001: package org.igfay.jfig;
002:
003: import org.apache.log4j.Logger;
004: import org.igfay.util.PropertyUtility;
005:
006: import java.util.ArrayList;
007: import java.util.HashMap;
008: import java.util.Iterator;
009: import java.util.List;
010: import java.util.Map;
011: import java.util.Properties;
012: import java.util.TreeMap;
013:
014: /**
015: * The JFig package provides very simple, flexible and powerful
016: * functionality for managing one or more configurations in a java environment.
017: *
018: * <P>It allows for a combination of a hierarchy of configuration files,
019: * substitution variables and property variables. Methods are provided to get
020: * values stored in a configuration dictionary with a variety of types (String,
021: * array, integer, float, boolean, etc) and default values.
022: *<P>
023: * Usage:
024: * <BR>To get an instance of the JFig singleton, use:
025: * JFig. getInstance();
026: *
027: * <P>There are a number of helper methods to retrieve configuration values. The
028: * most common is:
029: * <BR>String value = JFig. getInstance().getValue ("aSection","aKey","aDefaultValue");
030: *
031: * <P>See the javadocs for additional helper methods to retrieve values as
032: * different java types and with different exception handling.
033: *
034: *@author bconrad
035: *@created April 3, 2001
036: */
037: public class JFig implements JFigIF {
038: private static Logger log = Logger.getLogger(JFig.class);
039: private static JFigIF configSingleton;
040: private JFigDictionary configDictionary;
041: private Map allConfigFiles;
042: private JFigLocatorIF configLocator;
043: private JFigParser configParser;
044: private List configListeners;
045:
046: // for creating a "null" jfig object
047: private JFig() {
048: this .configDictionary = new JFigDictionary();
049: this .allConfigFiles = new HashMap();
050: }
051:
052: private JFig(JFigLocatorIF jfigLocator) throws JFigException {
053: if (jfigLocator == null) {
054: jfigLocator = new JFigLocator(null);
055: }
056: this .configLocator = jfigLocator;
057: this .configDictionary = new JFigDictionary();
058: this .allConfigFiles = new HashMap();
059: processConfig();
060: }
061:
062: public static void main(String[] args) {
063: JFig.getInstance().print();
064: PropertyUtility.listProperties();
065: }
066:
067: /**
068: * Return the config singleton
069: * @return
070: */
071: public synchronized static JFigIF getInstance() {
072: return getInstance(null);
073: }
074:
075: public static void setInstance(JFigIF jfig) {
076: configSingleton = jfig;
077: }
078:
079: /**
080: * Return the config singleton. If the configuration file is not found, throw an exception.
081: * @return
082: * @deprecated - Use initialize
083: */
084: public synchronized static JFigIF getInstance(int dummy)
085: throws JFigException {
086: return getConfigSingleton(null);
087: }
088:
089: /**
090: * Return the config singleton passing a JFigLocator. If the configuration file is not found, throw an exception.
091: * @return
092: * @deprecated - Use initialize
093: */
094: public synchronized static JFigIF getInstance(int dummy,
095: JFigLocatorIF locator) throws JFigException {
096: return getConfigSingleton(locator);
097: }
098:
099: /**
100: * Return the config singleton passing a JFigLocator
101: * @return
102: */
103: public synchronized static JFigIF getInstance(
104: JFigLocatorIF jfigLocator) {
105: // default to a "null" jfig if there are problems
106: JFigIF myConfigSingleton = new JFig();
107: try {
108: myConfigSingleton = getConfigSingleton(jfigLocator);
109: } catch (JFigException e) {
110: log.error("*** Unable to create configuration dictionary. "
111: + e.getMessage() + " ***");
112: } catch (NoClassDefFoundError e) {
113: log
114: .error("*** Unable to create configuration dictionary. NoClassDefFoundError "
115: + e.getMessage()
116: + "\nThis may be the result of incompatible XML jars. See JFIG documentation.");
117: } catch (Throwable e) {
118: log.error("*** Unhandled exception initializing JFig "
119: + e.getMessage(), e);
120: }
121: setInstance(myConfigSingleton);
122: return myConfigSingleton;
123: }
124:
125: private static JFigIF getConfigSingleton(JFigLocatorIF jfigLocator)
126: throws JFigException {
127: if (configSingleton == null) {
128: log.debug("Create singleton object.");
129: configSingleton = new JFig(jfigLocator);
130: log.debug("Created singleton object");
131: }
132: return configSingleton;
133: }
134:
135: /**
136: * Add JFig listeners to list so they can be notified when there
137: * is a significant change in the configuration.
138: *
139: *@param listener The feature to be added to the ConfigEventListener
140: * attribute
141: */
142: public void addConfigEventListener(JFigListener listener) {
143: log.debug("Add listener: " + listener);
144: getConfigListeners().add(listener);
145: log.debug("Number listeners: " + configListeners.size());
146: }
147:
148: /**
149: * Lazily initialize and return listeners
150: *
151: */
152: protected List getConfigListeners() {
153: if (configListeners == null) {
154: configListeners = new ArrayList();
155: }
156:
157: return configListeners;
158: }
159:
160: /**
161: * Notify registered listeners when configuration is updated.
162: */
163: protected void fireConfigUpdateEvent() {
164: log.debug("Number listeners: " + getConfigListeners().size());
165:
166: JFigEvent event = new JFigEvent("Configuration Updated");
167:
168: // loop through eventListener list and call configurationUpdate() method
169: for (int i = 0; i < getConfigListeners().size(); i++) {
170: log.debug("Notify listener");
171: ((JFigListener) getConfigListeners().get(i))
172: .configurationUpdate(event);
173: }
174: }
175:
176: /**
177: * Print the values in the JFig dictionary.
178: */
179: public void print() {
180: getConfigDictionary().print();
181: }
182:
183: /**
184: * Print the values in the JFig dictionary.
185: * @deprecated
186: */
187: public void printConfigurationDictionary() {
188: print();
189: }
190:
191: /**
192: * Call parser to process required config
193: */
194: protected void processConfig() throws JFigException {
195: log.debug("Processing file "
196: + getConfigLocator().getConfigFileName());
197: getParser().processConfig();
198:
199: getParser().resolveSymbolicValues();
200: getParser().addPropertyValues();
201: log.debug("Complete ");
202: log.debug("");
203: }
204:
205: /**
206: * Reprocess the configuration creating a new config dictionary
207: */
208: public void reprocessConfiguration() throws JFigException {
209: reprocessConfiguration(null);
210: }
211:
212: /**
213: * Reprocess the configuration with the specified JFigLocator, creating a new config dictionary
214: */
215: public void reprocessConfiguration(JFigLocator locator)
216: throws JFigException {
217: initialize(locator);
218: fireConfigUpdateEvent();
219: }
220:
221: /**
222: * Initialize configuration
223: */
224: public static JFigIF initialize() throws JFigException {
225: return initialize(null);
226: }
227:
228: /**
229: * Initialize configuration.
230: * It is recommended that JFig is explicitly initialized by this method.
231: * The alternative is to let getInstance() lazily initialize.
232: * The difference is that this will throw a JFigException if there is a problem
233: * in the initialization process while getInstance() will not.
234: */
235: public static JFigIF initialize(JFigLocator locator)
236: throws JFigException {
237: JFig newConfigSingleton = new JFig(locator);
238: configSingleton = newConfigSingleton;
239: return configSingleton;
240: }
241:
242: /**
243: * return the ConfigurationDictionary
244: * Made public so we can access this from a jsp and show the configuration
245: * via html.
246: */
247: public JFigDictionary getConfigDictionary() {
248: return configDictionary;
249: }
250:
251: /**
252: * Convenience method for getting values as array.
253: * The value is tokenized depending on the first token found in
254: * the following order: comma, semicolon, colon, space
255: *
256: */
257: public String[] getArrayValue(String section, String key)
258: throws JFigException {
259: String value = getValue(section, key);
260:
261: return JFigUtility.stringToArray(value);
262: }
263:
264: /**
265: * Convenience method for getting values as boolean
266: */
267: public boolean getBooleanValue(String section, String key,
268: String notFoundValue) {
269: String value = getValue(section, key, notFoundValue);
270:
271: return Boolean.valueOf(value).booleanValue();
272: }
273:
274: /**
275: * Convenience method for getting values as float
276: *
277: *@param section Description of Parameter
278: *@param key Description of Parameter
279: *@param notFoundValue Description of Parameter
280: *@return The FloatValue value
281: *@exception JFigException Description of Exception
282: */
283: public float getFloatValue(String section, String key,
284: String notFoundValue) throws JFigException {
285: String value = getValue(section, key, notFoundValue);
286:
287: try {
288: return Float.valueOf(value).floatValue();
289: } catch (ArithmeticException e) {
290: throw new JFigException(e.getMessage());
291: }
292: }
293:
294: /**
295: * Convenience method for getting values as int
296: */
297: public int getIntegerValue(String section, String key)
298: throws JFigException {
299: String value = getValue(section, key);
300:
301: try {
302: return Integer.parseInt(value);
303: } catch (ArithmeticException e) {
304: throw new JFigException(e.getMessage());
305: }
306: }
307:
308: /**
309: * Convenience method for getting values as int, with default value
310: */
311: public int getIntegerValue(String section, String key,
312: String notFoundValue) {
313: String value = getValue(section, key, notFoundValue);
314:
315: try {
316: return Integer.parseInt(value);
317: } catch (ArithmeticException e) {
318: log.info("Caught ArithmenticException for section "
319: + section + " key " + key + " defaultValue "
320: + notFoundValue + ". Returning 0");
321:
322: return 0;
323: } catch (NumberFormatException e) {
324: log.info("Caught NumberFormatException for section "
325: + section + " key " + key + " defaultValue "
326: + notFoundValue + ". Returning 0");
327:
328: return 0;
329: }
330: }
331:
332: /**
333: * Return the JFig parser
334: */
335: protected JFigParser getParser() {
336: if (configParser == null) {
337: if (isXML()) {
338: log.debug("Create XMLConfigParser");
339: configParser = new XMLJFigParser(this ,
340: getConfigLocator());
341: } else {
342: log.debug("create ConfigParser");
343: configParser = new IniJFigParser(this ,
344: getConfigLocator());
345: }
346: }
347:
348: return configParser;
349: }
350:
351: /**
352: * Is the configuration file in XML format or ini format.
353: * @return boolean
354: */
355: protected boolean isXML() {
356: return (getConfigFileName() != null)
357: && (getConfigFileName().indexOf("xml") > -1);
358: }
359:
360: /**
361: * Return the value for this section and key. If none found, return the
362: * default value.
363: *
364: *@param section Description of Parameter
365: *@param key Description of Parameter
366: *@param defaultValue Description of Parameter
367: *@return The Value value
368: */
369: public String getValue(String section, String key,
370: String defaultValue) {
371: String value = null;
372:
373: try {
374: value = getValue(section, key);
375: } catch (JFigException e) {
376: log.debug("Return default value " + defaultValue);
377:
378: return defaultValue;
379: }
380:
381: return value;
382: }
383:
384: /**
385: * Return a list of all values starting with "key" in the section.
386: * If section xxx contains x.1, x.2, and x.3,
387: * getValuesStartingWith("xxx", "x.") returns a list containing
388: * x.1, x.2, and x.3.
389: *
390: * @param section
391: * @param key
392: * @param defaultValue
393: * @return List
394: */
395: public List getValuesStartingWith(String section, String key) {
396: log.debug("section " + section + " key " + key);
397:
398: List list = new ArrayList();
399: TreeMap map = getConfigDictionary().getSectionNamed(section,
400: false);
401:
402: if (map != null) {
403: Iterator iterator = map.keySet().iterator();
404:
405: while (iterator.hasNext()) {
406: String compareKey = (String) iterator.next();
407: log.debug("compareKey " + compareKey);
408:
409: if (compareKey.startsWith(key)) {
410: list.add(map.get(compareKey));
411: }
412: }
413: }
414:
415: return list;
416: }
417:
418: /**
419: * Return a map of all values starting with "key" in the scetcion.
420: * If section xxx contains x.1=a, x.2=b, and x.3=c,
421: * getValuesStartingWith("xxx", "x.") returns a map containing
422: * x.1,a x.2,b and x.3,c.
423: *
424: * @param section
425: * @param key
426: * @param defaultValue
427: * @return List
428: */
429: public Map getEntriesStartingWith(String section, String key) {
430: log.debug("section " + section + " key " + key);
431:
432: List list = new ArrayList();
433: TreeMap map = getConfigDictionary().getSectionNamed(section,
434: false);
435: HashMap returnMap = new HashMap();
436: if (map != null) {
437: Iterator iterator = map.keySet().iterator();
438:
439: while (iterator.hasNext()) {
440: String compareKey = (String) iterator.next();
441: log.debug("compareKey " + compareKey);
442:
443: if (compareKey.startsWith(key)) {
444: returnMap.put(compareKey, map.get(compareKey));
445: }
446: }
447: }
448:
449: return returnMap;
450: }
451:
452: /**
453: * Return an entire section as a Map
454: */
455: public Map getSection(String section) {
456: log.debug("section " + section);
457: return getConfigDictionary().getSectionNamed(section, false);
458: }
459:
460: /**
461: * Return a section as a Properties object
462: */
463: public Properties getSectionAsProperties(String section) {
464: return getSectionAsProperties(section, new Properties());
465: }
466:
467: /**
468: * Return a section populated in a supplied Properties object.
469: */
470: public Properties getSectionAsProperties(String section,
471: Properties properties) {
472: log.debug("section " + section);
473: if (properties == null) {
474: return null;
475: }
476: // can't use putAll in case of null values
477: Map map = getSection(section);
478: Iterator iterator = map.keySet().iterator();
479: while (iterator.hasNext()) {
480: String key = (String) iterator.next();
481: String value = (String) map.get(key);
482: if (value != null) {
483: properties.put(key, value);
484: }
485:
486: }
487:
488: return properties;
489: }
490:
491: /**
492: * Call configParser to get the value for a key in a given section.
493: *
494: */
495: public String getValue(String section, String key)
496: throws JFigException {
497: String value = getConfigDictionary().getValue(section, key);
498: log.debug(value);
499:
500: return value;
501: }
502:
503: /**
504: * Set a configuration value.
505: * Most values are set during initial parsing so this is rarely used.
506: */
507: public void setConfigurationValue(String sectionName,
508: String keyString, String valueString) {
509: getConfigDictionary().setConfigurationValue(sectionName,
510: keyString, valueString);
511: }
512:
513: /**
514: * Convenience method for getting values as array with default value.
515: */
516: public String[] getArrayValue(String section, String key,
517: String notFoundValue) {
518: String value = getValue(section, key, notFoundValue);
519:
520: return JFigUtility.stringToArray(value);
521: }
522:
523: /**
524: * Sets the configDictionary.
525: * @param configDictionary
526: */
527: protected void setConfigDictionary(JFigDictionary configDictionary) {
528: this .configDictionary = configDictionary;
529: }
530:
531: /**
532: * Returns the list of all config files that have been processed.
533: * Used to prevent processing the same file multiple times
534: * esp in case of circular includes.
535: * @return List
536: */
537: protected Map getAllConfigFiles() {
538: return allConfigFiles;
539: }
540:
541: protected void setAllConfigFiles(HashMap map) {
542: allConfigFiles = map;
543: }
544:
545: /**
546: * @return
547: */
548: protected JFigLocatorIF getConfigLocator() {
549: return configLocator;
550: }
551:
552: protected String getConfigFileName() {
553: return getConfigLocator().getConfigFileName();
554: }
555: }
|