View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.configuration;
19  
20  import java.awt.Color;
21  import java.io.Serializable;
22  import java.lang.reflect.Array;
23  import java.math.BigDecimal;
24  import java.math.BigInteger;
25  import java.net.URL;
26  import java.util.ArrayList;
27  import java.util.Calendar;
28  import java.util.Collection;
29  import java.util.Date;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Locale;
33  import java.util.NoSuchElementException;
34  
35  import org.apache.commons.lang.ClassUtils;
36  import org.apache.commons.lang.StringUtils;
37  
38  /***
39   * Decorator providing additional getters for any Configuration. This extended
40   * Configuration supports more types:
41   * <ul>
42   *   <li>{@link java.net.URL}</li>
43   *   <li>{@link java.util.Locale}</li>
44   *   <li>{@link java.util.Date}</li>
45   *   <li>{@link java.util.Calendar}</li>
46   *   <li>{@link java.awt.Color}</li>
47   *   <li>{@link java.net.InetAddress}</li>
48   *   <li>{@link javax.mail.internet.InternetAddress} (requires Javamail in the classpath)</li>
49   *   <li>{@link java.lang.Enum} (Java 5 enumeration types)</li>
50   * </ul>
51   *
52   * Lists and arrays are available for all types.
53   *
54   * <h4>Example</h4>
55   *
56   * Configuration file <tt>config.properties</tt>:
57   * <pre>
58   * title.color = #0000FF
59   * remote.host = 192.168.0.53
60   * default.locales = fr,en,de
61   * email.contact = ebourg@apache.org, oheger@apache.org
62   * </pre>
63   *
64   * Usage:
65   *
66   * <pre>
67   * DataConfiguration config = new DataConfiguration(new PropertiesConfiguration("config.properties"));
68   *
69   * // retrieve a property using a specialized getter
70   * Color color = config.getColor("title.color");
71   *
72   * // retrieve a property using a generic getter
73   * InetAddress host = (InetAddress) config.get(InetAddress.class, "remote.host");
74   * Locale[] locales = (Locale[]) config.getArray(Locale.class, "default.locales");
75   * List contacts = config.getList(InternetAddress.class, "email.contact");
76   * </pre>
77   *
78   * <h4>Dates</h4>
79   *
80   * Date objects are expected to be formatted with the pattern <tt>yyyy-MM-dd HH:mm:ss</tt>.
81   * This default format can be changed by specifying another format in the
82   * getters, or by putting a date format in the configuration under the key
83   * <tt>org.apache.commons.configuration.format.date</tt>.
84   *
85   * @author <a href="ebourg@apache.org">Emmanuel Bourg</a>
86   * @version $Revision: 589380 $, $Date: 2007-10-28 17:37:35 +0100 (So, 28 Okt 2007) $
87   * @since 1.1
88   */
89  public class DataConfiguration extends AbstractConfiguration implements Serializable
90  {
91      /*** The key of the property storing the user defined date format. */
92      public static final String DATE_FORMAT_KEY = "org.apache.commons.configuration.format.date";
93  
94      /*** The default format for dates. */
95      public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
96  
97      /***
98       * The serial version UID.
99       */
100     private static final long serialVersionUID = -69011336405718640L;
101 
102     /*** Stores the wrapped configuration.*/
103     protected Configuration configuration;
104 
105     /***
106      * Creates a new instance of <code>DataConfiguration</code> and sets the
107      * wrapped configuration.
108      *
109      * @param configuration the wrapped configuration
110      */
111     public DataConfiguration(Configuration configuration)
112     {
113         this.configuration = configuration;
114     }
115 
116     /***
117      * Return the configuration decorated by this DataConfiguration.
118      *
119      * @return the wrapped configuration
120      */
121     public Configuration getConfiguration()
122     {
123         return configuration;
124     }
125 
126     public Object getProperty(String key)
127     {
128         return configuration.getProperty(key);
129     }
130 
131     protected void addPropertyDirect(String key, Object obj)
132     {
133         if (configuration instanceof AbstractConfiguration)
134         {
135             ((AbstractConfiguration) configuration).addPropertyDirect(key, obj);
136         }
137         else
138         {
139             configuration.addProperty(key, obj);
140         }
141     }
142 
143     public boolean isEmpty()
144     {
145         return configuration.isEmpty();
146     }
147 
148     public boolean containsKey(String key)
149     {
150         return configuration.containsKey(key);
151     }
152 
153     public void clearProperty(String key)
154     {
155         configuration.clearProperty(key);
156     }
157 
158     public Iterator getKeys()
159     {
160         return configuration.getKeys();
161     }
162 
163     /***
164      * Get an object of the specified type associated with the given
165      * configuration key. If the key doesn't map to an existing object, the
166      * method returns null unless {@link #isThrowExceptionOnMissing()} is set
167      * to <tt>true</tt>.
168      *
169      * @param cls the target type of the value
170      * @param key the key of the value
171      *
172      * @return the value of the requested type for the key
173      *
174      * @throws NoSuchElementException if the key doesn't map to an existing
175      *     object and <tt>throwExceptionOnMissing=true</tt>
176      * @throws ConversionException if the value is not compatible with the requested type
177      *
178      * @since 1.5
179      */
180     public Object get(Class cls, String key)
181     {
182         Object value = get(cls, key, null);
183         if (value != null)
184         {
185             return value;
186         }
187         else if (isThrowExceptionOnMissing())
188         {
189             throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
190         }
191         else
192         {
193             return null;
194         }
195     }
196 
197     /***
198      * Get an object of the specified type associated with the given
199      * configuration key. If the key doesn't map to an existing object, the
200      * default value is returned.
201      *
202      * @param cls          the target type of the value
203      * @param key          the key of the value
204      * @param defaultValue the default value
205      *
206      * @return the value of the requested type for the key
207      *
208      * @throws ConversionException if the value is not compatible with the requested type
209      *
210      * @since 1.5
211      */
212     public Object get(Class cls, String key, Object defaultValue)
213     {
214         Object value = resolveContainerStore(key);
215 
216         if (value == null)
217         {
218             return defaultValue;
219         }
220         else
221         {
222             try
223             {
224                 if (Date.class.equals(cls) || Calendar.class.equals(cls))
225                 {
226                     return PropertyConverter.to(cls, interpolate(value), new String[] {getDefaultDateFormat()});
227                 }
228                 else
229                 {
230                     return PropertyConverter.to(cls, interpolate(value), null);
231                 }
232             }
233             catch (ConversionException e)
234             {
235                 throw new ConversionException('\'' + key + "' doesn't map to a " + cls, e);
236             }
237         }
238     }
239 
240     /***
241      * Get a list of typed objects associated with the given configuration key.
242      * If the key doesn't map to an existing object, an empty list is returned.
243      *
244      * @param cls the type expected for the elements of the list
245      * @param key The configuration key.
246      * @return The associated list if the key is found.
247      *
248      * @throws ConversionException is thrown if the key maps to an object that
249      *     is not compatible with a list of the specified class.
250      *
251      * @since 1.5
252      */
253     public List getList(Class cls, String key)
254     {
255         return getList(cls, key, new ArrayList());
256     }
257 
258     /***
259      * Get a list of typed objects associated with the given configuration key.
260      * If the key doesn't map to an existing object, the default value is
261      * returned.
262      *
263      * @param cls the      type expected for the elements of the list
264      * @param key          the configuration key.
265      * @param defaultValue the default value.
266      * @return The associated List.
267      *
268      * @throws ConversionException is thrown if the key maps to an object that
269      *     is not compatible with a list of the specified class.
270      *
271      * @since 1.5
272      */
273     public List getList(Class cls, String key, List defaultValue)
274     {
275         Object value = getProperty(key);
276         Class valueClass = value != null ? value.getClass() : null;
277 
278         List list;
279 
280         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
281         {
282             // the value is null or is an empty string
283             list = defaultValue;
284         }
285         else
286         {
287             list = new ArrayList();
288 
289             Object[] params = null;
290             if (cls.equals(Date.class) || cls.equals(Calendar.class))
291             {
292                 params = new Object[] {getDefaultDateFormat()};
293             }
294 
295             try
296             {
297                 if (valueClass.isArray())
298                 {
299                     // get the class of the objects contained in the array
300                     Class arrayType = valueClass.getComponentType();
301                     int length = Array.getLength(value);
302 
303                     if (arrayType.equals(cls)
304                             || (arrayType.isPrimitive() && cls.equals(ClassUtils.primitiveToWrapper(arrayType))))
305                     {
306                         // the value is an array of the specified type, or an array
307                         // of the primitive type derived from the specified type
308                         for (int i = 0; i < length; i++)
309                         {
310                             list.add(Array.get(value, i));
311                         }
312                     }
313                     else
314                     {
315                         // attempt to convert the elements of the array
316                         for (int i = 0; i < length; i++)
317                         {
318                             list.add(PropertyConverter.to(cls, interpolate(Array.get(value, i)), params));
319                         }
320                     }
321                 }
322                 else if (value instanceof Collection)
323                 {
324                     Collection values = (Collection) value;
325 
326                     Iterator it = values.iterator();
327                     while (it.hasNext())
328                     {
329                         list.add(PropertyConverter.to(cls, interpolate(it.next()), params));
330                     }
331                 }
332                 else
333                 {
334                     // attempt to convert a single value
335                     list.add(PropertyConverter.to(cls, interpolate(value), params));
336                 }
337             }
338             catch (ConversionException e)
339             {
340                 throw new ConversionException("'" + key + "' doesn't map to a list of " + cls, e);
341             }
342         }
343 
344         return list;
345     }
346 
347     /***
348      * Get an array of typed objects associated with the given configuration key.
349      * If the key doesn't map to an existing object, an empty list is returned.
350      *
351      * @param cls the type expected for the elements of the array
352      * @param key The configuration key.
353      * @return The associated array if the key is found, and the value compatible with the type specified.
354      *
355      * @throws ConversionException is thrown if the key maps to an object that
356      *     is not compatible with a list of the specified class.
357      *
358      * @since 1.5
359      */
360     public Object getArray(Class cls, String key)
361     {
362         return getArray(cls, key, Array.newInstance(cls, 0));
363     }
364 
365     /***
366      * Get an array of typed objects associated with the given configuration key.
367      * If the key doesn't map to an existing object, the default value is returned.
368      *
369      * @param cls          the type expected for the elements of the array
370      * @param key          the configuration key.
371      * @param defaultValue the default value
372      * @return The associated array if the key is found, and the value compatible with the type specified.
373      *
374      * @throws ConversionException is thrown if the key maps to an object that
375      *     is not compatible with an array of the specified class.
376      * @throws IllegalArgumentException if the default value is not an array of the specified type
377      *
378      * @since 1.5
379      */
380     public Object getArray(Class cls, String key, Object defaultValue)
381     {
382         // check the type of the default value
383         if (defaultValue != null
384                 && (!defaultValue.getClass().isArray() || !cls
385                         .isAssignableFrom(defaultValue.getClass()
386                                 .getComponentType())))
387         {
388             throw new IllegalArgumentException(
389                     "The type of the default value (" + defaultValue.getClass()
390                             + ")" + " is not an array of the specified class ("
391                             + cls + ")");
392         }
393 
394         if (cls.isPrimitive())
395         {
396             return getPrimitiveArray(cls, key, defaultValue);
397         }
398 
399         List list = getList(cls, key);
400         if (list.isEmpty())
401         {
402             return defaultValue;
403         }
404         else
405         {
406             return list.toArray((Object[]) Array.newInstance(cls, list.size()));
407         }
408     }
409 
410     /***
411      * Get an array of primitive values associated with the given configuration key.
412      * If the key doesn't map to an existing object, the default value is returned.
413      *
414      * @param cls          the primitive type expected for the elements of the array
415      * @param key          the configuration key.
416      * @param defaultValue the default value
417      * @return The associated array if the key is found, and the value compatible with the type specified.
418      *
419      * @throws ConversionException is thrown if the key maps to an object that
420      *     is not compatible with an array of the specified class.
421      *
422      * @since 1.5
423      */
424     private Object getPrimitiveArray(Class cls, String key, Object defaultValue)
425     {
426         Object value = getProperty(key);
427         Class valueClass = value != null ? value.getClass() : null;
428 
429         Object array;
430 
431         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
432         {
433             // the value is null or is an empty string
434             array = defaultValue;
435         }
436         else
437         {
438             if (valueClass.isArray())
439             {
440                 // get the class of the objects contained in the array
441                 Class arrayType = valueClass.getComponentType();
442                 int length = Array.getLength(value);
443 
444                 if (arrayType.equals(cls))
445                 {
446                     // the value is an array of the same primitive type
447                     array = value;
448                 }
449                 else if (arrayType.equals(ClassUtils.primitiveToWrapper(cls)))
450                 {
451                     // the value is an array of the wrapper type derived from the specified primitive type
452                     array = Array.newInstance(cls, length);
453 
454                     for (int i = 0; i < length; i++)
455                     {
456                         Array.set(array, i, Array.get(value, i));
457                     }
458                 }
459                 else
460                 {
461                     throw new ConversionException('\'' + key + "' (" + arrayType + ")"
462                             + " doesn't map to a compatible array of " + cls);
463                 }
464             }
465             else if (value instanceof Collection)
466             {
467                 Collection values = (Collection) value;
468 
469                 array = Array.newInstance(cls, values.size());
470 
471                 Iterator it = values.iterator();
472                 int i = 0;
473                 while (it.hasNext())
474                 {
475                     Array.set(array, i++, PropertyConverter.to(cls, interpolate(it.next()), null));
476                 }
477             }
478             else
479             {
480                 try
481                 {
482                     // attempt to convert a single value
483                     Object convertedValue = PropertyConverter.to(cls, interpolate(value), null);
484 
485                     // create an array of one element
486                     array = Array.newInstance(cls, 1);
487                     Array.set(array, 0, convertedValue);
488                 }
489                 catch (ConversionException e)
490                 {
491                     throw new ConversionException('\'' + key + "' doesn't map to an array of " + cls, e);
492                 }
493             }
494         }
495 
496         return array;
497     }
498 
499     /***
500      * Get a list of Boolean objects associated with the given
501      * configuration key. If the key doesn't map to an existing object
502      * an empty list is returned.
503      *
504      * @param key The configuration key.
505      * @return The associated Boolean list if the key is found.
506      *
507      * @throws ConversionException is thrown if the key maps to an
508      *         object that is not a list of booleans.
509      */
510     public List getBooleanList(String key)
511     {
512         return getBooleanList(key, new ArrayList());
513     }
514 
515     /***
516      * Get a list of Boolean objects associated with the given
517      * configuration key. If the key doesn't map to an existing object,
518      * the default value is returned.
519      *
520      * @param key The configuration key.
521      * @param defaultValue The default value.
522      * @return The associated List of Booleans.
523      *
524      * @throws ConversionException is thrown if the key maps to an
525      *         object that is not a list of booleans.
526      */
527     public List getBooleanList(String key, List defaultValue)
528     {
529          return getList(Boolean.class, key, defaultValue);
530     }
531 
532     /***
533      * Get an array of boolean primitives associated with the given
534      * configuration key. If the key doesn't map to an existing object
535      * an empty array is returned.
536      *
537      * @param key The configuration key.
538      * @return The associated boolean array if the key is found.
539      *
540      * @throws ConversionException is thrown if the key maps to an
541      *         object that is not a list of booleans.
542      */
543     public boolean[] getBooleanArray(String key)
544     {
545         return (boolean[]) getArray(Boolean.TYPE, key);
546     }
547 
548     /***
549      * Get an array of boolean primitives associated with the given
550      * configuration key. If the key doesn't map to an existing object,
551      * the default value is returned.
552      *
553      * @param key          The configuration key.
554      * @param defaultValue The default value.
555      * @return The associated boolean array if the key is found.
556      *
557      * @throws ConversionException is thrown if the key maps to an
558      *         object that is not a list of booleans.
559      */
560     public boolean[] getBooleanArray(String key, boolean[] defaultValue)
561     {
562         return (boolean[]) getArray(Boolean.TYPE, key, defaultValue);
563     }
564 
565     /***
566      * Get a list of Byte objects associated with the given configuration key.
567      * If the key doesn't map to an existing object an empty list is returned.
568      *
569      * @param key The configuration key.
570      * @return The associated Byte list if the key is found.
571      *
572      * @throws ConversionException is thrown if the key maps to an
573      *         object that is not a list of bytes.
574      */
575     public List getByteList(String key)
576     {
577         return getByteList(key, new ArrayList());
578     }
579 
580     /***
581      * Get a list of Byte objects associated with the given configuration key.
582      * If the key doesn't map to an existing object, the default value is
583      * returned.
584      *
585      * @param key The configuration key.
586      * @param defaultValue The default value.
587      * @return The associated List of Bytes.
588      *
589      * @throws ConversionException is thrown if the key maps to an
590      *         object that is not a list of bytes.
591      */
592     public List getByteList(String key, List defaultValue)
593     {
594         return getList(Byte.class, key, defaultValue);
595     }
596 
597     /***
598      * Get an array of byte primitives associated with the given
599      * configuration key. If the key doesn't map to an existing object
600      * an empty array is returned.
601      *
602      * @param key The configuration key.
603      * @return The associated byte array if the key is found.
604      *
605      * @throws ConversionException is thrown if the key maps to an
606      *         object that is not a list of bytes.
607      */
608     public byte[] getByteArray(String key)
609     {
610         return getByteArray(key, new byte[0]);
611     }
612 
613     /***
614      * Get an array of byte primitives associated with the given
615      * configuration key. If the key doesn't map to an existing object
616      * an empty array is returned.
617      *
618      * @param key The configuration key.
619      * @param defaultValue the default value, which will be returned if the property is not found
620      * @return The associated byte array if the key is found.
621      *
622      * @throws ConversionException is thrown if the key maps to an
623      *         object that is not a list of bytes.
624      */
625     public byte[] getByteArray(String key, byte[] defaultValue)
626     {
627         return (byte[]) getArray(Byte.TYPE, key, defaultValue);
628     }
629 
630     /***
631      * Get a list of Short objects associated with the given configuration key.
632      * If the key doesn't map to an existing object an empty list is returned.
633      *
634      * @param key The configuration key.
635      * @return The associated Short list if the key is found.
636      *
637      * @throws ConversionException is thrown if the key maps to an
638      *         object that is not a list of shorts.
639      */
640     public List getShortList(String key)
641     {
642         return getShortList(key, new ArrayList());
643     }
644 
645     /***
646      * Get a list of Short objects associated with the given configuration key.
647      * If the key doesn't map to an existing object, the default value is
648      * returned.
649      *
650      * @param key The configuration key.
651      * @param defaultValue The default value.
652      * @return The associated List of Shorts.
653      *
654      * @throws ConversionException is thrown if the key maps to an
655      *         object that is not a list of shorts.
656      */
657     public List getShortList(String key, List defaultValue)
658     {
659         return getList(Short.class, key, defaultValue);
660     }
661 
662     /***
663      * Get an array of short primitives associated with the given
664      * configuration key. If the key doesn't map to an existing object
665      * an empty array is returned.
666      *
667      * @param key The configuration key.
668      * @return The associated short array if the key is found.
669      *
670      * @throws ConversionException is thrown if the key maps to an
671      *         object that is not a list of shorts.
672      */
673     public short[] getShortArray(String key)
674     {
675         return getShortArray(key, new short[0]);
676     }
677 
678     /***
679      * Get an array of short primitives associated with the given
680      * configuration key. If the key doesn't map to an existing object
681      * an empty array is returned.
682      *
683      * @param key The configuration key.
684      * @param defaultValue the default value, which will be returned if the property is not found
685      * @return The associated short array if the key is found.
686      *
687      * @throws ConversionException is thrown if the key maps to an
688      *         object that is not a list of shorts.
689      */
690     public short[] getShortArray(String key, short[] defaultValue)
691     {
692         return (short[]) getArray(Short.TYPE, key, defaultValue);
693     }
694 
695     /***
696      * Get a list of Integer objects associated with the given
697      * configuration key. If the key doesn't map to an existing object
698      * an empty list is returned.
699      *
700      * @param key The configuration key.
701      * @return The associated Integer list if the key is found.
702      *
703      * @throws ConversionException is thrown if the key maps to an
704      *         object that is not a list of integers.
705      */
706     public List getIntegerList(String key)
707     {
708         return getIntegerList(key, new ArrayList());
709     }
710 
711     /***
712      * Get a list of Integer objects associated with the given
713      * configuration key. If the key doesn't map to an existing object,
714      * the default value is returned.
715      *
716      * @param key The configuration key.
717      * @param defaultValue The default value.
718      * @return The associated List of Integers.
719      *
720      * @throws ConversionException is thrown if the key maps to an
721      *         object that is not a list of integers.
722      */
723     public List getIntegerList(String key, List defaultValue)
724     {
725         return getList(Integer.class, key, defaultValue);
726     }
727 
728     /***
729      * Get an array of int primitives associated with the given
730      * configuration key. If the key doesn't map to an existing object
731      * an empty array is returned.
732      *
733      * @param key The configuration key.
734      * @return The associated int array if the key is found.
735      *
736      * @throws ConversionException is thrown if the key maps to an
737      *         object that is not a list of integers.
738      */
739     public int[] getIntArray(String key)
740     {
741         return getIntArray(key, new int[0]);
742     }
743 
744     /***
745      * Get an array of int primitives associated with the given
746      * configuration key. If the key doesn't map to an existing object
747      * an empty array is returned.
748      *
749      * @param key The configuration key.
750      * @param defaultValue the default value, which will be returned if the property is not found
751      * @return The associated int array if the key is found.
752      *
753      * @throws ConversionException is thrown if the key maps to an
754      *         object that is not a list of integers.
755      */
756     public int[] getIntArray(String key, int[] defaultValue)
757     {
758         return (int[]) getArray(Integer.TYPE, key, defaultValue);
759     }
760 
761     /***
762      * Get a list of Long objects associated with the given configuration key.
763      * If the key doesn't map to an existing object an empty list is returned.
764      *
765      * @param key The configuration key.
766      * @return The associated Long list if the key is found.
767      *
768      * @throws ConversionException is thrown if the key maps to an
769      *         object that is not a list of longs.
770      */
771     public List getLongList(String key)
772     {
773         return getLongList(key, new ArrayList());
774     }
775 
776     /***
777      * Get a list of Long objects associated with the given configuration key.
778      * If the key doesn't map to an existing object, the default value is
779      * returned.
780      *
781      * @param key The configuration key.
782      * @param defaultValue The default value.
783      * @return The associated List of Longs.
784      *
785      * @throws ConversionException is thrown if the key maps to an
786      *         object that is not a list of longs.
787      */
788     public List getLongList(String key, List defaultValue)
789     {
790         return getList(Long.class, key, defaultValue);
791     }
792 
793     /***
794      * Get an array of long primitives associated with the given
795      * configuration key. If the key doesn't map to an existing object
796      * an empty array is returned.
797      *
798      * @param key The configuration key.
799      * @return The associated long array if the key is found.
800      *
801      * @throws ConversionException is thrown if the key maps to an
802      *         object that is not a list of longs.
803      */
804     public long[] getLongArray(String key)
805     {
806         return getLongArray(key, new long[0]);
807     }
808 
809     /***
810      * Get an array of long primitives associated with the given
811      * configuration key. If the key doesn't map to an existing object
812      * an empty array is returned.
813      *
814      * @param key The configuration key.
815      * @param defaultValue the default value, which will be returned if the property is not found
816      * @return The associated long array if the key is found.
817      *
818      * @throws ConversionException is thrown if the key maps to an
819      *         object that is not a list of longs.
820      */
821     public long[] getLongArray(String key, long[] defaultValue)
822     {
823         return (long[]) getArray(Long.TYPE, key, defaultValue);
824     }
825 
826     /***
827      * Get a list of Float objects associated with the given configuration key.
828      * If the key doesn't map to an existing object an empty list is returned.
829      *
830      * @param key The configuration key.
831      * @return The associated Float list if the key is found.
832      *
833      * @throws ConversionException is thrown if the key maps to an
834      *         object that is not a list of floats.
835      */
836     public List getFloatList(String key)
837     {
838         return getFloatList(key, new ArrayList());
839     }
840 
841     /***
842      * Get a list of Float objects associated with the given
843      * configuration key. If the key doesn't map to an existing object,
844      * the default value is returned.
845      *
846      * @param key The configuration key.
847      * @param defaultValue The default value.
848      * @return The associated List of Floats.
849      *
850      * @throws ConversionException is thrown if the key maps to an
851      *         object that is not a list of floats.
852      */
853     public List getFloatList(String key, List defaultValue)
854     {
855         return getList(Float.class, key, defaultValue);
856     }
857 
858     /***
859      * Get an array of float primitives associated with the given
860      * configuration key. If the key doesn't map to an existing object
861      * an empty array is returned.
862      *
863      * @param key The configuration key.
864      * @return The associated float array if the key is found.
865      *
866      * @throws ConversionException is thrown if the key maps to an
867      *         object that is not a list of floats.
868      */
869     public float[] getFloatArray(String key)
870     {
871         return getFloatArray(key, new float[0]);
872     }
873 
874     /***
875      * Get an array of float primitives associated with the given
876      * configuration key. If the key doesn't map to an existing object
877      * an empty array is returned.
878      *
879      * @param key The configuration key.
880      * @param defaultValue the default value, which will be returned if the property is not found
881      * @return The associated float array if the key is found.
882      *
883      * @throws ConversionException is thrown if the key maps to an
884      *         object that is not a list of floats.
885      */
886     public float[] getFloatArray(String key, float[] defaultValue)
887     {
888         return (float[]) getArray(Float.TYPE, key, defaultValue);
889     }
890 
891     /***
892      * Get a list of Double objects associated with the given
893      * configuration key. If the key doesn't map to an existing object
894      * an empty list is returned.
895      *
896      * @param key The configuration key.
897      * @return The associated Double list if the key is found.
898      *
899      * @throws ConversionException is thrown if the key maps to an
900      *         object that is not a list of doubles.
901      */
902     public List getDoubleList(String key)
903     {
904         return getDoubleList(key, new ArrayList());
905     }
906 
907     /***
908      * Get a list of Double objects associated with the given
909      * configuration key. If the key doesn't map to an existing object,
910      * the default value is returned.
911      *
912      * @param key The configuration key.
913      * @param defaultValue The default value.
914      * @return The associated List of Doubles.
915      *
916      * @throws ConversionException is thrown if the key maps to an
917      *         object that is not a list of doubles.
918      */
919     public List getDoubleList(String key, List defaultValue)
920     {
921         return getList(Double.class, key, defaultValue);
922     }
923 
924     /***
925      * Get an array of double primitives associated with the given
926      * configuration key. If the key doesn't map to an existing object
927      * an empty array is returned.
928      *
929      * @param key The configuration key.
930      * @return The associated double array if the key is found.
931      *
932      * @throws ConversionException is thrown if the key maps to an
933      *         object that is not a list of doubles.
934      */
935     public double[] getDoubleArray(String key)
936     {
937         return getDoubleArray(key, new double[0]);
938     }
939 
940     /***
941      * Get an array of double primitives associated with the given
942      * configuration key. If the key doesn't map to an existing object
943      * an empty array is returned.
944      *
945      * @param key The configuration key.
946      * @param defaultValue the default value, which will be returned if the property is not found
947      * @return The associated double array if the key is found.
948      *
949      * @throws ConversionException is thrown if the key maps to an
950      *         object that is not a list of doubles.
951      */
952     public double[] getDoubleArray(String key, double[] defaultValue)
953     {
954         return (double[]) getArray(Double.TYPE, key, defaultValue);
955     }
956 
957     /***
958      * Get a list of BigIntegers associated with the given configuration key.
959      * If the key doesn't map to an existing object an empty list is returned.
960      *
961      * @param key The configuration key.
962      * @return The associated BigInteger list if the key is found.
963      *
964      * @throws ConversionException is thrown if the key maps to an
965      *         object that is not a list of BigIntegers.
966      */
967     public List getBigIntegerList(String key)
968     {
969         return getBigIntegerList(key, new ArrayList());
970     }
971 
972     /***
973      * Get a list of BigIntegers associated with the given configuration key.
974      * If the key doesn't map to an existing object, the default value is
975      * returned.
976      *
977      * @param key The configuration key.
978      * @param defaultValue The default value.
979      * @return The associated List of BigIntegers.
980      *
981      * @throws ConversionException is thrown if the key maps to an
982      *         object that is not a list of BigIntegers.
983      */
984     public List getBigIntegerList(String key, List defaultValue)
985     {
986         return getList(BigInteger.class, key, defaultValue);
987     }
988 
989     /***
990      * Get an array of BigIntegers associated with the given
991      * configuration key. If the key doesn't map to an existing object
992      * an empty array is returned.
993      *
994      * @param key The configuration key.
995      * @return The associated BigInteger array if the key is found.
996      *
997      * @throws ConversionException is thrown if the key maps to an
998      *         object that is not a list of BigIntegers.
999      */
1000     public BigInteger[] getBigIntegerArray(String key)
1001     {
1002         return getBigIntegerArray(key, new BigInteger[0]);
1003     }
1004 
1005     /***
1006      * Get an array of BigIntegers associated with the given
1007      * configuration key. If the key doesn't map to an existing object
1008      * an empty array is returned.
1009      *
1010      * @param key The configuration key.
1011      * @param defaultValue the default value, which will be returned if the property is not found
1012      * @return The associated BigInteger array if the key is found.
1013      *
1014      * @throws ConversionException is thrown if the key maps to an
1015      *         object that is not a list of BigIntegers.
1016      */
1017     public BigInteger[] getBigIntegerArray(String key, BigInteger[] defaultValue)
1018     {
1019         return (BigInteger[]) getArray(BigInteger.class, key, defaultValue);
1020     }
1021 
1022     /***
1023      * Get a list of BigDecimals associated with the given configuration key.
1024      * If the key doesn't map to an existing object an empty list is returned.
1025      *
1026      * @param key The configuration key.
1027      * @return The associated BigDecimal list if the key is found.
1028      *
1029      * @throws ConversionException is thrown if the key maps to an
1030      *         object that is not a list of BigDecimals.
1031      */
1032     public List getBigDecimalList(String key)
1033     {
1034         return getBigDecimalList(key, new ArrayList());
1035     }
1036 
1037     /***
1038      * Get a list of BigDecimals associated with the given configuration key.
1039      * If the key doesn't map to an existing object, the default value is
1040      * returned.
1041      *
1042      * @param key The configuration key.
1043      * @param defaultValue The default value.
1044      * @return The associated List of BigDecimals.
1045      *
1046      * @throws ConversionException is thrown if the key maps to an
1047      *         object that is not a list of BigDecimals.
1048      */
1049     public List getBigDecimalList(String key, List defaultValue)
1050     {
1051         return getList(BigDecimal.class, key, defaultValue);
1052     }
1053 
1054     /***
1055      * Get an array of BigDecimals associated with the given
1056      * configuration key. If the key doesn't map to an existing object
1057      * an empty array is returned.
1058      *
1059      * @param key The configuration key.
1060      * @return The associated BigDecimal array if the key is found.
1061      *
1062      * @throws ConversionException is thrown if the key maps to an
1063      *         object that is not a list of BigDecimals.
1064      */
1065     public BigDecimal[] getBigDecimalArray(String key)
1066     {
1067         return getBigDecimalArray(key, new BigDecimal[0]);
1068     }
1069 
1070     /***
1071      * Get an array of BigDecimals associated with the given
1072      * configuration key. If the key doesn't map to an existing object
1073      * an empty array is returned.
1074      *
1075      * @param key The configuration key.
1076      * @param defaultValue the default value, which will be returned if the property is not found
1077      * @return The associated BigDecimal array if the key is found.
1078      *
1079      * @throws ConversionException is thrown if the key maps to an
1080      *         object that is not a list of BigDecimals.
1081      */
1082     public BigDecimal[] getBigDecimalArray(String key, BigDecimal[] defaultValue)
1083     {
1084         return (BigDecimal[]) getArray(BigDecimal.class, key, defaultValue);
1085     }
1086 
1087     /***
1088      * Get an URL associated with the given configuration key.
1089      *
1090      * @param key The configuration key.
1091      * @return The associated URL.
1092      *
1093      * @throws ConversionException is thrown if the key maps to an
1094      *         object that is not an URL.
1095      */
1096     public URL getURL(String key)
1097     {
1098         return (URL) get(URL.class, key);
1099     }
1100 
1101     /***
1102      * Get an URL associated with the given configuration key.
1103      * If the key doesn't map to an existing object, the default value
1104      * is returned.
1105      *
1106      * @param key          The configuration key.
1107      * @param defaultValue The default value.
1108      * @return The associated URL.
1109      *
1110      * @throws ConversionException is thrown if the key maps to an
1111      *         object that is not an URL.
1112      */
1113     public URL getURL(String key, URL defaultValue)
1114     {
1115         return (URL) get(URL.class, key, defaultValue);
1116     }
1117 
1118     /***
1119      * Get a list of URLs associated with the given configuration key.
1120      * If the key doesn't map to an existing object an empty list is returned.
1121      *
1122      * @param key The configuration key.
1123      * @return The associated URL list if the key is found.
1124      *
1125      * @throws ConversionException is thrown if the key maps to an
1126      *         object that is not a list of URLs.
1127      */
1128     public List getURLList(String key)
1129     {
1130         return getURLList(key, new ArrayList());
1131     }
1132 
1133     /***
1134      * Get a list of URLs associated with the given configuration key.
1135      * If the key doesn't map to an existing object, the default value is
1136      * returned.
1137      *
1138      * @param key The configuration key.
1139      * @param defaultValue The default value.
1140      * @return The associated List of URLs.
1141      *
1142      * @throws ConversionException is thrown if the key maps to an
1143      *         object that is not a list of URLs.
1144      */
1145     public List getURLList(String key, List defaultValue)
1146     {
1147         return getList(URL.class, key, defaultValue);
1148     }
1149 
1150     /***
1151      * Get an array of URLs associated with the given configuration key.
1152      * If the key doesn't map to an existing object an empty array is returned.
1153      *
1154      * @param key The configuration key.
1155      * @return The associated URL array if the key is found.
1156      *
1157      * @throws ConversionException is thrown if the key maps to an
1158      *         object that is not a list of URLs.
1159      */
1160     public URL[] getURLArray(String key)
1161     {
1162         return getURLArray(key, new URL[0]);
1163     }
1164 
1165     /***
1166      * Get an array of URLs associated with the given configuration key.
1167      * If the key doesn't map to an existing object an empty array is returned.
1168      *
1169      * @param key The configuration key.
1170      * @param defaultValue the default value, which will be returned if the property is not found
1171      * @return The associated URL array if the key is found.
1172      *
1173      * @throws ConversionException is thrown if the key maps to an
1174      *         object that is not a list of URLs.
1175      */
1176     public URL[] getURLArray(String key, URL[] defaultValue)
1177     {
1178         return (URL[]) getArray(URL.class, key, defaultValue);
1179     }
1180 
1181     /***
1182      * Get a Date associated with the given configuration key. If the property
1183      * is a String, it will be parsed with the format defined by the user in
1184      * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
1185      * {@link #DEFAULT_DATE_FORMAT} pattern.
1186      *
1187      * @param key The configuration key.
1188      * @return The associated Date.
1189      *
1190      * @throws ConversionException is thrown if the key maps to an
1191      *         object that is not a Date.
1192      */
1193     public Date getDate(String key)
1194     {
1195         return (Date) get(Date.class, key);
1196     }
1197 
1198     /***
1199      * Get a Date associated with the given configuration key. If the property
1200      * is a String, it will be parsed with the specified format pattern.
1201      *
1202      * @param key    The configuration key.
1203      * @param format The non-localized {@link java.text.DateFormat} pattern.
1204      * @return The associated Date
1205      *
1206      * @throws ConversionException is thrown if the key maps to an
1207      *         object that is not a Date.
1208      */
1209     public Date getDate(String key, String format)
1210     {
1211         Date value = getDate(key, null, format);
1212         if (value != null)
1213         {
1214             return value;
1215         }
1216         else if (isThrowExceptionOnMissing())
1217         {
1218             throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
1219         }
1220         else
1221         {
1222             return null;
1223         }
1224     }
1225 
1226     /***
1227      * Get a Date associated with the given configuration key. If the property
1228      * is a String, it will be parsed with the format defined by the user in
1229      * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
1230      * {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map to an
1231      * existing object, the default value is returned.
1232      *
1233      * @param key          The configuration key.
1234      * @param defaultValue The default value.
1235      * @return The associated Date.
1236      *
1237      * @throws ConversionException is thrown if the key maps to an
1238      *         object that is not a Date.
1239      */
1240     public Date getDate(String key, Date defaultValue)
1241     {
1242         return getDate(key, defaultValue, getDefaultDateFormat());
1243     }
1244 
1245     /***
1246      * Get a Date associated with the given configuration key. If the property
1247      * is a String, it will be parsed with the specified format pattern.
1248      * If the key doesn't map to an existing object, the default value
1249      * is returned.
1250      *
1251      * @param key          The configuration key.
1252      * @param defaultValue The default value.
1253      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1254      * @return The associated Date.
1255      *
1256      * @throws ConversionException is thrown if the key maps to an
1257      *         object that is not a Date.
1258      */
1259     public Date getDate(String key, Date defaultValue, String format)
1260     {
1261         Object value = resolveContainerStore(key);
1262 
1263         if (value == null)
1264         {
1265             return defaultValue;
1266         }
1267         else
1268         {
1269             try
1270             {
1271                 return PropertyConverter.toDate(interpolate(value), format);
1272             }
1273             catch (ConversionException e)
1274             {
1275                 throw new ConversionException('\'' + key + "' doesn't map to a Date", e);
1276             }
1277         }
1278     }
1279 
1280     /***
1281      * Get a list of Dates associated with the given configuration key.
1282      * If the property is a list of Strings, they will be parsed with the
1283      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1284      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1285      * If the key doesn't map to an existing object an empty list is returned.
1286      *
1287      * @param key The configuration key.
1288      * @return The associated Date list if the key is found.
1289      *
1290      * @throws ConversionException is thrown if the key maps to an
1291      *         object that is not a list of Dates.
1292      */
1293     public List getDateList(String key)
1294     {
1295         return getDateList(key, new ArrayList());
1296     }
1297 
1298     /***
1299      * Get a list of Dates associated with the given configuration key.
1300      * If the property is a list of Strings, they will be parsed with the
1301      * specified format pattern. If the key doesn't map to an existing object
1302      * an empty list is returned.
1303      *
1304      * @param key    The configuration key.
1305      * @param format The non-localized {@link java.text.DateFormat} pattern.
1306      * @return The associated Date list if the key is found.
1307      *
1308      * @throws ConversionException is thrown if the key maps to an
1309      *         object that is not a list of Dates.
1310      */
1311     public List getDateList(String key, String format)
1312     {
1313         return getDateList(key, new ArrayList(), format);
1314     }
1315 
1316     /***
1317      * Get a list of Dates associated with the given configuration key.
1318      * If the property is a list of Strings, they will be parsed with the
1319      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1320      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1321      * If the key doesn't map to an existing object, the default value is
1322      * returned.
1323      *
1324      * @param key          The configuration key.
1325      * @param defaultValue The default value.
1326      * @return The associated Date list if the key is found.
1327      *
1328      * @throws ConversionException is thrown if the key maps to an
1329      *         object that is not a list of Dates.
1330      */
1331     public List getDateList(String key, List defaultValue)
1332     {
1333         return getDateList(key, defaultValue, getDefaultDateFormat());
1334     }
1335 
1336     /***
1337      * Get a list of Dates associated with the given configuration key.
1338      * If the property is a list of Strings, they will be parsed with the
1339      * specified format pattern. If the key doesn't map to an existing object,
1340      * the default value is returned.
1341      *
1342      * @param key          The configuration key.
1343      * @param defaultValue The default value.
1344      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1345      * @return The associated Date list if the key is found.
1346      *
1347      * @throws ConversionException is thrown if the key maps to an
1348      *         object that is not a list of Dates.
1349      */
1350     public List getDateList(String key, List defaultValue, String format)
1351     {
1352         Object value = getProperty(key);
1353 
1354         List list;
1355 
1356         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1357         {
1358             list = defaultValue;
1359         }
1360         else if (value.getClass().isArray())
1361         {
1362             list = new ArrayList();
1363             int length = Array.getLength(value);
1364             for (int i = 0; i < length; i++)
1365             {
1366                 list.add(PropertyConverter.toDate(interpolate(Array.get(value, i)), format));
1367             }
1368         }
1369         else if (value instanceof Collection)
1370         {
1371             Collection values = (Collection) value;
1372             list = new ArrayList();
1373 
1374             Iterator it = values.iterator();
1375             while (it.hasNext())
1376             {
1377                 list.add(PropertyConverter.toDate(interpolate(it.next()), format));
1378             }
1379         }
1380         else
1381         {
1382             try
1383             {
1384                 // attempt to convert a single value
1385                 list = new ArrayList();
1386                 list.add(PropertyConverter.toDate(interpolate(value), format));
1387             }
1388             catch (ConversionException e)
1389             {
1390                 throw new ConversionException('\'' + key + "' doesn't map to a list of Dates", e);
1391             }
1392         }
1393 
1394         return list;
1395     }
1396 
1397     /***
1398      * Get an array of Dates associated with the given configuration key.
1399      * If the property is a list of Strings, they will be parsed with the
1400      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1401      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1402      * If the key doesn't map to an existing object an empty array is returned.
1403      *
1404      * @param key The configuration key.
1405      * @return The associated Date array if the key is found.
1406      *
1407      * @throws ConversionException is thrown if the key maps to an
1408      *         object that is not a list of Dates.
1409      */
1410     public Date[] getDateArray(String key)
1411     {
1412         return getDateArray(key, new Date[0]);
1413     }
1414 
1415     /***
1416      * Get an array of Dates associated with the given configuration key.
1417      * If the property is a list of Strings, they will be parsed with the
1418      * specified format pattern. If the key doesn't map to an existing object
1419      * an empty array is returned.
1420      *
1421      * @param key    The configuration key.
1422      * @param format The non-localized {@link java.text.DateFormat} pattern.
1423      * @return The associated Date array if the key is found.
1424      *
1425      * @throws ConversionException is thrown if the key maps to an
1426      *         object that is not a list of Dates.
1427      */
1428     public Date[] getDateArray(String key, String format)
1429     {
1430         return getDateArray(key, new Date[0], format);
1431     }
1432 
1433     /***
1434      * Get an array of Dates associated with the given configuration key.
1435      * If the property is a list of Strings, they will be parsed with the
1436      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1437      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1438      * If the key doesn't map to an existing object an empty array is returned.
1439      *
1440      * @param key The configuration key.
1441      * @param defaultValue the default value, which will be returned if the property is not found
1442      * @return The associated Date array if the key is found.
1443      *
1444      * @throws ConversionException is thrown if the key maps to an
1445      *         object that is not a list of Dates.
1446      */
1447     public Date[] getDateArray(String key, Date[] defaultValue)
1448     {
1449         return getDateArray(key, defaultValue, getDefaultDateFormat());
1450     }
1451 
1452     /***
1453      * Get an array of Dates associated with the given configuration key.
1454      * If the property is a list of Strings, they will be parsed with the
1455      * specified format pattern. If the key doesn't map to an existing object,
1456      * the default value is returned.
1457      *
1458      * @param key          The configuration key.
1459      * @param defaultValue The default value.
1460      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1461      * @return The associated Date array if the key is found.
1462      *
1463      * @throws ConversionException is thrown if the key maps to an
1464      *         object that is not a list of Dates.
1465      */
1466     public Date[] getDateArray(String key, Date[] defaultValue, String format)
1467     {
1468         List list = getDateList(key, format);
1469         if (list.isEmpty())
1470         {
1471             return defaultValue;
1472         }
1473         else
1474         {
1475             return (Date[]) list.toArray(new Date[list.size()]);
1476         }
1477     }
1478 
1479     /***
1480      * Get a Calendar associated with the given configuration key. If the
1481      * property is a String, it will be parsed with the format defined by the
1482      * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
1483      * with the {@link #DEFAULT_DATE_FORMAT} pattern.
1484      *
1485      * @param key The configuration key.
1486      * @return The associated Calendar.
1487      *
1488      * @throws ConversionException is thrown if the key maps to an
1489      *         object that is not a Calendar.
1490      */
1491     public Calendar getCalendar(String key)
1492     {
1493         return (Calendar) get(Calendar.class, key);
1494     }
1495 
1496     /***
1497      * Get a Calendar associated with the given configuration key. If the
1498      * property is a String, it will be parsed with the specified format
1499      * pattern.
1500      *
1501      * @param key    The configuration key.
1502      * @param format The non-localized {@link java.text.DateFormat} pattern.
1503      * @return The associated Calendar
1504      *
1505      * @throws ConversionException is thrown if the key maps to an
1506      *         object that is not a Calendar.
1507      */
1508     public Calendar getCalendar(String key, String format)
1509     {
1510         Calendar value = getCalendar(key, null, format);
1511         if (value != null)
1512         {
1513             return value;
1514         }
1515         else if (isThrowExceptionOnMissing())
1516         {
1517             throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
1518         }
1519         else
1520         {
1521             return null;
1522         }
1523     }
1524 
1525     /***
1526      * Get a Calendar associated with the given configuration key. If the
1527      * property is a String, it will be parsed with the format defined by the
1528      * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
1529      * with the {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map
1530      * to an existing object, the default value is returned.
1531      *
1532      * @param key          The configuration key.
1533      * @param defaultValue The default value.
1534      * @return The associated Calendar.
1535      *
1536      * @throws ConversionException is thrown if the key maps to an
1537      *         object that is not a Calendar.
1538      */
1539     public Calendar getCalendar(String key, Calendar defaultValue)
1540     {
1541         return getCalendar(key, defaultValue, getDefaultDateFormat());
1542     }
1543 
1544     /***
1545      * Get a Calendar associated with the given configuration key. If the
1546      * property is a String, it will be parsed with the specified format
1547      * pattern. If the key doesn't map to an existing object, the default
1548      * value is returned.
1549      *
1550      * @param key          The configuration key.
1551      * @param defaultValue The default value.
1552      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1553      * @return The associated Calendar.
1554      *
1555      * @throws ConversionException is thrown if the key maps to an
1556      *         object that is not a Calendar.
1557      */
1558     public Calendar getCalendar(String key, Calendar defaultValue, String format)
1559     {
1560         Object value = resolveContainerStore(key);
1561 
1562         if (value == null)
1563         {
1564             return defaultValue;
1565         }
1566         else
1567         {
1568             try
1569             {
1570                 return PropertyConverter.toCalendar(interpolate(value), format);
1571             }
1572             catch (ConversionException e)
1573             {
1574                 throw new ConversionException('\'' + key + "' doesn't map to a Calendar", e);
1575             }
1576         }
1577     }
1578 
1579     /***
1580      * Get a list of Calendars associated with the given configuration key.
1581      * If the property is a list of Strings, they will be parsed with the
1582      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1583      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1584      * If the key doesn't map to an existing object an empty list is returned.
1585      *
1586      * @param key The configuration key.
1587      * @return The associated Calendar list if the key is found.
1588      *
1589      * @throws ConversionException is thrown if the key maps to an
1590      *         object that is not a list of Calendars.
1591      */
1592     public List getCalendarList(String key)
1593     {
1594         return getCalendarList(key, new ArrayList());
1595     }
1596 
1597     /***
1598      * Get a list of Calendars associated with the given configuration key.
1599      * If the property is a list of Strings, they will be parsed with the
1600      * specified format pattern. If the key doesn't map to an existing object
1601      * an empty list is returned.
1602      *
1603      * @param key    The configuration key.
1604      * @param format The non-localized {@link java.text.DateFormat} pattern.
1605      * @return The associated Calendar list if the key is found.
1606      *
1607      * @throws ConversionException is thrown if the key maps to an
1608      *         object that is not a list of Calendars.
1609      */
1610     public List getCalendarList(String key, String format)
1611     {
1612         return getCalendarList(key, new ArrayList(), format);
1613     }
1614 
1615     /***
1616      * Get a list of Calendars associated with the given configuration key.
1617      * If the property is a list of Strings, they will be parsed with the
1618      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1619      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1620      * If the key doesn't map to an existing object, the default value is
1621      * returned.
1622      *
1623      * @param key The configuration key.
1624      * @param defaultValue The default value.
1625      * @return The associated Calendar list if the key is found.
1626      *
1627      * @throws ConversionException is thrown if the key maps to an
1628      *         object that is not a list of Calendars.
1629      */
1630     public List getCalendarList(String key, List defaultValue)
1631     {
1632         return getCalendarList(key, defaultValue, getDefaultDateFormat());
1633     }
1634 
1635     /***
1636      * Get a list of Calendars associated with the given configuration key.
1637      * If the property is a list of Strings, they will be parsed with the
1638      * specified format pattern. If the key doesn't map to an existing object,
1639      * the default value is returned.
1640      *
1641      * @param key          The configuration key.
1642      * @param defaultValue The default value.
1643      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1644      * @return The associated Calendar list if the key is found.
1645      *
1646      * @throws ConversionException is thrown if the key maps to an
1647      *         object that is not a list of Calendars.
1648      */
1649     public List getCalendarList(String key, List defaultValue, String format)
1650     {
1651         Object value = getProperty(key);
1652 
1653         List list;
1654 
1655         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1656         {
1657             list = defaultValue;
1658         }
1659         else if (value.getClass().isArray())
1660         {
1661             list = new ArrayList();
1662             int length = Array.getLength(value);
1663             for (int i = 0; i < length; i++)
1664             {
1665                 list.add(PropertyConverter.toCalendar(interpolate(Array.get(value, i)), format));
1666             }
1667         }
1668         else if (value instanceof Collection)
1669         {
1670             Collection values = (Collection) value;
1671             list = new ArrayList();
1672 
1673             Iterator it = values.iterator();
1674             while (it.hasNext())
1675             {
1676                 list.add(PropertyConverter.toCalendar(interpolate(it.next()), format));
1677             }
1678         }
1679         else
1680         {
1681             try
1682             {
1683                 // attempt to convert a single value
1684                 list = new ArrayList();
1685                 list.add(PropertyConverter.toCalendar(interpolate(value), format));
1686             }
1687             catch (ConversionException e)
1688             {
1689                 throw new ConversionException('\'' + key + "' doesn't map to a list of Calendars", e);
1690             }
1691         }
1692 
1693         return list;
1694     }
1695 
1696     /***
1697      * Get an array of Calendars associated with the given configuration key.
1698      * If the property is a list of Strings, they will be parsed with the
1699      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1700      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1701      * If the key doesn't map to an existing object an empty array is returned.
1702      *
1703      * @param key The configuration key.
1704      * @return The associated Calendar array if the key is found.
1705      *
1706      * @throws ConversionException is thrown if the key maps to an
1707      *         object that is not a list of Calendars.
1708      */
1709     public Calendar[] getCalendarArray(String key)
1710     {
1711         return getCalendarArray(key, new Calendar[0]);
1712     }
1713 
1714     /***
1715      * Get an array of Calendars associated with the given configuration key.
1716      * If the property is a list of Strings, they will be parsed with the
1717      * specified format pattern. If the key doesn't map to an existing object
1718      * an empty array is returned.
1719      *
1720      * @param key    The configuration key.
1721      * @param format The non-localized {@link java.text.DateFormat} pattern.
1722      * @return The associated Calendar array if the key is found.
1723      *
1724      * @throws ConversionException is thrown if the key maps to an
1725      *         object that is not a list of Calendars.
1726      */
1727     public Calendar[] getCalendarArray(String key, String format)
1728     {
1729         return getCalendarArray(key, new Calendar[0], format);
1730     }
1731 
1732     /***
1733      * Get an array of Calendars associated with the given configuration key.
1734      * If the property is a list of Strings, they will be parsed with the
1735      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1736      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1737      * If the key doesn't map to an existing object an empty array is returned.
1738      *
1739      * @param key The configuration key.
1740      * @param defaultValue the default value, which will be returned if the property is not found
1741      * @return The associated Calendar array if the key is found.
1742      *
1743      * @throws ConversionException is thrown if the key maps to an
1744      *         object that is not a list of Calendars.
1745      */
1746     public Calendar[] getCalendarArray(String key, Calendar[] defaultValue)
1747     {
1748         return getCalendarArray(key, defaultValue, getDefaultDateFormat());
1749     }
1750 
1751     /***
1752      * Get an array of Calendars associated with the given configuration key.
1753      * If the property is a list of Strings, they will be parsed with the
1754      * specified format pattern. If the key doesn't map to an existing object,
1755      * the default value is returned.
1756      *
1757      * @param key          The configuration key.
1758      * @param defaultValue The default value.
1759      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1760      * @return The associated Calendar array if the key is found.
1761      *
1762      * @throws ConversionException is thrown if the key maps to an
1763      *         object that is not a list of Calendars.
1764      */
1765     public Calendar[] getCalendarArray(String key, Calendar[] defaultValue, String format)
1766     {
1767         List list = getCalendarList(key, format);
1768         if (list.isEmpty())
1769         {
1770             return defaultValue;
1771         }
1772         else
1773         {
1774             return (Calendar[]) list.toArray(new Calendar[list.size()]);
1775         }
1776     }
1777 
1778     /***
1779      * Returns the date format specified by the user in the DATE_FORMAT_KEY
1780      * property, or the default format otherwise.
1781      *
1782      * @return the default date format
1783      */
1784     private String getDefaultDateFormat()
1785     {
1786         return getString(DATE_FORMAT_KEY, DEFAULT_DATE_FORMAT);
1787     }
1788 
1789     /***
1790      * Get a Locale associated with the given configuration key.
1791      *
1792      * @param key The configuration key.
1793      * @return The associated Locale.
1794      *
1795      * @throws ConversionException is thrown if the key maps to an
1796      *         object that is not a Locale.
1797      */
1798     public Locale getLocale(String key)
1799     {
1800         return (Locale) get(Locale.class, key);
1801     }
1802 
1803     /***
1804      * Get a Locale associated with the given configuration key.
1805      * If the key doesn't map to an existing object, the default value
1806      * is returned.
1807      *
1808      * @param key          The configuration key.
1809      * @param defaultValue The default value.
1810      * @return The associated Locale.
1811      *
1812      * @throws ConversionException is thrown if the key maps to an
1813      *         object that is not a Locale.
1814      */
1815     public Locale getLocale(String key, Locale defaultValue)
1816     {
1817         return (Locale) get(Locale.class, key, defaultValue);
1818     }
1819 
1820     /***
1821      * Get a list of Locales associated with the given configuration key.
1822      * If the key doesn't map to an existing object an empty list is returned.
1823      *
1824      * @param key The configuration key.
1825      * @return The associated Locale list if the key is found.
1826      *
1827      * @throws ConversionException is thrown if the key maps to an
1828      *         object that is not a list of Locales.
1829      */
1830     public List getLocaleList(String key)
1831     {
1832         return getLocaleList(key, new ArrayList());
1833     }
1834 
1835     /***
1836      * Get a list of Locales associated with the given configuration key.
1837      * If the key doesn't map to an existing object, the default value is
1838      * returned.
1839      *
1840      * @param key The configuration key.
1841      * @param defaultValue The default value.
1842      * @return The associated List of Locales.
1843      *
1844      * @throws ConversionException is thrown if the key maps to an
1845      *         object that is not a list of Locales.
1846      */
1847     public List getLocaleList(String key, List defaultValue)
1848     {
1849         return getList(Locale.class, key, defaultValue);
1850     }
1851 
1852     /***
1853      * Get an array of Locales associated with the given
1854      * configuration key. If the key doesn't map to an existing object
1855      * an empty array is returned.
1856      *
1857      * @param key The configuration key.
1858      * @return The associated Locale array if the key is found.
1859      *
1860      * @throws ConversionException is thrown if the key maps to an
1861      *         object that is not a list of Locales.
1862      */
1863     public Locale[] getLocaleArray(String key)
1864     {
1865         return getLocaleArray(key, new Locale[0]);
1866     }
1867 
1868     /***
1869      * Get an array of Locales associated with the given
1870      * configuration key. If the key doesn't map to an existing object
1871      * an empty array is returned.
1872      *
1873      * @param key The configuration key.
1874      * @param defaultValue the default value, which will be returned if the property is not found
1875      * @return The associated Locale array if the key is found.
1876      *
1877      * @throws ConversionException is thrown if the key maps to an
1878      *         object that is not a list of Locales.
1879      */
1880     public Locale[] getLocaleArray(String key, Locale[] defaultValue)
1881     {
1882         return (Locale[]) getArray(Locale.class, key, defaultValue);
1883     }
1884 
1885     /***
1886      * Get a Color associated with the given configuration key.
1887      *
1888      * @param key The configuration key.
1889      * @return The associated Color.
1890      *
1891      * @throws ConversionException is thrown if the key maps to an
1892      *         object that is not a Color.
1893      */
1894     public Color getColor(String key)
1895     {
1896         return (Color) get(Color.class, key);
1897     }
1898 
1899     /***
1900      * Get a Color associated with the given configuration key.
1901      * If the key doesn't map to an existing object, the default value
1902      * is returned.
1903      *
1904      * @param key          The configuration key.
1905      * @param defaultValue The default value.
1906      * @return The associated Color.
1907      *
1908      * @throws ConversionException is thrown if the key maps to an
1909      *         object that is not a Color.
1910      */
1911     public Color getColor(String key, Color defaultValue)
1912     {
1913         return (Color) get(Color.class, key, defaultValue);
1914     }
1915 
1916     /***
1917      * Get a list of Colors associated with the given configuration key.
1918      * If the key doesn't map to an existing object an empty list is returned.
1919      *
1920      * @param key The configuration key.
1921      * @return The associated Color list if the key is found.
1922      *
1923      * @throws ConversionException is thrown if the key maps to an
1924      *         object that is not a list of Colors.
1925      */
1926     public List getColorList(String key)
1927     {
1928         return getColorList(key, new ArrayList());
1929     }
1930 
1931     /***
1932      * Get a list of Colors associated with the given configuration key.
1933      * If the key doesn't map to an existing object, the default value is
1934      * returned.
1935      *
1936      * @param key The configuration key.
1937      * @param defaultValue The default value.
1938      * @return The associated List of Colors.
1939      *
1940      * @throws ConversionException is thrown if the key maps to an
1941      *         object that is not a list of Colors.
1942      */
1943     public List getColorList(String key, List defaultValue)
1944     {
1945         return getList(Color.class, key, defaultValue);
1946     }
1947 
1948     /***
1949      * Get an array of Colors associated with the given
1950      * configuration key. If the key doesn't map to an existing object
1951      * an empty array is returned.
1952      *
1953      * @param key The configuration key.
1954      * @return The associated Color array if the key is found.
1955      *
1956      * @throws ConversionException is thrown if the key maps to an
1957      *         object that is not a list of Colors.
1958      */
1959     public Color[] getColorArray(String key)
1960     {
1961         return getColorArray(key, new Color[0]);
1962     }
1963 
1964     /***
1965      * Get an array of Colors associated with the given
1966      * configuration key. If the key doesn't map to an existing object
1967      * an empty array is returned.
1968      *
1969      * @param key The configuration key.
1970      * @param defaultValue the default value, which will be returned if the property is not found
1971      * @return The associated Color array if the key is found.
1972      *
1973      * @throws ConversionException is thrown if the key maps to an
1974      *         object that is not a list of Colors.
1975      */
1976     public Color[] getColorArray(String key, Color[] defaultValue)
1977     {
1978         return (Color[]) getArray(Color.class, key, defaultValue);
1979     }
1980 
1981 }