KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > myvietnam > mvncore > configuration > AbstractConfiguration


1 package net.myvietnam.mvncore.configuration;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowledgement:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgement may appear in the software itself,
26  * if and wherever such third-party acknowledgements normally appear.
27  *
28  * 4. The names "The Jakarta Project", "Commons", and "Apache Software
29  * Foundation" must not be used to endorse or promote products derived
30  * from this software without prior written permission. For written
31  * permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache"
34  * nor may "Apache" appear in their names without prior written
35  * permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  */

56
57 import java.util.ArrayList JavaDoc;
58 import java.util.Collection JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.List JavaDoc;
61 import java.util.NoSuchElementException JavaDoc;
62 import java.util.Properties JavaDoc;
63 import java.util.StringTokenizer JavaDoc;
64 import java.util.Vector JavaDoc;
65 import org.apache.commons.logging.Log;
66 import org.apache.commons.logging.LogFactory;
67
68 /**
69  * Abstract configuration class. Provide basic functionality but does not
70  * store any data. If you want to write your own Configuration class
71  * then you should implement only abstract methods from this class.
72  *
73  * @author <a HREF="mailto:ksh@scand.com">Konstantin Shaposhnikov</a>
74  * @author <a HREF="mailto:oliver.heger@t-online.de">Oliver Heger</a>
75  * @version $Id: AbstractConfiguration.java,v 1.4 2004/06/01 13:25:39 skoehler Exp $
76  */

