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