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 }