001: package net.myvietnam.mvncore.configuration;
002:
003: /* ====================================================================
004: * The Apache Software License, Version 1.1
005: *
006: * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
007: * reserved.
008: *
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowledgement:
023: * "This product includes software developed by the
024: * Apache Software Foundation (http://www.apache.org/)."
025: * Alternately, this acknowledgement may appear in the software itself,
026: * if and wherever such third-party acknowledgements normally appear.
027: *
028: * 4. The names "The Jakarta Project", "Commons", and "Apache Software
029: * Foundation" must not be used to endorse or promote products derived
030: * from this software without prior written permission. For written
031: * permission, please contact apache@apache.org.
032: *
033: * 5. Products derived from this software may not be called "Apache"
034: * nor may "Apache" appear in their names without prior written
035: * permission of the Apache Software Foundation.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
041: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
042: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
043: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
044: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
045: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
046: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
047: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
048: * SUCH DAMAGE.
049: * ====================================================================
050: *
051: * This software consists of voluntary contributions made by many
052: * individuals on behalf of the Apache Software Foundation. For more
053: * information on the Apache Software Foundation, please see
054: * <http://www.apache.org/>.
055: */
056:
057: import java.util.ArrayList;
058: import java.util.Iterator;
059: import java.util.LinkedList;
060: import java.util.List;
061: import java.util.ListIterator;
062: import java.util.NoSuchElementException;
063: import java.util.Properties;
064: import java.util.Vector;
065:
066: /**
067: * This Configuration class allows you to add multiple different types of Configuration
068: * to this CompositeConfiguration. If you add Configuration1, and then Configuration2,
069: * any properties shared will mean that Configuration1 will be returned.
070: * You can add multiple different types or the same type of properties file.
071: * If Configuration1 doesn't have the property, then Configuration2 will be checked.
072: *
073: * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
074: * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
075: * @version $Id: CompositeConfiguration.java,v 1.2 2004/06/27 01:20:38 skoehler Exp $
076: */
077: public class CompositeConfiguration implements Configuration {
078: /** Array holding all the configuration */
079: private LinkedList configList = new LinkedList();
080:
081: /**
082: * Configuration that holds in memory stuff. Inserted as first so any
083: * setProperty() override anything else added.
084: */
085: private BaseConfiguration inMemoryConfiguration;
086:
087: /**
088: * Creates an empty CompositeConfiguration object which can then
089: * be added some other Configuration files
090: */
091: public CompositeConfiguration() {
092: clear();
093: }
094:
095: public void addConfiguration(Configuration config) {
096: if (!configList.contains(config)) {
097: // As the inMemoryConfiguration contains all manually added keys,
098: // we must make sure that it is always last. "Normal", non composed
099: // configuration add their keys at the end of the configuration and
100: // we want to mimic this behaviour.
101: configList.add(configList.indexOf(inMemoryConfiguration),
102: config);
103: }
104: }
105:
106: public void removeConfiguration(Configuration config) {
107: // Make sure that you can't remove the inMemoryConfiguration from
108: // the CompositeConfiguration object
109: if (!config.equals(inMemoryConfiguration)) {
110: configList.remove(config);
111: }
112: }
113:
114: public int getNumberOfConfigurations() {
115: return configList.size();
116: }
117:
118: public void clear() {
119: configList.clear();
120: // recreate the in memory configuration
121: inMemoryConfiguration = new BaseConfiguration();
122: configList.addLast(inMemoryConfiguration);
123: }
124:
125: /**
126: * CompositeConfigurations can not be added to
127: *
128: * @param key The Key to add the property to.
129: * @param token The Value to add.
130: */
131: public void addProperty(String key, Object token) {
132: inMemoryConfiguration.addProperty(key, token);
133: }
134:
135: /**
136: * Get the list of the keys contained in the configuration
137: * repository.
138: *
139: * @return An Iterator.
140: */
141: public Iterator getKeys() {
142: List keys = new ArrayList();
143: for (ListIterator i = configList.listIterator(); i.hasNext();) {
144: Configuration config = (Configuration) i.next();
145: for (Iterator j = config.getKeys(); j.hasNext();) {
146: String key = (String) j.next();
147: if (!keys.contains(key)) {
148: keys.add(key);
149: }
150: }
151: }
152: return keys.iterator();
153: }
154:
155: /**
156: * Get the list of the keys contained in the configuration
157: * repository.
158: *
159: * @return An Iterator.
160: */
161: public Iterator getKeys(String key) {
162: List keys = new ArrayList();
163: for (ListIterator i = configList.listIterator(); i.hasNext();) {
164: Configuration config = (Configuration) i.next();
165: for (Iterator j = config.getKeys(key); j.hasNext();) {
166: String newKey = (String) j.next();
167: if (!keys.contains(newKey)) {
168: keys.add(newKey);
169: }
170: }
171: }
172: return keys.iterator();
173: }
174:
175: /**
176: * Get a list of properties associated with the given
177: * configuration key.
178: *
179: * @param key The configuration key.
180: * @return The associated properties if key is found.
181: * @exception ClassCastException is thrown if the key maps to an
182: * object that is not a String/Vector.
183: * @exception IllegalArgumentException if one of the tokens is
184: * malformed (does not contain an equals sign).
185: */
186: public Properties getProperties(String key) {
187: return getFirstMatchingConfig(key).getProperties(key);
188: }
189:
190: public boolean isEmpty() {
191: boolean isEmpty = true;
192: for (ListIterator i = configList.listIterator(); i.hasNext();) {
193: Configuration config = (Configuration) i.next();
194: if (!config.isEmpty()) {
195: return false;
196: }
197: }
198: return isEmpty;
199: }
200:
201: /**
202: * Gets a property from the configuration.
203: *
204: * @param key property to retrieve
205: * @return value as object. Will return user value if exists,
206: * if not then default value if exists, otherwise null
207: */
208: public Object getProperty(String key) {
209: return getFirstMatchingConfig(key).getProperty(key);
210: }
211:
212: /**
213: * Set a property, this will replace any previously
214: * set values. Set values is implicitly a call
215: * to clearProperty(key), addProperty(key,value).
216: *
217: * @param key
218: * @param value
219: */
220: public void setProperty(String key, Object value) {
221: clearProperty(key);
222: addProperty(key, value);
223: }
224:
225: /**
226: * Clear a property in the configuration.
227: *
228: * @param key the key to remove along with corresponding value.
229: */
230: public void clearProperty(String key) {
231: for (ListIterator i = configList.listIterator(); i.hasNext();) {
232: Configuration config = (Configuration) i.next();
233: config.clearProperty(key);
234: }
235: }
236:
237: /**
238: * check if the configuration contains the key
239: */
240: public boolean containsKey(String key) {
241: for (ListIterator i = configList.listIterator(); i.hasNext();) {
242: Configuration config = (Configuration) i.next();
243: if (config.containsKey(key)) {
244: return true;
245: }
246: }
247: return false;
248: }
249:
250: /**
251: * Create a CompositeConfiguration object that is a subset
252: * of this one. Cycles over all the config objects, and calls
253: * their subset method and then just adds that.
254: *
255: * @param prefix
256: */
257: public Configuration subset(String prefix) {
258: CompositeConfiguration subsetCompositeConfiguration = new CompositeConfiguration();
259: Configuration subConf = null;
260: int count = 0;
261: for (ListIterator i = configList.listIterator(); i.hasNext();) {
262: Configuration config = (Configuration) i.next();
263: Configuration subset = config.subset(prefix);
264: if (subset != null) {
265: subsetCompositeConfiguration.addConfiguration(subset);
266: subConf = subset;
267: count++;
268: }
269: }
270: return (count == 1) ? subConf : subsetCompositeConfiguration;
271: }
272:
273: /**
274: * Get a float associated with the given configuration key.
275: *
276: * @ param key The configuration key.
277: * @ return The associated float.
278: * @ exception NoSuchElementException is thrown if the key doesn 't
279: * map to an existing object.
280: * @ exception ClassCastException is thrown if the key maps to an
281: * object that is not a Float.
282: * @ exception NumberFormatException is thrown if the value mapped
283: * by the key has not a valid number format.
284: */
285: public float getFloat(String key) {
286: return getFirstMatchingConfig(key).getFloat(key);
287: }
288:
289: /**
290: * Get a boolean associated with the given configuration key.
291: *
292: * @param key The configuration key.
293: * @return The associated boolean.
294: * @exception NoSuchElementException is thrown if the key doesn't
295: * map to an existing object.
296: * @exception ClassCastException is thrown if the key maps to an
297: * object that is not a Boolean.
298: */
299: public boolean getBoolean(String key) {
300: return getFirstMatchingConfig(key).getBoolean(key);
301: }
302:
303: /**
304: * Get a boolean associated with the given configuration key.
305: *
306: * @param key The configuration key.
307: * @param defaultValue The default value.
308: * @return The associated boolean.
309: * @exception ClassCastException is thrown if the key maps to an
310: * object that is not a Boolean.
311: */
312: public boolean getBoolean(String key, boolean defaultValue) {
313: return getBoolean(key, new Boolean(defaultValue))
314: .booleanValue();
315: }
316:
317: /**
318: * Get a boolean associated with the given configuration key.
319: *
320: * @param key The configuration key.
321: * @param defaultValue The default value.
322: * @return The associated boolean if key is found and has valid
323: * format, default value otherwise.
324: * @exception ClassCastException is thrown if the key maps to an
325: * object that is not a Boolean.
326: */
327: public Boolean getBoolean(String key, Boolean defaultValue) {
328: try {
329: return getFirstMatchingConfig(key).getBoolean(key,
330: defaultValue);
331: } catch (NoSuchElementException nsee) {
332: return defaultValue;
333: }
334: }
335:
336: /**
337: * Get a byte associated with the given configuration key.
338: *
339: * @param key The configuration key.
340: * @return The associated byte.
341: * @exception NoSuchElementException is thrown if the key doesn't
342: * map to an existing object.
343: * @exception ClassCastException is thrown if the key maps to an
344: * object that is not a Byte.
345: * @exception NumberFormatException is thrown if the value mapped
346: * by the key has not a valid number format.
347: */
348: public byte getByte(String key) {
349: return getFirstMatchingConfig(key).getByte(key);
350: }
351:
352: /**
353: * Get a byte associated with the given configuration key.
354: *
355: * @param key The configuration key.
356: * @param defaultValue The default value.
357: * @return The associated byte.
358: * @exception ClassCastException is thrown if the key maps to an
359: * object that is not a Byte.
360: * @exception NumberFormatException is thrown if the value mapped
361: * by the key has not a valid number format.
362: */
363: public byte getByte(String key, byte defaultValue) {
364: return getByte(key, new Byte(defaultValue).byteValue());
365: }
366:
367: /**
368: * Get a byte associated with the given configuration key.
369: *
370: * @param key The configuration key.
371: * @param defaultValue The default value.
372: * @return The associated byte if key is found and has valid format, default
373: * value otherwise.
374: * @exception ClassCastException is thrown if the key maps to an object that
375: * is not a Byte.
376: * @exception NumberFormatException is thrown if the value mapped by the key
377: * has not a valid number format.
378: */
379: public Byte getByte(String key, Byte defaultValue) {
380: try {
381: return getFirstMatchingConfig(key).getByte(key,
382: defaultValue);
383: } catch (NoSuchElementException nsee) {
384: return defaultValue;
385: }
386: }
387:
388: /**
389: * Get a double associated with the given configuration key.
390: *
391: * @param key The configuration key.
392: * @return The associated double.
393: * @exception NoSuchElementException is thrown if the key doesn't
394: * map to an existing object.
395: * @exception ClassCastException is thrown if the key maps to an
396: * object that is not a Double.
397: * @exception NumberFormatException is thrown if the value mapped
398: * by the key has not a valid number format.
399: */
400: public double getDouble(String key) {
401: return getFirstMatchingConfig(key).getDouble(key);
402: }
403:
404: /**
405: * Get a double associated with the given configuration key.
406: *
407: * @param key The configuration key.
408: * @param defaultValue The default value.
409: * @return The associated double.
410: * @exception ClassCastException is thrown if the key maps to an
411: * object that is not a Double.
412: * @exception NumberFormatException is thrown if the value mapped
413: * by the key has not a valid number format.
414: */
415: public double getDouble(String key, double defaultValue) {
416: return getDouble(key, new Double(defaultValue)).doubleValue();
417: }
418:
419: /**
420: * Get a double associated with the given configuration key.
421: *
422: * @param key The configuration key.
423: * @param defaultValue The default value.
424: * @return The associated double if key is found and has valid
425: * format, default value otherwise.
426: * @exception ClassCastException is thrown if the key maps to an
427: * object that is not a Double.
428: * @exception NumberFormatException is thrown if the value mapped
429: * by the key has not a valid number format.
430: */
431: public Double getDouble(String key, Double defaultValue) {
432: try {
433: return getFirstMatchingConfig(key).getDouble(key,
434: defaultValue);
435: } catch (NoSuchElementException nsee) {
436: return defaultValue;
437: }
438: }
439:
440: /**
441: * Get a float associated with the given configuration key.
442: *
443: * @param key The configuration key.
444: * @param defaultValue The default value.
445: * @return The associated float.
446: * @exception ClassCastException is thrown if the key maps to an
447: * object that is not a Float.
448: * @exception NumberFormatException is thrown if the value mapped
449: * by the key has not a valid number format.
450: */
451: public float getFloat(String key, float defaultValue) {
452: return getFloat(key, new Float(defaultValue)).floatValue();
453: }
454:
455: /**
456: * Get a float associated with the given configuration key.
457: *
458: * @param key The configuration key.
459: * @param defaultValue The default value.
460: * @return The associated float if key is found and has valid
461: * format, default value otherwise.
462: * @exception ClassCastException is thrown if the key maps to an
463: * object that is not a Float.
464: * @exception NumberFormatException is thrown if the value mapped
465: * by the key has not a valid number format.
466: */
467: public Float getFloat(String key, Float defaultValue) {
468: try {
469: return getFirstMatchingConfig(key).getFloat(key,
470: defaultValue);
471: } catch (NoSuchElementException nsee) {
472: return defaultValue;
473: }
474: }
475:
476: /**
477: * Get a int associated with the given configuration key.
478: *
479: * @param key The configuration key.
480: * @return The associated int.
481: * @exception NoSuchElementException is thrown if the key doesn't
482: * map to an existing object.
483: * @exception ClassCastException is thrown if the key maps to an
484: * object that is not a Integer.
485: * @exception NumberFormatException is thrown if the value mapped
486: * by the key has not a valid number format.
487: */
488: public int getInt(String key) {
489: return getFirstMatchingConfig(key).getInt(key);
490: }
491:
492: /**
493: * Get a int associated with the given configuration key.
494: *
495: * @param key The configuration key.
496: * @param defaultValue The default value.
497: * @return The associated int.
498: * @exception ClassCastException is thrown if the key maps to an
499: * object that is not a Integer.
500: * @exception NumberFormatException is thrown if the value mapped
501: * by the key has not a valid number format.
502: */
503: public int getInt(String key, int defaultValue) {
504: return getInteger(key, new Integer(defaultValue)).intValue();
505: }
506:
507: /**
508: * Get a int associated with the given configuration key.
509: *
510: * @param key The configuration key.
511: * @param defaultValue The default value.
512: * @return The associated int if key is found and has valid format, default
513: * value otherwise.
514: * @exception ClassCastException is thrown if the key maps to an object that
515: * is not a Integer.
516: * @exception NumberFormatException is thrown if the value mapped by the key
517: * has not a valid number format.
518: */
519: public Integer getInteger(String key, Integer defaultValue) {
520: try {
521: return getFirstMatchingConfig(key).getInteger(key,
522: defaultValue);
523: } catch (NoSuchElementException nsee) {
524: return defaultValue;
525: }
526: }
527:
528: /**
529: * Get a long associated with the given configuration key.
530: *
531: * @param key The configuration key.
532: * @return The associated long.
533: * @exception NoSuchElementException is thrown if the key doesn't
534: * map to an existing object.
535: * @exception ClassCastException is thrown if the key maps to an
536: * object that is not a Long.
537: * @exception NumberFormatException is thrown if the value mapped
538: * by the key has not a valid number format.
539: */
540: public long getLong(String key) {
541: return getFirstMatchingConfig(key).getLong(key);
542: }
543:
544: /**
545: * Get a long associated with the given configuration key.
546: *
547: * @param key The configuration key.
548: * @param defaultValue The default value.
549: * @return The associated long.
550: * @exception ClassCastException is thrown if the key maps to an
551: * object that is not a Long.
552: * @exception NumberFormatException is thrown if the value mapped
553: * by the key has not a valid number format.
554: */
555: public long getLong(String key, long defaultValue) {
556: return getLong(key, new Long(defaultValue)).longValue();
557: }
558:
559: /**
560: * Get a long associated with the given configuration key.
561: *
562: * @param key The configuration key.
563: * @param defaultValue The default value.
564: * @return The associated long if key is found and has valid
565: * format, default value otherwise.
566: * @exception ClassCastException is thrown if the key maps to an
567: * object that is not a Long.
568: * @exception NumberFormatException is thrown if the value mapped
569: * by the key has not a valid number format.
570: */
571: public Long getLong(String key, Long defaultValue) {
572: try {
573: return getFirstMatchingConfig(key).getLong(key,
574: defaultValue);
575: } catch (NoSuchElementException nsee) {
576: return defaultValue;
577: }
578: }
579:
580: /**
581: * Get a short associated with the given configuration key.
582: *
583: * @param key The configuration key.
584: * @return The associated short.
585: * @exception NoSuchElementException is thrown if the key doesn't
586: * map to an existing object.
587: * @exception ClassCastException is thrown if the key maps to an
588: * object that is not a Short.
589: * @exception NumberFormatException is thrown if the value mapped
590: * by the key has not a valid number format.
591: */
592: public short getShort(String key) {
593: return getFirstMatchingConfig(key).getShort(key);
594: }
595:
596: /**
597: * Get a short associated with the given configuration key.
598: *
599: * @param key The configuration key.
600: * @param defaultValue The default value.
601: * @return The associated short.
602: * @exception ClassCastException is thrown if the key maps to an
603: * object that is not a Short.
604: * @exception NumberFormatException is thrown if the value mapped
605: * by the key has not a valid number format.
606: */
607: public short getShort(String key, short defaultValue) {
608: return getShort(key, new Short(defaultValue)).shortValue();
609: }
610:
611: /**
612: * Get a short associated with the given configuration key.
613: *
614: * @param key The configuration key.
615: * @param defaultValue The default value.
616: * @return The associated short if key is found and has valid
617: * format, default value otherwise.
618: * @exception ClassCastException is thrown if the key maps to an
619: * object that is not a Short.
620: * @exception NumberFormatException is thrown if the value mapped
621: * by the key has not a valid number format.
622: */
623: public Short getShort(String key, Short defaultValue) {
624: try {
625: return getFirstMatchingConfig(key).getShort(key,
626: defaultValue);
627: } catch (NoSuchElementException nsee) {
628: return defaultValue;
629: }
630: }
631:
632: /**
633: * Get a string associated with the given configuration key.
634: *
635: * @param key The configuration key.
636: * @return The associated string.
637: * @exception ClassCastException is thrown if the key maps to an object that
638: * is not a String.
639: */
640: public String getString(String key) {
641: return getString(key, null);
642: }
643:
644: /**
645: * Get a string associated with the given configuration key.
646: *
647: * @param key The configuration key.
648: * @param defaultValue The default value.
649: * @return The associated string if key is found, default value otherwise.
650: * @exception ClassCastException is thrown if the key maps to an object that
651: * is not a String.
652: */
653: public String getString(String key, String defaultValue) {
654: try {
655: return getFirstMatchingConfig(key).getString(key,
656: defaultValue);
657: } catch (NoSuchElementException nsee) {
658: return defaultValue;
659: }
660: }
661:
662: /**
663: * Get an array of strings associated with the given configuration
664: * key.
665: *
666: * @param key The configuration key.
667: * @return The associated string array if key is found.
668: * @exception ClassCastException is thrown if the key maps to an
669: * object that is not a String/Vector of Strings.
670: */
671: public String[] getStringArray(String key) {
672: Vector v = getVector(key);
673: return (String[]) v.toArray(new String[0]);
674: }
675:
676: /**
677: * Get a Vector of strings associated with the given configuration key.
678: *
679: * @param key The configuration key.
680: * @return The associated Vector.
681: * @exception ClassCastException is thrown if the key maps to an
682: * object that is not a Vector.
683: */
684: public Vector getVector(String key) {
685: Vector v = new Vector();
686:
687: for (ListIterator li = configList.listIterator(); li.hasNext();) {
688: Configuration config = (Configuration) li.next();
689: if (config.containsKey(key)) {
690: v.addAll(config.getVector(key));
691: }
692: }
693:
694: return v;
695: }
696:
697: /**
698: * Get a Vector of strings associated with the given configuration key.
699: *
700: * @param key The configuration key.
701: * @param defaultValue The default value.
702: * @return The associated Vector.
703: * @exception ClassCastException is thrown if the key maps to an
704: * object that is not a Vector.
705: */
706: public Vector getVector(String key, Vector defaultValue) {
707: Vector v = getVector(key);
708:
709: return (v.size() == 0) ? defaultValue : v;
710: }
711:
712: private Configuration getFirstMatchingConfig(String key) {
713: for (ListIterator i = configList.listIterator(); i.hasNext();) {
714: Configuration config = (Configuration) i.next();
715: if (config.containsKey(key)) {
716: return config;
717: }
718: }
719: throw new NoSuchElementException('\'' + key
720: + "' doesn't map to an existing object");
721: }
722:
723: public Configuration getConfiguration(int index) {
724: return (Configuration) configList.get(index);
725: }
726: }
|