77 public abstract class AbstractConfiguration implements Configuration
78 {
79     /** how big the initial arraylist for splitting up name value pairs */
80     private static final int INITIAL_LIST_SIZE = 2;
81
82     private static Log log = LogFactory.getLog(AbstractConfiguration.class);
83     /**
84      * stores the configuration key-value pairs
85      */

86     protected Configuration defaults = null;
87
88     /** start token */
89     protected static final String JavaDoc START_TOKEN = "${";
90     /** end token */
91     protected static final String JavaDoc END_TOKEN = "}";
92
93     /**
94      * Empty constructor.
95      */

96     public AbstractConfiguration()
97     {
98     }
99
100     /**
101      * Creates an empty AbstractConfiguration object with
102      * a Super-Object which is queries for every key.
103      *
104      * @param defaults Configuration defaults to use if key not in file
105      */

106     public AbstractConfiguration(Configuration defaults)
107     {
108         this();
109         this.defaults = defaults;
110     }
111
112     /**
113      * Add a property to the configuration. If it already exists then the value
114      * stated here will be added to the configuration entry. For example, if
115      *
116      * resource.loader = file
117      *
118      * is already present in the configuration and you
119      *
120      * addProperty("resource.loader", "classpath")
121      *
122      * Then you will end up with a Vector like the following:
123      *
124      * ["file", "classpath"]
125      *
126      * @param key The Key to add the property to.
127      * @param token The Value to add.
128      */

129     public void addProperty(String JavaDoc key, Object JavaDoc token)
130     {
131         if (token instanceof String JavaDoc)
132         {
133             for(Iterator JavaDoc it = processString((String JavaDoc) token).iterator();
134             it.hasNext();)
135             {
136                 addPropertyDirect(key, it.next());
137             }
138         }
139         else if (token instanceof Collection JavaDoc)
140         {
141             for (Iterator JavaDoc it = ((Collection JavaDoc) token).iterator(); it.hasNext();)
142             {
143                 addProperty(key, it.next());
144             }
145         }
146         else
147         {
148             addPropertyDirect(key, token);
149         }
150     }
151
152     /**
153      * Read property. Should return <code>null</code> if the key doesn't
154      * map to an existing object.
155      *
156      * @param key key to use for mapping
157      *
158      * @return object associated with the given configuration key.
159      */

160     protected abstract Object JavaDoc getPropertyDirect(String JavaDoc key);
161
162     /**
163      * Adds a key/value pair to the Configuration. Override this method to
164      * provide write acces to underlying Configuration store.
165      *
166      * @param key key to use for mapping
167      * @param obj object to store
168      */

169     protected abstract void addPropertyDirect(String JavaDoc key, Object JavaDoc obj);
170
171     /**
172      * interpolate key names to handle ${key} stuff
173      *
174      * @param base string to interpolate
175      *
176      * @return returns the key name with the ${key} substituted
177      */

178     protected String JavaDoc interpolate(String JavaDoc base)
179     {
180         return (interpolateHelper(base, null));
181     }
182
183     /**
184      * Recursive handler for multple levels of interpolation.
185      *
186      * When called the first time, priorVariables should be null.
187      *
188      * @param base string with the ${key} variables
189      * @param priorVariables serves two purposes: to allow checking for
190      * loops, and creating a meaningful exception message should a loop
191      * occur. It's 0'th element will be set to the value of base from
192      * the first call. All subsequent interpolated variables are added
193      * afterward.
194      *
195      * @return the string with the interpolation taken care of
196      */

197     protected String JavaDoc interpolateHelper(String JavaDoc base, List JavaDoc priorVariables)
198     {
199         if (base == null)
200         {
201             return null;
202         }
203
204         // on the first call initialize priorVariables
205
// and add base as the first element
206
if (priorVariables == null)
207         {
208             priorVariables = new ArrayList JavaDoc();
209             priorVariables.add(base);
210         }
211
212         int begin = -1;
213         int end = -1;
214         int prec = 0 - END_TOKEN.length();
215         String JavaDoc variable = null;
216         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
217
218         // FIXME: we should probably allow the escaping of the start token
219
while (((begin = base.indexOf(START_TOKEN, prec + END_TOKEN.length()))
220             > -1)
221             && ((end = base.indexOf(END_TOKEN, begin)) > -1))
222         {
223             result.append(base.substring(prec + END_TOKEN.length(), begin));
224             variable = base.substring(begin + START_TOKEN.length(), end);
225
226             // if we've got a loop, create a useful exception message and throw
227
if (priorVariables.contains(variable))
228             {
229                 String JavaDoc initialBase = priorVariables.remove(0).toString();
230                 priorVariables.add(variable);
231                 StringBuffer JavaDoc priorVariableSb = new StringBuffer JavaDoc();
232
233                 // create a nice trace of interpolated variables like so:
234
// var1->var2->var3
235
for (Iterator JavaDoc it = priorVariables.iterator(); it.hasNext();)
236                 {
237                     priorVariableSb.append(it.next());
238                     if (it.hasNext())
239                     {
240                         priorVariableSb.append("->");
241                     }
242                 }
243
244                 throw new IllegalStateException JavaDoc(
245                     "infinite loop in property interpolation of "
246                         + initialBase
247                         + ": "
248                         + priorVariableSb.toString());
249             }
250             // otherwise, add this variable to the interpolation list.
251
else
252             {
253                 priorVariables.add(variable);
254             }
255
256             //QUESTION: getProperty or getPropertyDirect
257
Object JavaDoc value = getProperty(variable);
258             if (value != null)
259             {
260                 result.append(interpolateHelper(value.toString(),
261                     priorVariables));
262
263                 // pop the interpolated variable off the stack
264
// this maintains priorVariables correctness for
265
// properties with multiple interpolations, e.g.
266
// prop.name=${some.other.prop1}/blahblah/${some.other.prop2}
267
priorVariables.remove(priorVariables.size() - 1);
268             }
269             else if (defaults != null && defaults.getString(variable,
270                 null) != null)
271             {
272                 result.append(defaults.getString(variable));
273             }
274             else
275             {
276                 //variable not defined - so put it back in the value
277
result.append(START_TOKEN).append(variable).append(END_TOKEN);
278             }
279             prec = end;
280         }
281         result.append(base.substring(prec + END_TOKEN.length(), base.length()));
282
283         return result.toString();
284     }
285
286     /**
287      * Returns a Vector of Strings built from the supplied
288      * String. Splits up CSV lists. If no commas are in the
289      * String, simply returns a Vector with the String as its
290      * first element
291      *
292      * @param token The String to tokenize
293      *
294      * @return A List of Strings
295      */

296     protected List JavaDoc processString(String JavaDoc token)
297     {
298         List JavaDoc retList = new ArrayList JavaDoc(INITIAL_LIST_SIZE);
299
300         if (token.indexOf(PropertiesTokenizer.DELIMITER) > 0)
301         {
302             PropertiesTokenizer tokenizer =
303                 new PropertiesTokenizer(token);
304
305             while (tokenizer.hasMoreTokens())
306             {
307                 String JavaDoc value = tokenizer.nextToken();
308                 retList.add(value);
309             }
310         }
311         else
312         {
313             retList.add(token);
314         }
315
316         //
317
// We keep the sequence of the keys here and
318
// we also keep it in the Container. So the
319
// Keys are added to the store in the sequence that
320
// is given in the properties
321
return retList;
322     }
323
324
325     /**
326      * Test whether the string represent by value maps to a boolean
327      * value or not. We will allow <code>true</code>, <code>on</code>,
328      * and <code>yes</code> for a <code>true</code> boolean value, and
329      * <code>false</code>, <code>off</code>, and <code>no</code> for
330      * <code>false</code> boolean values. Case of value to test for
331      * boolean status is ignored.
332      *
333      * @param value The value to test for boolean state.
334      * @return <code>true</code> or <code>false</code> if the supplied
335      * text maps to a boolean value, or <code>null</code> otherwise.
336      */

337     protected final Boolean JavaDoc testBoolean(String JavaDoc value)
338     {
339         String JavaDoc s = value.toLowerCase();
340
341         if (s.equals("true") || s.equals("on") || s.equals("yes"))
342         {
343             return Boolean.TRUE;
344         }
345         else if (s.equals("false") || s.equals("off") || s.equals("no"))
346         {
347             return Boolean.FALSE;
348         }
349         else
350         {
351             return null;
352         }
353     }
354
355     /**
356      * Create an BaseConfiguration object that is a subset
357      * of this one.
358      *
359      * @param prefix prefix string for keys
360      *
361      * @return subset of configuration if there is keys, that match
362      * given prefix, or <code>null</code> if there is no such keys.
363      */

364     public Configuration subset(String JavaDoc prefix)
365     {
366         BaseConfiguration c = new BaseConfiguration();
367         Iterator JavaDoc keys = this.getKeys();
368         boolean validSubset = false;
369
370         while (keys.hasNext())
371         {
372             Object JavaDoc key = keys.next();
373
374             if (key instanceof String JavaDoc && ((String JavaDoc) key).startsWith(prefix))
375             {
376                 if (!validSubset)
377                 {
378                     validSubset = true;
379                 }
380
381                 String JavaDoc newKey = null;
382
383                 /*
384                  * Check to make sure that c.subset(prefix) doesn't blow up when
385                  * there is only a single property with the key prefix. This is
386                  * not a useful subset but it is a valid subset.
387                  */

388                 if (((String JavaDoc) key).length() == prefix.length())
389                 {
390                     newKey = prefix;
391                 }
392                 else
393                 {
394                     newKey = ((String JavaDoc) key).substring(prefix.length() + 1);
395                 }
396
397                 /*
398                  * use addPropertyDirect() - this will plug the data as is into
399                  * the Map, but will also do the right thing re key accounting
400                  *
401                  * QUESTION: getProperty or getPropertyDirect
402                  */

403                 Object JavaDoc value = getProperty((String JavaDoc) key);
404                 if (value instanceof String JavaDoc)
405                 {
406                     c.addPropertyDirect(newKey, interpolate((String JavaDoc) value));
407                 }
408                 else
409                 {
410                     c.addProperty(newKey, value);
411                 }
412             }
413         }
414
415         if (validSubset)
416         {
417             return c;
418         }
419         else
420         {
421             return null;
422         }
423     }
424
425     /**
426      * Check if the configuration is empty
427      *
428      * @return <code>true</code> if Configuration is empty,
429      * <code>false</code> otherwise.
430      */

431     public abstract boolean isEmpty();
432
433     /**
434      * check if the configuration contains the key
435      *
436      * @param key the configuration key
437      *
438      * @return <code>true</code> if Configuration contain given key,
439      * <code>false</code> otherwise.
440      */

441     public abstract boolean containsKey(String JavaDoc key);
442
443     /**
444      * Set a property, this will replace any previously
445      * set values. Set values is implicitly a call
446      * to clearProperty(key), addProperty(key,value).
447      *
448      * @param key the configuration key
449      * @param value the property value
450      */

451     public void setProperty(String JavaDoc key, Object JavaDoc value)
452     {
453         clearProperty(key);
454         addProperty(key, value); // QUESTION: or addPropertyDirect?
455
}
456
457     /**
458      * Clear a property in the configuration.
459      *
460      * @param key the key to remove along with corresponding value.
461      */

462     public abstract void clearProperty(String JavaDoc key);
463
464     /**
465      * Get the list of the keys contained in the configuration
466      * repository.
467      *
468      * @return An Iterator.
469      */

470     public abstract Iterator JavaDoc getKeys();
471
472     /**
473      * Get the list of the keys contained in the configuration
474      * repository that match the specified prefix.
475      *
476      * @param prefix The prefix to test against.
477      *
478      * @return An Iterator of keys that match the prefix.
479      */

480     public Iterator JavaDoc getKeys(String JavaDoc prefix)
481     {
482         Iterator JavaDoc keys = getKeys();
483         ArrayList JavaDoc matchingKeys = new ArrayList JavaDoc();
484
485         while (keys.hasNext())
486         {
487             Object JavaDoc key = keys.next();
488
489             if (key instanceof String JavaDoc && ((String JavaDoc) key).startsWith(prefix))
490             {
491                 matchingKeys.add(key);
492             }
493         }
494         return matchingKeys.iterator();
495     }
496
497     /**
498      * Get a list of properties associated with the given
499      * configuration key.
500      *
501      * @param key The configuration key.
502      *
503      * @return The associated properties if key is found.
504      *
505      * @throws ClassCastException is thrown if the key maps to an
506      * object that is not a String/Vector.
507      * @throws IllegalArgumentException if one of the tokens is
508      * malformed (does not contain an equals sign).
509      *
510      * @see #getProperties(String, Properties)
511      */

512     public Properties JavaDoc getProperties(String JavaDoc key)
513     {
514         return getProperties(key, null);
515     }
516
517     /**
518      * Get a list of properties associated with the given
519      * configuration key.
520      *
521      * @param key The configuration key.
522      * @param defaults Any default values for the returned
523      * <code>Properties</code> object. Ignored if <code>null</code>.
524      *
525      * @return The associated properties if key is found.
526      *
527      * @throws ClassCastException is thrown if the key maps to an
528      * object that is not a String/Vector of Strings.
529      * @throws IllegalArgumentException if one of the tokens is
530      * malformed (does not contain an equals sign).
531      */

532     public Properties JavaDoc getProperties(String JavaDoc key, Properties JavaDoc defaults)
533     {
534         /*
535          * Grab an array of the tokens for this key.
536          */

537         String JavaDoc[] tokens = getStringArray(key);
538
539         /*
540          * Each token is of the form 'key=value'.
541          */

542         Properties JavaDoc props =
543             (defaults == null ? new Properties JavaDoc() : new Properties JavaDoc(defaults));
544         for (int i = 0; i < tokens.length; i++)
545         {
546             String JavaDoc token = tokens[i];
547             int equalSign = token.indexOf('=');
548             if (equalSign > 0)
549             {
550                 String JavaDoc pkey = token.substring(0, equalSign).trim();
551                 String JavaDoc pvalue = token.substring(equalSign + 1).trim();
552                 props.put(pkey, pvalue);
553             }
554             else if (tokens.length == 1 && "".equals(token))
555             {
556                 // Semantically equivalent to an empty Properties
557
// object.
558
break;
559             }
560             else
561             {
562                 throw new IllegalArgumentException JavaDoc(
563                     '\'' + token + "' does not contain an equals sign");
564             }
565         }
566         return props;
567     }
568
569     /**
570      * Gets a property from the configuration.
571      *
572      * @param key property to retrieve
573      * @return value as object. Will return user value if exists,
574      * if not then default value if exists, otherwise null
575      */

576     public Object JavaDoc getProperty(String JavaDoc key)
577     {
578         // first, try to get from the 'user value' store
579
Object JavaDoc o = getPropertyDirect(key);
580
581         if (o == null)
582         {
583             // if there isn't a value there, get it from the defaults if we have
584
// them
585
if (defaults != null)
586             {
587                 o = defaults.getProperty(key);
588             }
589         }
590
591         //
592
// We must never give a Container Object out. So if the
593
// Return Value is a Container, we fix it up to be a
594
// Vector
595
//
596
if (o instanceof Container)
597         {
598             o = ((Container) o).asVector();
599         }
600         return o;
601    }
602
603     /**
604      * Get a boolean associated with the given configuration key.
605      *
606      * @param key The configuration key.
607      *
608      * @return The associated boolean.
609      *
610      * @throws NoSuchElementException is thrown if the key doesn't
611      * map to an existing object.
612      * @throws ClassCastException is thrown if the key maps to an
613      * object that is not a Boolean.
614      */

615     public boolean getBoolean(String JavaDoc key)
616     {
617         Boolean JavaDoc b = getBoolean(key, (Boolean JavaDoc) null);
618         if (b != null)
619         {
620             return b.booleanValue();
621         }
622         else
623         {
624             throw new NoSuchElementException JavaDoc(
625                 '\'' + key + "' doesn't map to an existing object");
626         }
627     }
628
629     /**
630      * Get a boolean associated with the given configuration key.
631      *
632      * @param key The configuration key.
633      * @param defaultValue The default value.
634      *
635      * @return The associated boolean.
636      *
637      * @throws ClassCastException is thrown if the key maps to an
638      * object that is not a Boolean.
639      */

640     public boolean getBoolean(String JavaDoc key, boolean defaultValue)
641     {
642         return getBoolean(key, new Boolean JavaDoc(defaultValue)).booleanValue();
643     }
644
645     /**
646      * Get a boolean associated with the given configuration key.
647      *
648      * @param key The configuration key.
649      * @param defaultValue The default value.
650      *
651      * @return The associated boolean if key is found and has valid
652      * format, default value otherwise.
653      *
654      * @throws ClassCastException is thrown if the key maps to an
655      * object that is not a Boolean.
656      */

657     public Boolean JavaDoc getBoolean(String JavaDoc key, Boolean JavaDoc defaultValue)
658     {
659         Object JavaDoc value = resolveContainerStore(key);
660
661         if (value instanceof Boolean JavaDoc)
662         {
663             return (Boolean JavaDoc) value;
664         }
665         else if (value instanceof String JavaDoc)
666         {
667             return testBoolean((String JavaDoc) value);
668         }
669         else if (value == null)
670         {
671             if (defaults != null)
672             {
673                 return defaults.getBoolean(key, defaultValue);
674             }
675             else
676             {
677                 log.warn("Use Boolean default value for key '" + key + "' (" + defaultValue + ")");
678                 return defaultValue;
679             }
680         }
681         else
682         {
683             throw new ClassCastException JavaDoc(
684                 '\'' + key + "' doesn't map to a Boolean object");
685         }
686     }
687
688     /**
689      * Get a byte associated with the given configuration key.
690      *
691      * @param key The configuration key.
692      *
693      * @return The associated byte.
694      *
695      * @throws NoSuchElementException is thrown if the key doesn't
696      * map to an existing object.
697      * @throws ClassCastException is thrown if the key maps to an
698      * object that is not a Byte.
699      * @throws NumberFormatException is thrown if the value mapped
700      * by the key has not a valid number format.
701      */

702     public byte getByte(String JavaDoc key)
703     {
704         Byte JavaDoc b = getByte(key, null);
705         if (b != null)
706         {
707             return b.byteValue();
708         }
709         else
710         {
711             throw new NoSuchElementException JavaDoc(
712                 '\'' + key + " doesn't map to an existing object");
713         }
714     }
715
716     /**
717      * Get a byte associated with the given configuration key.
718      *
719      * @param key The configuration key.
720      * @param defaultValue The default value.
721      *
722      * @return The associated byte.
723      *
724      * @throws ClassCastException is thrown if the key maps to an
725      * object that is not a Byte.
726      * @throws NumberFormatException is thrown if the value mapped
727      * by the key has not a valid number format.
728      */

729     public byte getByte(String JavaDoc key, byte defaultValue)
730     {
731         return getByte(key, new Byte JavaDoc(defaultValue)).byteValue();
732     }
733
734     /**
735      * Get a byte associated with the given configuration key.
736      *
737      * @param key The configuration key.
738      * @param defaultValue The default value.
739      *
740      * @return The associated byte if key is found and has valid format, default
741      * value otherwise.
742      *
743      * @throws ClassCastException is thrown if the key maps to an object that
744      * is not a Byte.
745      * @throws NumberFormatException is thrown if the value mapped by the key
746      * has not a valid number format.
747      */

748     public Byte JavaDoc getByte(String JavaDoc key, Byte JavaDoc defaultValue)
749     {
750         Object JavaDoc value = resolveContainerStore(key);
751
752         if (value instanceof Byte JavaDoc)
753         {
754             return (Byte JavaDoc) value;
755         }
756         else if (value instanceof String JavaDoc)
757         {
758             Byte JavaDoc b = new Byte JavaDoc((String JavaDoc) value);
759             return b;
760         }
761         else if (value == null)
762         {
763             if (defaults != null)
764             {
765                 return defaults.getByte(key, defaultValue);
766             }
767             else
768             {
769                 log.warn("Use Byte default value for key '" + key + "' (" + defaultValue + ")");
770                 return defaultValue;
771             }
772         }
773         else
774         {
775             throw new ClassCastException JavaDoc(
776                 '\'' + key + "' doesn't map to a Byte object");
777         }
778     }
779
780     /**
781      * Get a double associated with the given configuration key.
782      *
783      * @param key The configuration key.
784      *
785      * @return The associated double.
786      *
787      * @throws NoSuchElementException is thrown if the key doesn't
788      * map to an existing object.
789      * @throws ClassCastException is thrown if the key maps to an
790      * object that is not a Double.
791      * @throws NumberFormatException is thrown if the value mapped
792      * by the key has not a valid number format.
793      */

794     public double getDouble(String JavaDoc key)
795     {
796         Double JavaDoc d = getDouble(key, null);
797         if (d != null)
798         {
799             return d.doubleValue();
800         }
801         else
802         {
803             throw new NoSuchElementException JavaDoc(
804                 '\'' + key + "' doesn't map to an existing object");
805         }
806     }
807
808     /**
809      * Get a double associated with the given configuration key.
810      *
811      * @param key The configuration key.
812      * @param defaultValue The default value.
813      *
814      * @return The associated double.
815      *
816      * @throws ClassCastException is thrown if the key maps to an
817      * object that is not a Double.
818      * @throws NumberFormatException is thrown if the value mapped
819      * by the key has not a valid number format.
820      */

821     public double getDouble(String JavaDoc key, double defaultValue)
822     {
823         return getDouble(key, new Double JavaDoc(defaultValue)).doubleValue();
824     }
825
826     /**
827      * Get a double associated with the given configuration key.
828      *
829      * @param key The configuration key.
830      * @param defaultValue The default value.
831      *
832      * @return The associated double if key is found and has valid
833      * format, default value otherwise.
834      *
835      * @throws ClassCastException is thrown if the key maps to an
836      * object that is not a Double.
837      * @throws NumberFormatException is thrown if the value mapped
838      * by the key has not a valid number format.
839      */

840     public Double JavaDoc getDouble(String JavaDoc key, Double JavaDoc defaultValue)
841     {
842         Object JavaDoc value = resolveContainerStore(key);
843
844         if (value instanceof Double JavaDoc)
845         {
846             return (Double JavaDoc) value;
847         }
848         else if (value instanceof String JavaDoc)
849         {
850             Double JavaDoc d = new Double JavaDoc((String JavaDoc) value);
851             return d;
852         }
853         else if (value == null)
854         {
855             if (defaults != null)
856             {
857                 return defaults.getDouble(key, defaultValue);
858             }
859             else
860             {
861                 log.warn("Use Double default value for key '" + key + "' (" + defaultValue + ")");
862                 return defaultValue;
863             }
864         }
865         else
866         {
867             throw new ClassCastException JavaDoc(
868                 '\'' + key + "' doesn't map to a Double object");
869         }
870     }
871
872     /**
873      * Get a float associated with the given configuration key.
874      *
875      * @param key The configuration key.
876      *
877      * @return The associated float.
878      *
879      * @throws NoSuchElementException is thrown if the key doesn't
880      * map to an existing object.
881      * @throws ClassCastException is thrown if the key maps to an
882      * object that is not a Float.
883      * @throws NumberFormatException is thrown if the value mapped
884      * by the key has not a valid number format.
885      */

886     public float getFloat(String JavaDoc key)
887     {
888         Float JavaDoc f = getFloat(key, null);
889         if (f != null)
890         {
891             return f.floatValue();
892         }
893         else
894         {
895             throw new NoSuchElementException JavaDoc(
896                 '\'' + key + "' doesn't map to an existing object");
897         }
898     }
899
900     /**
901      * Get a float associated with the given configuration key.
902      *
903      * @param key The configuration key.
904      * @param defaultValue The default value.
905      *
906      * @return The associated float.
907      *
908      * @throws ClassCastException is thrown if the key maps to an
909      * object that is not a Float.
910      * @throws NumberFormatException is thrown if the value mapped
911      * by the key has not a valid number format.
912      */

913     public float getFloat(String JavaDoc key, float defaultValue)
914     {
915         return getFloat(key, new Float JavaDoc(defaultValue)).floatValue();
916     }
917
918     /**
919      * Get a float associated with the given configuration key.
920      *
921      * @param key The configuration key.
922      * @param defaultValue The default value.
923      *
924      * @return The associated float if key is found and has valid
925      * format, default value otherwise.
926      *
927      * @throws ClassCastException is thrown if the key maps to an
928      * object that is not a Float.
929      * @throws NumberFormatException is thrown if the value mapped
930      * by the key has not a valid number format.
931      */

932     public Float JavaDoc getFloat(String JavaDoc key, Float JavaDoc defaultValue)
933     {
934         Object JavaDoc value = resolveContainerStore(key);
935
936         if (value instanceof Float JavaDoc)
937         {
938             return (Float JavaDoc) value;
939         }
940         else if (value instanceof String JavaDoc)
941         {
942             Float JavaDoc f = new Float JavaDoc((String JavaDoc) value);
943             return f;
944         }
945         else if (value == null)
946         {
947             if (defaults != null)
948             {
949                 return defaults.getFloat(key, defaultValue);
950             }
951             else
952             {
953                 log.warn("Use Float default value for key '" + key + "' (" + defaultValue + ")");
954                 return defaultValue;
955             }
956         }
957         else
958         {
959             throw new ClassCastException JavaDoc(
960                 '\'' + key + "' doesn't map to a Float object");
961         }
962     }
963
964     /**
965      * Get a int associated with the given configuration key.
966      *
967      * @param key The configuration key.
968      *
969      * @return The associated int.
970      *
971      * @throws NoSuchElementException is thrown if the key doesn't
972      * map to an existing object.
973      * @throws ClassCastException is thrown if the key maps to an
974      * object that is not a Integer.
975      * @throws NumberFormatException is thrown if the value mapped
976      * by the key has not a valid number format.
977      */

978     public int getInt(String JavaDoc key)
979     {
980         Integer JavaDoc i = getInteger(key, null);
981         if (i != null)
982         {
983             return i.intValue();
984         }
985         else
986         {
987             throw new NoSuchElementException JavaDoc(
988                 '\'' + key + "' doesn't map to an existing object");
989         }
990     }
991
992     /**
993      * Get a int associated with the given configuration key.
994      *
995      * @param key The configuration key.
996      * @param defaultValue The default value.
997      *
998      * @return The associated int.
999      *
1000     * @throws ClassCastException is thrown if the key maps to an
1001     * object that is not a Integer.
1002     * @throws NumberFormatException is thrown if the value mapped
1003     * by the key has not a valid number format.
1004     */

1005    public int getInt(String JavaDoc key, int defaultValue)
1006    {
1007        Integer JavaDoc i = getInteger(key, null);
1008
1009        if (i == null)
1010        {
1011            return defaultValue;
1012        }
1013
1014        return i.intValue();
1015    }
1016
1017    /**
1018     * Get a int associated with the given configuration key.
1019     *
1020     * @param key The configuration key.
1021     * @param defaultValue The default value.
1022     *
1023     * @return The associated int if key is found and has valid format, default
1024     * value otherwise.
1025     *
1026     * @throws ClassCastException is thrown if the key maps to an object that
1027     * is not a Integer.
1028     * @throws NumberFormatException is thrown if the value mapped by the key
1029     * has not a valid number format.
1030     */

1031    public Integer JavaDoc getInteger(String JavaDoc key, Integer JavaDoc defaultValue)
1032    {
1033        Object JavaDoc value = resolveContainerStore(key);
1034
1035        if (value instanceof Integer JavaDoc)
1036        {
1037            return (Integer JavaDoc) value;
1038        }
1039        else if (value instanceof String JavaDoc)
1040        {
1041            Integer JavaDoc i = new Integer JavaDoc((String JavaDoc) value);
1042            return i;
1043        }
1044        else if (value == null)
1045        {
1046            if (defaults != null)
1047            {
1048                return defaults.getInteger(key, defaultValue);
1049            }
1050            else
1051            {
1052                log.warn("Use Integer default value for key '" + key + "' (" + defaultValue + ")");
1053                return defaultValue;
1054            }
1055        }
1056        else
1057        {
1058            throw new ClassCastException JavaDoc(
1059                '\'' + key + "' doesn't map to a Integer object");
1060        }
1061    }
1062
1063    /**
1064     * Get a long associated with the given configuration key.
1065     *
1066     * @param key The configuration key.
1067     *
1068     * @return The associated long.
1069     *
1070     * @throws NoSuchElementException is thrown if the key doesn't
1071     * map to an existing object.
1072     * @throws ClassCastException is thrown if the key maps to an
1073     * object that is not a Long.
1074     * @throws NumberFormatException is thrown if the value mapped
1075     * by the key has not a valid number format.
1076     */

1077    public long getLong(String JavaDoc key)
1078    {
1079        Long JavaDoc l = getLong(key, null);
1080        if (l != null)
1081        {
1082            return l.longValue();
1083        }
1084        else
1085        {
1086            throw new NoSuchElementException JavaDoc(
1087                '\'' + key + "' doesn't map to an existing object");
1088        }
1089    }
1090
1091    /**
1092     * Get a long associated with the given configuration key.
1093     *
1094     * @param key The configuration key.
1095     * @param defaultValue The default value.
1096     *
1097     * @return The associated long.
1098     *
1099     * @throws ClassCastException is thrown if the key maps to an
1100     * object that is not a Long.
1101     * @throws NumberFormatException is thrown if the value mapped
1102     * by the key has not a valid number format.
1103     */

1104    public long getLong(String JavaDoc key, long defaultValue)
1105    {
1106        return getLong(key, new Long JavaDoc(defaultValue)).longValue();
1107    }
1108
1109    /**
1110     * Get a long associated with the given configuration key.
1111     *
1112     * @param key The configuration key.
1113     * @param defaultValue The default value.
1114     *
1115     * @return The associated long if key is found and has valid
1116     * format, default value otherwise.
1117     *
1118     * @throws ClassCastException is thrown if the key maps to an
1119     * object that is not a Long.
1120     * @throws NumberFormatException is thrown if the value mapped
1121     * by the key has not a valid number format.
1122     */

1123    public Long JavaDoc getLong(String JavaDoc key, Long JavaDoc defaultValue)
1124    {
1125        Object JavaDoc value = resolveContainerStore(key);
1126
1127        if (value instanceof Long JavaDoc)
1128        {
1129            return (Long JavaDoc) value;
1130        }
1131        else if (value instanceof String JavaDoc)
1132        {
1133            Long JavaDoc l = new Long JavaDoc((String JavaDoc) value);
1134            return l;
1135        }
1136        else if (value == null)
1137        {
1138            if (defaults != null)
1139            {
1140                return defaults.getLong(key, defaultValue);
1141            }
1142            else
1143            {
1144                log.warn("Use Long default value for key '" + key + "' (" + defaultValue + ")");
1145                return defaultValue;
1146            }
1147        }
1148        else
1149        {
1150            throw new ClassCastException JavaDoc(
1151                '\'' + key + "' doesn't map to a Long object");
1152        }
1153    }
1154
1155    /**
1156     * Get a short associated with the given configuration key.
1157     *
1158     * @param key The configuration key.
1159     *
1160     * @return The associated short.
1161     *
1162     * @throws NoSuchElementException is thrown if the key doesn't
1163     * map to an existing object.
1164     * @throws ClassCastException is thrown if the key maps to an
1165     * object that is not a Short.
1166     * @throws NumberFormatException is thrown if the value mapped
1167     * by the key has not a valid number format.
1168     */

1169    public short getShort(String JavaDoc key)
1170    {
1171        Short JavaDoc s = getShort(key, null);
1172        if (s != null)
1173        {
1174            return s.shortValue();
1175        }
1176        else
1177        {
1178            throw new NoSuchElementException JavaDoc(
1179                '\'' + key + "' doesn't map to an existing object");
1180        }
1181    }
1182
1183    /**
1184     * Get a short associated with the given configuration key.
1185     *
1186     * @param key The configuration key.
1187     * @param defaultValue The default value.
1188     *
1189     * @return The associated short.
1190     *
1191     * @throws ClassCastException is thrown if the key maps to an
1192     * object that is not a Short.
1193     * @throws NumberFormatException is thrown if the value mapped
1194     * by the key has not a valid number format.
1195     */

1196    public short getShort(String JavaDoc key, short defaultValue)
1197    {
1198        return getShort(key, new Short JavaDoc(defaultValue)).shortValue();
1199    }
1200
1201    /**
1202     * Get a short associated with the given configuration key.
1203     *
1204     * @param key The configuration key.
1205     * @param defaultValue The default value.
1206     *
1207     * @return The associated short if key is found and has valid
1208     * format, default value otherwise.
1209     *
1210     * @throws ClassCastException is thrown if the key maps to an
1211     * object that is not a Short.
1212     * @throws NumberFormatException is thrown if the value mapped
1213     * by the key has not a valid number format.
1214     */

1215    public Short JavaDoc getShort(String JavaDoc key, Short JavaDoc defaultValue)
1216    {
1217        Object JavaDoc value = resolveContainerStore(key);
1218
1219        if (value instanceof Short JavaDoc)
1220        {
1221            return (Short JavaDoc) value;
1222        }
1223        else if (value instanceof String JavaDoc)
1224        {
1225            Short JavaDoc s = new Short JavaDoc((String JavaDoc) value);
1226            return s;
1227        }
1228        else if (value == null)
1229        {
1230            if (defaults != null)
1231            {
1232                return defaults.getShort(key, defaultValue);
1233            }
1234            else
1235            {
1236                log.warn("Use Short default value for key '" + key + "' (" + defaultValue + ")");
1237                return defaultValue;
1238            }
1239        }
1240        else
1241        {
1242            throw new ClassCastException JavaDoc(
1243                '\'' + key + "' doesn't map to a Short object");
1244        }
1245    }
1246
1247    /**
1248     * Get a string associated with the given configuration key.
1249     *
1250     * @param key The configuration key.
1251     *
1252     * @return The associated string.
1253     *
1254     * @throws ClassCastException is thrown if the key maps to an object that
1255     * is not a String.
1256     * @throws NoSuchElementException is thrown if the key doesn't
1257     * map to an existing object.
1258     */

1259    public String JavaDoc getString(String JavaDoc key)
1260    {
1261        String JavaDoc s = getString(key, null);
1262        if (s != null)
1263        {
1264            return s;
1265        }
1266        else
1267        {
1268            throw new NoSuchElementException JavaDoc(
1269                '\'' + key + "' doesn't map to an existing object");
1270        }
1271    }
1272
1273    /**
1274     * Get a string associated with the given configuration key.
1275     *
1276     * @param key The configuration key.
1277     * @param defaultValue The default value.
1278     *
1279     * @return The associated string if key is found, default value otherwise.
1280     *
1281     * @throws ClassCastException is thrown if the key maps to an object that
1282     * is not a String.
1283     */

1284    public String JavaDoc getString(String JavaDoc key, String JavaDoc defaultValue)
1285    {
1286        Object JavaDoc value = resolveContainerStore(key);
1287
1288        if (value instanceof String JavaDoc)
1289        {
1290            return interpolate((String JavaDoc) value);
1291        }
1292        else if (value == null)
1293        {
1294            if (defaults != null)
1295            {
1296                return interpolate(defaults.getString(key, defaultValue));
1297            }
1298            else
1299            {
1300                log.warn("Use String default value for key '" + key + "' (" + defaultValue + ")");
1301                return interpolate(defaultValue);
1302            }
1303        }
1304        else
1305        {
1306            throw new ClassCastException JavaDoc(
1307                '\'' + key + "' doesn't map to a String object");
1308        }
1309    }
1310
1311    /**
1312     * Get an array of strings associated with the given configuration
1313     * key.
1314     *
1315     * @param key The configuration key.
1316     *
1317     * @return The associated string array if key is found.
1318     *
1319     * @throws ClassCastException is thrown if the key maps to an
1320     * object that is not a String/Vector of Strings.
1321     */

1322    public String JavaDoc[] getStringArray(String JavaDoc key)
1323    {
1324        Object JavaDoc value = getPropertyDirect(key);
1325
1326        String JavaDoc[] tokens;
1327
1328        if (value instanceof String JavaDoc)
1329        {
1330            tokens = new String JavaDoc[1];
1331
1332            tokens[0] = interpolate((String JavaDoc) value);
1333        }
1334        else if (value instanceof Container)
1335        {
1336            tokens = new String JavaDoc[((Container) value).size()];
1337
1338            for (int i = 0; i < tokens.length; i++)
1339            {
1340                tokens[i] = interpolate((String JavaDoc) ((Container) value).get(i));
1341            }
1342        }
1343        else if (value == null)
1344        {
1345            if (defaults != null)
1346            {
1347                tokens = defaults.getStringArray(key);
1348            }
1349            else
1350            {
1351                tokens = new String JavaDoc[0];
1352            }
1353        }
1354        else
1355        {
1356            throw new ClassCastException JavaDoc(
1357                '\'' + key + "' doesn't map to a String/Vector object");
1358        }
1359        return tokens;
1360    }
1361
1362    /**
1363     * Get a Vector of strings associated with the given configuration key.
1364     *
1365     * @param key The configuration key.
1366     *
1367     * @return The associated Vector.
1368     *
1369     * @throws ClassCastException is thrown if the key maps to an
1370     * object that is not a Vector.
1371     * @throws NoSuchElementException is thrown if the key doesn't
1372     * map to an existing object.
1373     */

1374    public Vector JavaDoc getVector(String JavaDoc key)
1375    {
1376        Vector JavaDoc v = getVector(key, null);
1377        if (v != null)
1378        {
1379            return v;
1380        }
1381        else
1382        {
1383            throw new NoSuchElementException JavaDoc(
1384                '\'' + key + "' doesn't map to an existing object");
1385        }
1386    }
1387
1388    /**
1389     * Get a Vector of strings associated with the given configuration key.
1390     *
1391     * @param key The configuration key.
1392     * @param defaultValue The default value.
1393     *
1394     * @return The associated Vector.
1395     *
1396     * @throws ClassCastException is thrown if the key maps to an
1397     * object that is not a Vector.
1398     */

1399    public Vector JavaDoc getVector(String JavaDoc key, Vector JavaDoc defaultValue)
1400    {
1401        Object JavaDoc value = getPropertyDirect(key);
1402        Vector JavaDoc v = null;
1403
1404        if (value instanceof String JavaDoc)
1405        {
1406            v = new Vector JavaDoc(1);
1407            v.addElement(value);
1408        }
1409        else if (value instanceof Container)
1410        {
1411            v = ((Container) value).asVector();
1412        }
1413        else if (value == null)
1414        {
1415            if (defaults != null)
1416            {
1417                v = defaults.getVector(key, defaultValue);
1418            }
1419            else
1420            {
1421                v = ((defaultValue == null) ? new Vector JavaDoc() : defaultValue);
1422            }
1423        }
1424        else
1425        {
1426            throw new ClassCastException JavaDoc(
1427                '\''
1428                    + key
1429                    + "' doesn't map to a Vector object: "
1430                    + value
1431                    + ", a "
1432                    + value.getClass().getName());
1433        }
1434        return v;
1435    }
1436
1437    /**
1438     * Returns an object from the store described by the key.
1439     * If the value is a Container object, replace it with the
1440     * first object in the container
1441     *
1442     * @param key The property key.
1443     *
1444     * @return value Value, transparently resolving a possible
1445     * Container dependency.
1446     */

1447    private Object JavaDoc resolveContainerStore(String JavaDoc key)
1448    {
1449        Object JavaDoc value = getPropertyDirect(key);
1450        if (value != null && value instanceof Container)
1451        {
1452            value = ((Container) value).get(0);
1453        }
1454        return value;
1455    }
1456
1457    /**
1458     * This class divides into tokens a property value. Token
1459     * separator is "," but commas into the property value are escaped
1460     * using the backslash in front.
1461     */

1462    class PropertiesTokenizer extends StringTokenizer JavaDoc
1463    {
1464        /** The property delimiter used while parsing (a comma). */
1465        static final String JavaDoc DELIMITER = ",";
1466
1467        /**
1468         * Constructor.
1469         *
1470         * @param string A String.
1471         */

1472        public PropertiesTokenizer(String JavaDoc string)
1473        {
1474            super(string, DELIMITER);
1475        }
1476
1477        /**
1478         * Check whether the object has more tokens.
1479         *
1480         * @return True if the object has more tokens.
1481         */

1482        public boolean hasMoreTokens()
1483        {
1484            return super.hasMoreTokens();
1485        }
1486
1487        /**
1488         * Get next token.
1489         *
1490         * @return A String.
1491         */

1492        public String JavaDoc nextToken()
1493        {
1494            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1495
1496            while (hasMoreTokens())
1497            {
1498                String JavaDoc token = super.nextToken();
1499                if (token.endsWith("\\"))
1500                {
1501                    buffer.append(token.substring(0, token.length() - 1));
1502                    buffer.append(DELIMITER);
1503                }
1504                else
1505                {
1506                    buffer.append(token);
1507                    break;
1508                }
1509            }
1510            return buffer.toString().trim();
1511        }
1512    } // class PropertiesTokenizer
1513

1514    /**
1515     * Private Wrapper class for Vector, so we can distinguish between
1516     * Vector objects and our container
1517     */

1518    static class Container
1519    {
1520        /** We're wrapping a List object (A vector) */
1521        private List JavaDoc l = null;
1522
1523        /**
1524         * C'tor
1525         */

1526        public Container()
1527        {
1528            l = new Vector JavaDoc(INITIAL_LIST_SIZE);
1529        }
1530
1531        /**
1532         * Add an Object to the Container
1533         *
1534         * @param o The Object
1535         */

1536        public void add(Object JavaDoc o)
1537        {
1538            l.add(o);
1539        }
1540
1541        /**
1542         * Returns the current size of the Container
1543         *
1544         * @return The Number of elements in the container
1545         */

1546        public int size()
1547        {
1548            return l.size();
1549        }
1550
1551        /**
1552         * Returns the Element at an index
1553         *
1554         * @param index The Index
1555         * @return The element at that index
1556         */

1557        public Object JavaDoc get(int index)
1558        {
1559            return l.get(index);
1560        }
1561
1562        /**
1563         * Returns an Iterator over the container objects
1564         *
1565         * @return An Iterator
1566         */

1567        public Iterator JavaDoc iterator()
1568        {
1569            return l.iterator();
1570        }
1571
1572        /**
1573         * Returns the Elements of the Container as
1574         * a Vector. This is not the internal vector
1575         * element but a shallow copy of the internal
1576         * list. You may modify the returned list without
1577         * modifying the container.
1578         *
1579         * @return A Vector containing the elements of the Container.
1580         */

1581        public Vector JavaDoc asVector()
1582        {
1583            Vector JavaDoc v = new Vector JavaDoc(l.size());
1584
1585            for (Iterator JavaDoc it = l.iterator(); it.hasNext();)
1586            {
1587                v.add(it.next());
1588            }
1589            return v;
1590        }
1591    }
1592}
1593
Popular Tags