    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.configuration2;
    019
    020import java.awt.Color;
    021import java.math.BigDecimal;
    022import java.math.BigInteger;
    023import java.net.URI;
    024import java.net.URL;
    025import java.util.ArrayList;
    026import java.util.Calendar;
    027import java.util.Date;
    028import java.util.Iterator;
    029import java.util.List;
    030import java.util.Locale;
    031import java.util.NoSuchElementException;
    032
    033import org.apache.commons.configuration2.convert.ConversionHandler;
    034import org.apache.commons.configuration2.convert.DefaultConversionHandler;
    035import org.apache.commons.configuration2.ex.ConversionException;
    036import org.apache.commons.lang3.StringUtils;
    037
    038/**
    039 * Decorator providing additional getters for any Configuration. This extended
    040 * Configuration supports more types:
    041 * <ul>
    042 *   <li>{@link java.net.URL}</li>
    043 *   <li>{@link java.util.Locale}</li>
    044 *   <li>{@link java.util.Date}</li>
    045 *   <li>{@link java.util.Calendar}</li>
    046 *   <li>{@link java.awt.Color}</li>
    047 *   <li>{@link java.net.InetAddress}</li>
    048 *   <li>{@code javax.mail.internet.InternetAddress} (requires Javamail in the classpath)</li>
    049 *   <li>{@link java.lang.Enum} (Java 5 enumeration types)</li>
    050 * </ul>
    051 *
    052 * Lists and arrays are available for all types.<br>
    053 * Note that this class is only a thin wrapper over functionality already
    054 * provided by {@link AbstractConfiguration}. Basically, the generic
    055 * {@code get()}, and {@code getCollection()} methods are
    056 * used to actually perform data conversions.
    057 *
    058 * <p><strong>Example</strong></p>
    059 *
    060 * Configuration file {@code config.properties}:
    061 * <pre>
    062 * title.color = #0000FF
    063 * remote.host = 192.168.0.53
    064 * default.locales = fr,en,de
    065 * email.contact = ebourg@apache.org, tester@test.org
    066 * </pre>
    067 *
    068 * Usage:
    069 *
    070 * <pre>
    071 * DataConfiguration config = new DataConfiguration(new PropertiesConfiguration("config.properties"));
    072 *
    073 * // retrieve a property using a specialized getter
    074 * Color color = config.getColor("title.color");
    075 *
    076 * // retrieve a property using a generic getter
    077 * InetAddress host = (InetAddress) config.get(InetAddress.class, "remote.host");
    078 * Locale[] locales = (Locale[]) config.getArray(Locale.class, "default.locales");
    079 * List contacts = config.getList(InternetAddress.class, "email.contact");
    080 * </pre>
    081 *
    082 * <p><strong>Dates</strong></p>
    083 *
    084 * Date objects are expected to be formatted with the pattern {@code yyyy-MM-dd HH:mm:ss}.
    085 * This default format can be changed by specifying another format in the
    086 * getters, or by putting a date format in the configuration under the key
    087 * {@code org.apache.commons.configuration.format.date}. Alternatively, the
    088 * date format can also be specified via the {@code ConversionHandler} used
    089 * by a configuration instance:
    090 *
    091 * <pre>
    092 * DefaultConversionHandler handler = new DefaultConversionHandler();
    093 * handler.setDateFormat("mm/dd/yyyy");
    094 * config.setConversionHandler(handler);
    095 * </pre>
    096 *
    097 * @since 1.1
    098 */
    099public class DataConfiguration extends AbstractConfiguration
    100{
    101    /** The key of the property storing the user defined date format. */
    102    public static final String DATE_FORMAT_KEY = "org.apache.commons.configuration.format.date";
    103
    104    /** The default format for dates. */
    105    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    106
    107    /** Stores temporary date formats. */
    108    private static final ThreadLocal<String> TEMP_DATE_FORMAT = new ThreadLocal<>();
    109
    110    /** Stores the wrapped configuration.*/
    111    private final Configuration configuration;
    112
    113    /** A special conversion handler object used by this configuration. */
    114    private final ConversionHandler dataConversionHandler;
    115
    116    /**
    117     * Creates a new instance of {@code DataConfiguration} and sets the
    118     * wrapped configuration.
    119     *
    120     * @param configuration the wrapped configuration
    121     */
    122    public DataConfiguration(final Configuration configuration)
    123    {
    124        this.configuration = configuration;
    125        dataConversionHandler = new DataConversionHandler();
    126    }
    127
    128    /**
    129     * Return the configuration decorated by this DataConfiguration.
    130     *
    131     * @return the wrapped configuration
    132     */
    133    public Configuration getConfiguration()
    134    {
    135        return configuration;
    136    }
    137
    138    /**
    139     * {@inheritDoc} This implementation returns the special conversion handler
    140     * used by this configuration instance.
    141     */
    142    @Override
    143    public ConversionHandler getConversionHandler()
    144    {
    145        return dataConversionHandler;
    146    }
    147
    148    @Override
    149    protected Object getPropertyInternal(final String key)
    150    {
    151        return configuration.getProperty(key);
    152    }
    153
    154    @Override
    155    protected void addPropertyInternal(final String key, final Object obj)
    156    {
    157        configuration.addProperty(key, obj);
    158    }
    159
    160    @Override
    161    protected void addPropertyDirect(final String key, final Object value)
    162    {
    163        if (configuration instanceof AbstractConfiguration)
    164        {
    165            ((AbstractConfiguration) configuration).addPropertyDirect(key, value);
    166        }
    167        else
    168        {
    169            configuration.addProperty(key, value);
    170        }
    171    }
    172
    173    @Override
    174    protected boolean isEmptyInternal()
    175    {
    176        return configuration.isEmpty();
    177    }
    178
    179    @Override
    180    protected boolean containsKeyInternal(final String key)
    181    {
    182        return configuration.containsKey(key);
    183    }
    184
    185    @Override
    186    protected void clearPropertyDirect(final String key)
    187    {
    188        configuration.clearProperty(key);
    189    }
    190
    191    @Override
    192    protected void setPropertyInternal(final String key, final Object value)
    193    {
    194        configuration.setProperty(key, value);
    195    }
    196
    197    @Override
    198    protected Iterator<String> getKeysInternal()
    199    {
    200        return configuration.getKeys();
    201    }
    202
    203    /**
    204     * Get a list of Boolean objects associated with the given
    205     * configuration key. If the key doesn't map to an existing object
    206     * an empty list is returned.
    207     *
    208     * @param key The configuration key.
    209     * @return The associated Boolean list if the key is found.
    210     *
    211     * @throws ConversionException is thrown if the key maps to an
    212     *         object that is not a list of booleans.
    213     */
    214    public List<Boolean> getBooleanList(final String key)
    215    {
    216        return getBooleanList(key, new ArrayList<Boolean>());
    217    }
    218
    219    /**
    220     * Get a list of Boolean objects associated with the given
    221     * configuration key. If the key doesn't map to an existing object,
    222     * the default value is returned.
    223     *
    224     * @param key The configuration key.
    225     * @param defaultValue The default value.
    226     * @return The associated List of Booleans.
    227     *
    228     * @throws ConversionException is thrown if the key maps to an
    229     *         object that is not a list of booleans.
    230     */
    231    public List<Boolean> getBooleanList(final String key, final List<Boolean> defaultValue)
    232    {
    233         return getList(Boolean.class, key, defaultValue);
    234    }
    235
    236    /**
    237     * Get an array of boolean primitives associated with the given
    238     * configuration key. If the key doesn't map to an existing object
    239     * an empty array is returned.
    240     *
    241     * @param key The configuration key.
    242     * @return The associated boolean array if the key is found.
    243     *
    244     * @throws ConversionException is thrown if the key maps to an
    245     *         object that is not a list of booleans.
    246     */
    247    public boolean[] getBooleanArray(final String key)
    248    {
    249        return (boolean[]) getArray(Boolean.TYPE, key);
    250    }
    251
    252    /**
    253     * Get an array of boolean primitives associated with the given
    254     * configuration key. If the key doesn't map to an existing object,
    255     * the default value is returned.
    256     *
    257     * @param key          The configuration key.
    258     * @param defaultValue The default value.
    259     * @return The associated boolean array if the key is found.
    260     *
    261     * @throws ConversionException is thrown if the key maps to an
    262     *         object that is not a list of booleans.
    263     */
    264    public boolean[] getBooleanArray(final String key, final boolean[] defaultValue)
    265    {
    266        return get(boolean[].class, key, defaultValue);
    267    }
    268
    269    /**
    270     * Get a list of Byte objects associated with the given configuration key.
    271     * If the key doesn't map to an existing object an empty list is returned.
    272     *
    273     * @param key The configuration key.
    274     * @return The associated Byte list if the key is found.
    275     *
    276     * @throws ConversionException is thrown if the key maps to an
    277     *         object that is not a list of bytes.
    278     */
    279    public List<Byte> getByteList(final String key)
    280    {
    281        return getByteList(key, new ArrayList<Byte>());
    282    }
    283
    284    /**
    285     * Get a list of Byte objects associated with the given configuration key.
    286     * If the key doesn't map to an existing object, the default value is
    287     * returned.
    288     *
    289     * @param key The configuration key.
    290     * @param defaultValue The default value.
    291     * @return The associated List of Bytes.
    292     *
    293     * @throws ConversionException is thrown if the key maps to an
    294     *         object that is not a list of bytes.
    295     */
    296    public List<Byte> getByteList(final String key, final List<Byte> defaultValue)
    297    {
    298        return getList(Byte.class, key, defaultValue);
    299    }
    300
    301    /**
    302     * Get an array of byte primitives associated with the given
    303     * configuration key. If the key doesn't map to an existing object
    304     * an empty array is returned.
    305     *
    306     * @param key The configuration key.
    307     * @return The associated byte array if the key is found.
    308     *
    309     * @throws ConversionException is thrown if the key maps to an
    310     *         object that is not a list of bytes.
    311     */
    312    public byte[] getByteArray(final String key)
    313    {
    314        return getByteArray(key, new byte[0]);
    315    }
    316
    317    /**
    318     * Get an array of byte primitives associated with the given
    319     * configuration key. If the key doesn't map to an existing object
    320     * an empty array is returned.
    321     *
    322     * @param key The configuration key.
    323     * @param defaultValue the default value, which will be returned if the property is not found
    324     * @return The associated byte array if the key is found.
    325     *
    326     * @throws ConversionException is thrown if the key maps to an
    327     *         object that is not a list of bytes.
    328     */
    329    public byte[] getByteArray(final String key, final byte[] defaultValue)
    330    {
    331        return get(byte[].class, key, defaultValue);
    332    }
    333
    334    /**
    335     * Get a list of Short objects associated with the given configuration key.
    336     * If the key doesn't map to an existing object an empty list is returned.
    337     *
    338     * @param key The configuration key.
    339     * @return The associated Short list if the key is found.
    340     *
    341     * @throws ConversionException is thrown if the key maps to an
    342     *         object that is not a list of shorts.
    343     */
    344    public List<Short> getShortList(final String key)
    345    {
    346        return getShortList(key, new ArrayList<Short>());
    347    }
    348
    349    /**
    350     * Get a list of Short objects associated with the given configuration key.
    351     * If the key doesn't map to an existing object, the default value is
    352     * returned.
    353     *
    354     * @param key The configuration key.
    355     * @param defaultValue The default value.
    356     * @return The associated List of Shorts.
    357     *
    358     * @throws ConversionException is thrown if the key maps to an
    359     *         object that is not a list of shorts.
    360     */
    361    public List<Short> getShortList(final String key, final List<Short> defaultValue)
    362    {
    363        return getList(Short.class, key, defaultValue);
    364    }
    365
    366    /**
    367     * Get an array of short primitives associated with the given
    368     * configuration key. If the key doesn't map to an existing object
    369     * an empty array is returned.
    370     *
    371     * @param key The configuration key.
    372     * @return The associated short array if the key is found.
    373     *
    374     * @throws ConversionException is thrown if the key maps to an
    375     *         object that is not a list of shorts.
    376     */
    377    public short[] getShortArray(final String key)
    378    {
    379        return getShortArray(key, new short[0]);
    380    }
    381
    382    /**
    383     * Get an array of short primitives associated with the given
    384     * configuration key. If the key doesn't map to an existing object
    385     * an empty array is returned.
    386     *
    387     * @param key The configuration key.
    388     * @param defaultValue the default value, which will be returned if the property is not found
    389     * @return The associated short array if the key is found.
    390     *
    391     * @throws ConversionException is thrown if the key maps to an
    392     *         object that is not a list of shorts.
    393     */
    394    public short[] getShortArray(final String key, final short[] defaultValue)
    395    {
    396        return get(short[].class, key, defaultValue);
    397    }
    398
    399    /**
    400     * Get a list of Integer objects associated with the given
    401     * configuration key. If the key doesn't map to an existing object
    402     * an empty list is returned.
    403     *
    404     * @param key The configuration key.
    405     * @return The associated Integer list if the key is found.
    406     *
    407     * @throws ConversionException is thrown if the key maps to an
    408     *         object that is not a list of integers.
    409     */
    410    public List<Integer> getIntegerList(final String key)
    411    {
    412        return getIntegerList(key, new ArrayList<Integer>());
    413    }
    414
    415    /**
    416     * Get a list of Integer objects associated with the given
    417     * configuration key. If the key doesn't map to an existing object,
    418     * the default value is returned.
    419     *
    420     * @param key The configuration key.
    421     * @param defaultValue The default value.
    422     * @return The associated List of Integers.
    423     *
    424     * @throws ConversionException is thrown if the key maps to an
    425     *         object that is not a list of integers.
    426     */
    427    public List<Integer> getIntegerList(final String key, final List<Integer> defaultValue)
    428    {
    429        return getList(Integer.class, key, defaultValue);
    430    }
    431
    432    /**
    433     * Get an array of int primitives associated with the given
    434     * configuration key. If the key doesn't map to an existing object
    435     * an empty array is returned.
    436     *
    437     * @param key The configuration key.
    438     * @return The associated int array if the key is found.
    439     *
    440     * @throws ConversionException is thrown if the key maps to an
    441     *         object that is not a list of integers.
    442     */
    443    public int[] getIntArray(final String key)
    444    {
    445        return getIntArray(key, new int[0]);
    446    }
    447
    448    /**
    449     * Get an array of int primitives associated with the given
    450     * configuration key. If the key doesn't map to an existing object
    451     * an empty array is returned.
    452     *
    453     * @param key The configuration key.
    454     * @param defaultValue the default value, which will be returned if the property is not found
    455     * @return The associated int array if the key is found.
    456     *
    457     * @throws ConversionException is thrown if the key maps to an
    458     *         object that is not a list of integers.
    459     */
    460    public int[] getIntArray(final String key, final int[] defaultValue)
    461    {
    462        return get(int[].class, key, defaultValue);
    463    }
    464
    465    /**
    466     * Get a list of Long objects associated with the given configuration key.
    467     * If the key doesn't map to an existing object an empty list is returned.
    468     *
    469     * @param key The configuration key.
    470     * @return The associated Long list if the key is found.
    471     *
    472     * @throws ConversionException is thrown if the key maps to an
    473     *         object that is not a list of longs.
    474     */
    475    public List<Long> getLongList(final String key)
    476    {
    477        return getLongList(key, new ArrayList<Long>());
    478    }
    479
    480    /**
    481     * Get a list of Long objects associated with the given configuration key.
    482     * If the key doesn't map to an existing object, the default value is
    483     * returned.
    484     *
    485     * @param key The configuration key.
    486     * @param defaultValue The default value.
    487     * @return The associated List of Longs.
    488     *
    489     * @throws ConversionException is thrown if the key maps to an
    490     *         object that is not a list of longs.
    491     */
    492    public List<Long> getLongList(final String key, final List<Long> defaultValue)
    493    {
    494        return getList(Long.class, key, defaultValue);
    495    }
    496
    497    /**
    498     * Get an array of long primitives associated with the given
    499     * configuration key. If the key doesn't map to an existing object
    500     * an empty array is returned.
    501     *
    502     * @param key The configuration key.
    503     * @return The associated long array if the key is found.
    504     *
    505     * @throws ConversionException is thrown if the key maps to an
    506     *         object that is not a list of longs.
    507     */
    508    public long[] getLongArray(final String key)
    509    {
    510        return getLongArray(key, new long[0]);
    511    }
    512
    513    /**
    514     * Get an array of long primitives associated with the given
    515     * configuration key. If the key doesn't map to an existing object
    516     * an empty array is returned.
    517     *
    518     * @param key The configuration key.
    519     * @param defaultValue the default value, which will be returned if the property is not found
    520     * @return The associated long array if the key is found.
    521     *
    522     * @throws ConversionException is thrown if the key maps to an
    523     *         object that is not a list of longs.
    524     */
    525    public long[] getLongArray(final String key, final long[] defaultValue)
    526    {
    527        return get(long[].class, key, defaultValue);
    528    }
    529
    530    /**
    531     * Get a list of Float objects associated with the given configuration key.
    532     * If the key doesn't map to an existing object an empty list is returned.
    533     *
    534     * @param key The configuration key.
    535     * @return The associated Float list if the key is found.
    536     *
    537     * @throws ConversionException is thrown if the key maps to an
    538     *         object that is not a list of floats.
    539     */
    540    public List<Float> getFloatList(final String key)
    541    {
    542        return getFloatList(key, new ArrayList<Float>());
    543    }
    544
    545    /**
    546     * Get a list of Float objects associated with the given
    547     * configuration key. If the key doesn't map to an existing object,
    548     * the default value is returned.
    549     *
    550     * @param key The configuration key.
    551     * @param defaultValue The default value.
    552     * @return The associated List of Floats.
    553     *
    554     * @throws ConversionException is thrown if the key maps to an
    555     *         object that is not a list of floats.
    556     */
    557    public List<Float> getFloatList(final String key, final List<Float> defaultValue)
    558    {
    559        return getList(Float.class, key, defaultValue);
    560    }
    561
    562    /**
    563     * Get an array of float primitives associated with the given
    564     * configuration key. If the key doesn't map to an existing object
    565     * an empty array is returned.
    566     *
    567     * @param key The configuration key.
    568     * @return The associated float array if the key is found.
    569     *
    570     * @throws ConversionException is thrown if the key maps to an
    571     *         object that is not a list of floats.
    572     */
    573    public float[] getFloatArray(final String key)
    574    {
    575        return getFloatArray(key, new float[0]);
    576    }
    577
    578    /**
    579     * Get an array of float primitives associated with the given
    580     * configuration key. If the key doesn't map to an existing object
    581     * an empty array is returned.
    582     *
    583     * @param key The configuration key.
    584     * @param defaultValue the default value, which will be returned if the property is not found
    585     * @return The associated float array if the key is found.
    586     *
    587     * @throws ConversionException is thrown if the key maps to an
    588     *         object that is not a list of floats.
    589     */
    590    public float[] getFloatArray(final String key, final float[] defaultValue)
    591    {
    592        return get(float[].class, key, defaultValue);
    593    }
    594
    595    /**
    596     * Get a list of Double objects associated with the given
    597     * configuration key. If the key doesn't map to an existing object
    598     * an empty list is returned.
    599     *
    600     * @param key The configuration key.
    601     * @return The associated Double list if the key is found.
    602     *
    603     * @throws ConversionException is thrown if the key maps to an
    604     *         object that is not a list of doubles.
    605     */
    606    public List<Double> getDoubleList(final String key)
    607    {
    608        return getDoubleList(key, new ArrayList<Double>());
    609    }
    610
    611    /**
    612     * Get a list of Double objects associated with the given
    613     * configuration key. If the key doesn't map to an existing object,
    614     * the default value is returned.
    615     *
    616     * @param key The configuration key.
    617     * @param defaultValue The default value.
    618     * @return The associated List of Doubles.
    619     *
    620     * @throws ConversionException is thrown if the key maps to an
    621     *         object that is not a list of doubles.
    622     */
    623    public List<Double> getDoubleList(final String key, final List<Double> defaultValue)
    624    {
    625        return getList(Double.class, key, defaultValue);
    626    }
    627
    628    /**
    629     * Get an array of double primitives associated with the given
    630     * configuration key. If the key doesn't map to an existing object
    631     * an empty array is returned.
    632     *
    633     * @param key The configuration key.
    634     * @return The associated double array if the key is found.
    635     *
    636     * @throws ConversionException is thrown if the key maps to an
    637     *         object that is not a list of doubles.
    638     */
    639    public double[] getDoubleArray(final String key)
    640    {
    641        return getDoubleArray(key, new double[0]);
    642    }
    643
    644    /**
    645     * Get an array of double primitives associated with the given
    646     * configuration key. If the key doesn't map to an existing object
    647     * an empty array is returned.
    648     *
    649     * @param key The configuration key.
    650     * @param defaultValue the default value, which will be returned if the property is not found
    651     * @return The associated double array if the key is found.
    652     *
    653     * @throws ConversionException is thrown if the key maps to an
    654     *         object that is not a list of doubles.
    655     */
    656    public double[] getDoubleArray(final String key, final double[] defaultValue)
    657    {
    658        return get(double[].class, key, defaultValue);
    659    }
    660
    661    /**
    662     * Get a list of BigIntegers associated with the given configuration key.
    663     * If the key doesn't map to an existing object an empty list is returned.
    664     *
    665     * @param key The configuration key.
    666     * @return The associated BigInteger list if the key is found.
    667     *
    668     * @throws ConversionException is thrown if the key maps to an
    669     *         object that is not a list of BigIntegers.
    670     */
    671    public List<BigInteger> getBigIntegerList(final String key)
    672    {
    673        return getBigIntegerList(key, new ArrayList<BigInteger>());
    674    }
    675
    676    /**
    677     * Get a list of BigIntegers associated with the given configuration key.
    678     * If the key doesn't map to an existing object, the default value is
    679     * returned.
    680     *
    681     * @param key The configuration key.
    682     * @param defaultValue The default value.
    683     * @return The associated List of BigIntegers.
    684     *
    685     * @throws ConversionException is thrown if the key maps to an
    686     *         object that is not a list of BigIntegers.
    687     */
    688    public List<BigInteger> getBigIntegerList(final String key, final List<BigInteger> defaultValue)
    689    {
    690        return getList(BigInteger.class, key, defaultValue);
    691    }
    692
    693    /**
    694     * Get an array of BigIntegers associated with the given
    695     * configuration key. If the key doesn't map to an existing object
    696     * an empty array is returned.
    697     *
    698     * @param key The configuration key.
    699     * @return The associated BigInteger array if the key is found.
    700     *
    701     * @throws ConversionException is thrown if the key maps to an
    702     *         object that is not a list of BigIntegers.
    703     */
    704    public BigInteger[] getBigIntegerArray(final String key)
    705    {
    706        return getBigIntegerArray(key, new BigInteger[0]);
    707    }
    708
    709    /**
    710     * Get an array of BigIntegers associated with the given
    711     * configuration key. If the key doesn't map to an existing object
    712     * an empty array is returned.
    713     *
    714     * @param key The configuration key.
    715     * @param defaultValue the default value, which will be returned if the property is not found
    716     * @return The associated BigInteger array if the key is found.
    717     *
    718     * @throws ConversionException is thrown if the key maps to an
    719     *         object that is not a list of BigIntegers.
    720     */
    721    public BigInteger[] getBigIntegerArray(final String key, final BigInteger[] defaultValue)
    722    {
    723        return get(BigInteger[].class, key, defaultValue);
    724    }
    725
    726    /**
    727     * Get a list of BigDecimals associated with the given configuration key.
    728     * If the key doesn't map to an existing object an empty list is returned.
    729     *
    730     * @param key The configuration key.
    731     * @return The associated BigDecimal list if the key is found.
    732     *
    733     * @throws ConversionException is thrown if the key maps to an
    734     *         object that is not a list of BigDecimals.
    735     */
    736    public List<BigDecimal> getBigDecimalList(final String key)
    737    {
    738        return getBigDecimalList(key, new ArrayList<BigDecimal>());
    739    }
    740
    741    /**
    742     * Get a list of BigDecimals associated with the given configuration key.
    743     * If the key doesn't map to an existing object, the default value is
    744     * returned.
    745     *
    746     * @param key The configuration key.
    747     * @param defaultValue The default value.
    748     * @return The associated List of BigDecimals.
    749     *
    750     * @throws ConversionException is thrown if the key maps to an
    751     *         object that is not a list of BigDecimals.
    752     */
    753    public List<BigDecimal> getBigDecimalList(final String key, final List<BigDecimal> defaultValue)
    754    {
    755        return getList(BigDecimal.class, key, defaultValue);
    756    }
    757
    758    /**
    759     * Get an array of BigDecimals associated with the given
    760     * configuration key. If the key doesn't map to an existing object
    761     * an empty array is returned.
    762     *
    763     * @param key The configuration key.
    764     * @return The associated BigDecimal array if the key is found.
    765     *
    766     * @throws ConversionException is thrown if the key maps to an
    767     *         object that is not a list of BigDecimals.
    768     */
    769    public BigDecimal[] getBigDecimalArray(final String key)
    770    {
    771        return getBigDecimalArray(key, new BigDecimal[0]);
    772    }
    773
    774    /**
    775     * Get an array of BigDecimals associated with the given
    776     * configuration key. If the key doesn't map to an existing object
    777     * an empty array is returned.
    778     *
    779     * @param key The configuration key.
    780     * @param defaultValue the default value, which will be returned if the property is not found
    781     * @return The associated BigDecimal array if the key is found.
    782     *
    783     * @throws ConversionException is thrown if the key maps to an
    784     *         object that is not a list of BigDecimals.
    785     */
    786    public BigDecimal[] getBigDecimalArray(final String key, final BigDecimal[] defaultValue)
    787    {
    788        return get(BigDecimal[].class, key, defaultValue);
    789    }
    790
    791    /**
    792     * Get an URI associated with the given configuration key.
    793     *
    794     * @param key The configuration key.
    795     * @return The associated URI.
    796     *
    797     * @throws ConversionException is thrown if the key maps to an
    798     *         object that is not an URI.
    799     */
    800    public URI getURI(final String key)
    801    {
    802        return get(URI.class, key);
    803    }
    804
    805    /**
    806     * Get an URI associated with the given configuration key.
    807     * If the key doesn't map to an existing object, the default value
    808     * is returned.
    809     *
    810     * @param key          The configuration key.
    811     * @param defaultValue The default value.
    812     * @return The associated URI.
    813     *
    814     * @throws ConversionException is thrown if the key maps to an
    815     *         object that is not an URI.
    816     */
    817    public URI getURI(final String key, final URI defaultValue)
    818    {
    819        return get(URI.class, key, defaultValue);
    820    }
    821
    822    /**
    823     * Get an array of URIs associated with the given configuration key.
    824     * If the key doesn't map to an existing object an empty array is returned.
    825     *
    826     * @param key The configuration key.
    827     * @return The associated URI array if the key is found.
    828     *
    829     * @throws ConversionException is thrown if the key maps to an
    830     *         object that is not a list of URIs.
    831     */
    832    public URI[] getURIArray(final String key)
    833    {
    834        return getURIArray(key, new URI[0]);
    835    }
    836
    837    /**
    838     * Get an array of URIs associated with the given configuration key.
    839     * If the key doesn't map to an existing object an empty array is returned.
    840     *
    841     * @param key The configuration key.
    842     * @param defaultValue the default value, which will be returned if the property is not found
    843     * @return The associated URI array if the key is found.
    844     *
    845     * @throws ConversionException is thrown if the key maps to an
    846     *         object that is not a list of URIs.
    847     */
    848    public URI[] getURIArray(final String key, final URI[] defaultValue)
    849    {
    850        return get(URI[].class, key, defaultValue);
    851    }
    852
    853    /**
    854     * Get a list of URIs associated with the given configuration key.
    855     * If the key doesn't map to an existing object an empty list is returned.
    856     *
    857     * @param key The configuration key.
    858     * @return The associated URI list if the key is found.
    859     *
    860     * @throws ConversionException is thrown if the key maps to an
    861     *         object that is not a list of URIs.
    862     */
    863    public List<URI> getURIList(final String key)
    864    {
    865        return getURIList(key, new ArrayList<URI>());
    866    }
    867
    868    /**
    869     * Get a list of URIs associated with the given configuration key.
    870     * If the key doesn't map to an existing object, the default value is
    871     * returned.
    872     *
    873     * @param key The configuration key.
    874     * @param defaultValue The default value.
    875     * @return The associated List of URIs.
    876     *
    877     * @throws ConversionException is thrown if the key maps to an
    878     *         object that is not a list of URIs.
    879     */
    880    public List<URI> getURIList(final String key, final List<URI> defaultValue)
    881    {
    882        return getList(URI.class, key, defaultValue);
    883    }
    884
    885    /**
    886     * Get an URL associated with the given configuration key.
    887     *
    888     * @param key The configuration key.
    889     * @return The associated URL.
    890     *
    891     * @throws ConversionException is thrown if the key maps to an
    892     *         object that is not an URL.
    893     */
    894    public URL getURL(final String key)
    895    {
    896        return get(URL.class, key);
    897    }
    898
    899    /**
    900     * Get an URL associated with the given configuration key.
    901     * If the key doesn't map to an existing object, the default value
    902     * is returned.
    903     *
    904     * @param key          The configuration key.
    905     * @param defaultValue The default value.
    906     * @return The associated URL.
    907     *
    908     * @throws ConversionException is thrown if the key maps to an
    909     *         object that is not an URL.
    910     */
    911    public URL getURL(final String key, final URL defaultValue)
    912    {
    913        return get(URL.class, key, defaultValue);
    914    }
    915
    916    /**
    917     * Get a list of URLs associated with the given configuration key.
    918     * If the key doesn't map to an existing object an empty list is returned.
    919     *
    920     * @param key The configuration key.
    921     * @return The associated URL list if the key is found.
    922     *
    923     * @throws ConversionException is thrown if the key maps to an
    924     *         object that is not a list of URLs.
    925     */
    926    public List<URL> getURLList(final String key)
    927    {
    928        return getURLList(key, new ArrayList<URL>());
    929    }
    930
    931    /**
    932     * Get a list of URLs associated with the given configuration key.
    933     * If the key doesn't map to an existing object, the default value is
    934     * returned.
    935     *
    936     * @param key The configuration key.
    937     * @param defaultValue The default value.
    938     * @return The associated List of URLs.
    939     *
    940     * @throws ConversionException is thrown if the key maps to an
    941     *         object that is not a list of URLs.
    942     */
    943    public List<URL> getURLList(final String key, final List<URL> defaultValue)
    944    {
    945        return getList(URL.class, key, defaultValue);
    946    }
    947
    948    /**
    949     * Get an array of URLs associated with the given configuration key.
    950     * If the key doesn't map to an existing object an empty array is returned.
    951     *
    952     * @param key The configuration key.
    953     * @return The associated URL array if the key is found.
    954     *
    955     * @throws ConversionException is thrown if the key maps to an
    956     *         object that is not a list of URLs.
    957     */
    958    public URL[] getURLArray(final String key)
    959    {
    960        return getURLArray(key, new URL[0]);
    961    }
    962
    963    /**
    964     * Get an array of URLs associated with the given configuration key.
    965     * If the key doesn't map to an existing object an empty array is returned.
    966     *
    967     * @param key The configuration key.
    968     * @param defaultValue the default value, which will be returned if the property is not found
    969     * @return The associated URL array if the key is found.
    970     *
    971     * @throws ConversionException is thrown if the key maps to an
    972     *         object that is not a list of URLs.
    973     */
    974    public URL[] getURLArray(final String key, final URL[] defaultValue)
    975    {
    976        return get(URL[].class, key, defaultValue);
    977    }
    978
    979    /**
    980     * Get a Date associated with the given configuration key. If the property
    981     * is a String, it will be parsed with the format defined by the user in
    982     * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
    983     * {@link #DEFAULT_DATE_FORMAT} pattern.
    984     *
    985     * @param key The configuration key.
    986     * @return The associated Date.
    987     *
    988     * @throws ConversionException is thrown if the key maps to an
    989     *         object that is not a Date.
    990     */
    991    public Date getDate(final String key)
    992    {
    993        return get(Date.class, key);
    994    }
    995
    996    /**
    997     * Get a Date associated with the given configuration key. If the property
    998     * is a String, it will be parsed with the specified format pattern.
    999     *
    1000     * @param key    The configuration key.
    1001     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1002     * @return The associated Date
    1003     *
    1004     * @throws ConversionException is thrown if the key maps to an
    1005     *         object that is not a Date.
    1006     */
    1007    public Date getDate(final String key, final String format)
    1008    {
    1009        final Date value = getDate(key, null, format);
    1010        if (value != null)
    1011        {
    1012            return value;
    1013        }
    1014        else if (isThrowExceptionOnMissing())
    1015        {
    1016            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
    1017        }
    1018        else
    1019        {
    1020            return null;
    1021        }
    1022    }
    1023
    1024    /**
    1025     * Get a Date associated with the given configuration key. If the property
    1026     * is a String, it will be parsed with the format defined by the user in
    1027     * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
    1028     * {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map to an
    1029     * existing object, the default value is returned.
    1030     *
    1031     * @param key          The configuration key.
    1032     * @param defaultValue The default value.
    1033     * @return The associated Date.
    1034     *
    1035     * @throws ConversionException is thrown if the key maps to an
    1036     *         object that is not a Date.
    1037     */
    1038    public Date getDate(final String key, final Date defaultValue)
    1039    {
    1040        return getDate(key, defaultValue, null);
    1041    }
    1042
    1043    /**
    1044     * Get a Date associated with the given configuration key. If the property
    1045     * is a String, it will be parsed with the specified format pattern.
    1046     * If the key doesn't map to an existing object, the default value
    1047     * is returned.
    1048     *
    1049     * @param key          The configuration key.
    1050     * @param defaultValue The default value.
    1051     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1052     * @return The associated Date.
    1053     *
    1054     * @throws ConversionException is thrown if the key maps to an
    1055     *         object that is not a Date.
    1056     */
    1057    public Date getDate(final String key, final Date defaultValue, final String format)
    1058    {
    1059        TEMP_DATE_FORMAT.set(format);
    1060        try
    1061        {
    1062            return get(Date.class, key, defaultValue);
    1063        }
    1064        finally
    1065        {
    1066            TEMP_DATE_FORMAT.remove();
    1067        }
    1068    }
    1069
    1070    public List<Date> getDateList(final String key)
    1071    {
    1072        return getDateList(key, new ArrayList<Date>());
    1073    }
    1074
    1075    /**
    1076     * Get a list of Dates associated with the given configuration key.
    1077     * If the property is a list of Strings, they will be parsed with the
    1078     * specified format pattern. If the key doesn't map to an existing object
    1079     * an empty list is returned.
    1080     *
    1081     * @param key    The configuration key.
    1082     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1083     * @return The associated Date list if the key is found.
    1084     *
    1085     * @throws ConversionException is thrown if the key maps to an
    1086     *         object that is not a list of Dates.
    1087     */
    1088    public List<Date> getDateList(final String key, final String format)
    1089    {
    1090        return getDateList(key, new ArrayList<Date>(), format);
    1091    }
    1092
    1093    /**
    1094     * Get a list of Dates associated with the given configuration key.
    1095     * If the property is a list of Strings, they will be parsed with the
    1096     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1097     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1098     * If the key doesn't map to an existing object, the default value is
    1099     * returned.
    1100     *
    1101     * @param key          The configuration key.
    1102     * @param defaultValue The default value.
    1103     * @return The associated Date list if the key is found.
    1104     *
    1105     * @throws ConversionException is thrown if the key maps to an
    1106     *         object that is not a list of Dates.
    1107     */
    1108    public List<Date> getDateList(final String key, final List<Date> defaultValue)
    1109    {
    1110        return getDateList(key, defaultValue, null);
    1111    }
    1112
    1113    /**
    1114     * Get a list of Dates associated with the given configuration key.
    1115     * If the property is a list of Strings, they will be parsed with the
    1116     * specified format pattern. If the key doesn't map to an existing object,
    1117     * the default value is returned.
    1118     *
    1119     * @param key          The configuration key.
    1120     * @param defaultValue The default value.
    1121     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1122     * @return The associated Date list if the key is found.
    1123     *
    1124     * @throws ConversionException is thrown if the key maps to an
    1125     *         object that is not a list of Dates.
    1126     */
    1127    public List<Date> getDateList(final String key, final List<Date> defaultValue, final String format)
    1128    {
    1129        TEMP_DATE_FORMAT.set(format);
    1130        try
    1131        {
    1132            return getList(Date.class, key, defaultValue);
    1133        }
    1134        finally
    1135        {
    1136            TEMP_DATE_FORMAT.remove();
    1137        }
    1138    }
    1139
    1140    /**
    1141     * Get an array of Dates associated with the given configuration key.
    1142     * If the property is a list of Strings, they will be parsed with the
    1143     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1144     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1145     * If the key doesn't map to an existing object an empty array is returned.
    1146     *
    1147     * @param key The configuration key.
    1148     * @return The associated Date array if the key is found.
    1149     *
    1150     * @throws ConversionException is thrown if the key maps to an
    1151     *         object that is not a list of Dates.
    1152     */
    1153    public Date[] getDateArray(final String key)
    1154    {
    1155        return getDateArray(key, new Date[0]);
    1156    }
    1157
    1158    /**
    1159     * Get an array of Dates associated with the given configuration key.
    1160     * If the property is a list of Strings, they will be parsed with the
    1161     * specified format pattern. If the key doesn't map to an existing object
    1162     * an empty array is returned.
    1163     *
    1164     * @param key    The configuration key.
    1165     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1166     * @return The associated Date array if the key is found.
    1167     *
    1168     * @throws ConversionException is thrown if the key maps to an
    1169     *         object that is not a list of Dates.
    1170     */
    1171    public Date[] getDateArray(final String key, final String format)
    1172    {
    1173        return getDateArray(key, new Date[0], format);
    1174    }
    1175
    1176    /**
    1177     * Get an array of Dates associated with the given configuration key.
    1178     * If the property is a list of Strings, they will be parsed with the
    1179     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1180     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1181     * If the key doesn't map to an existing object an empty array is returned.
    1182     *
    1183     * @param key The configuration key.
    1184     * @param defaultValue the default value, which will be returned if the property is not found
    1185     * @return The associated Date array if the key is found.
    1186     *
    1187     * @throws ConversionException is thrown if the key maps to an
    1188     *         object that is not a list of Dates.
    1189     */
    1190    public Date[] getDateArray(final String key, final Date[] defaultValue)
    1191    {
    1192        return getDateArray(key, defaultValue, null);
    1193    }
    1194
    1195    /**
    1196     * Get an array of Dates associated with the given configuration key.
    1197     * If the property is a list of Strings, they will be parsed with the
    1198     * specified format pattern. If the key doesn't map to an existing object,
    1199     * the default value is returned.
    1200     *
    1201     * @param key          The configuration key.
    1202     * @param defaultValue The default value.
    1203     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1204     * @return The associated Date array if the key is found.
    1205     *
    1206     * @throws ConversionException is thrown if the key maps to an
    1207     *         object that is not a list of Dates.
    1208     */
    1209    public Date[] getDateArray(final String key, final Date[] defaultValue, final String format)
    1210    {
    1211        TEMP_DATE_FORMAT.set(format);
    1212        try
    1213        {
    1214            return get(Date[].class, key, defaultValue);
    1215        }
    1216        finally
    1217        {
    1218            TEMP_DATE_FORMAT.remove();
    1219        }
    1220    }
    1221
    1222    /**
    1223     * Get a Calendar associated with the given configuration key. If the
    1224     * property is a String, it will be parsed with the format defined by the
    1225     * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
    1226     * with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1227     *
    1228     * @param key The configuration key.
    1229     * @return The associated Calendar.
    1230     *
    1231     * @throws ConversionException is thrown if the key maps to an
    1232     *         object that is not a Calendar.
    1233     */
    1234    public Calendar getCalendar(final String key)
    1235    {
    1236        return get(Calendar.class, key);
    1237    }
    1238
    1239    /**
    1240     * Get a Calendar associated with the given configuration key. If the
    1241     * property is a String, it will be parsed with the specified format
    1242     * pattern.
    1243     *
    1244     * @param key    The configuration key.
    1245     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1246     * @return The associated Calendar
    1247     *
    1248     * @throws ConversionException is thrown if the key maps to an
    1249     *         object that is not a Calendar.
    1250     */
    1251    public Calendar getCalendar(final String key, final String format)
    1252    {
    1253        final Calendar value = getCalendar(key, null, format);
    1254        if (value != null)
    1255        {
    1256            return value;
    1257        }
    1258        else if (isThrowExceptionOnMissing())
    1259        {
    1260            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
    1261        }
    1262        else
    1263        {
    1264            return null;
    1265        }
    1266    }
    1267
    1268    /**
    1269     * Get a Calendar associated with the given configuration key. If the
    1270     * property is a String, it will be parsed with the format defined by the
    1271     * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
    1272     * with the {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map
    1273     * to an existing object, the default value is returned.
    1274     *
    1275     * @param key          The configuration key.
    1276     * @param defaultValue The default value.
    1277     * @return The associated Calendar.
    1278     *
    1279     * @throws ConversionException is thrown if the key maps to an
    1280     *         object that is not a Calendar.
    1281     */
    1282    public Calendar getCalendar(final String key, final Calendar defaultValue)
    1283    {
    1284        return getCalendar(key, defaultValue, null);
    1285    }
    1286
    1287    /**
    1288     * Get a Calendar associated with the given configuration key. If the
    1289     * property is a String, it will be parsed with the specified format
    1290     * pattern. If the key doesn't map to an existing object, the default
    1291     * value is returned.
    1292     *
    1293     * @param key          The configuration key.
    1294     * @param defaultValue The default value.
    1295     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1296     * @return The associated Calendar.
    1297     *
    1298     * @throws ConversionException is thrown if the key maps to an
    1299     *         object that is not a Calendar.
    1300     */
    1301    public Calendar getCalendar(final String key, final Calendar defaultValue, final String format)
    1302    {
    1303        TEMP_DATE_FORMAT.set(format);
    1304        try
    1305        {
    1306            return get(Calendar.class, key, defaultValue);
    1307        }
    1308        finally
    1309        {
    1310            TEMP_DATE_FORMAT.remove();
    1311        }
    1312    }
    1313
    1314    /**
    1315     * Get a list of Calendars associated with the given configuration key.
    1316     * If the property is a list of Strings, they will be parsed with the
    1317     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1318     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1319     * If the key doesn't map to an existing object an empty list is returned.
    1320     *
    1321     * @param key The configuration key.
    1322     * @return The associated Calendar list if the key is found.
    1323     *
    1324     * @throws ConversionException is thrown if the key maps to an
    1325     *         object that is not a list of Calendars.
    1326     */
    1327    public List<Calendar> getCalendarList(final String key)
    1328    {
    1329        return getCalendarList(key, new ArrayList<Calendar>());
    1330    }
    1331
    1332    /**
    1333     * Get a list of Calendars associated with the given configuration key.
    1334     * If the property is a list of Strings, they will be parsed with the
    1335     * specified format pattern. If the key doesn't map to an existing object
    1336     * an empty list is returned.
    1337     *
    1338     * @param key    The configuration key.
    1339     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1340     * @return The associated Calendar list if the key is found.
    1341     *
    1342     * @throws ConversionException is thrown if the key maps to an
    1343     *         object that is not a list of Calendars.
    1344     */
    1345    public List<Calendar> getCalendarList(final String key, final String format)
    1346    {
    1347        return getCalendarList(key, new ArrayList<Calendar>(), format);
    1348    }
    1349
    1350    /**
    1351     * Get a list of Calendars associated with the given configuration key.
    1352     * If the property is a list of Strings, they will be parsed with the
    1353     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1354     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1355     * If the key doesn't map to an existing object, the default value is
    1356     * returned.
    1357     *
    1358     * @param key The configuration key.
    1359     * @param defaultValue The default value.
    1360     * @return The associated Calendar list if the key is found.
    1361     *
    1362     * @throws ConversionException is thrown if the key maps to an
    1363     *         object that is not a list of Calendars.
    1364     */
    1365    public List<Calendar> getCalendarList(final String key, final List<Calendar> defaultValue)
    1366    {
    1367        return getCalendarList(key, defaultValue, null);
    1368    }
    1369
    1370    /**
    1371     * Get a list of Calendars associated with the given configuration key.
    1372     * If the property is a list of Strings, they will be parsed with the
    1373     * specified format pattern. If the key doesn't map to an existing object,
    1374     * the default value is returned.
    1375     *
    1376     * @param key          The configuration key.
    1377     * @param defaultValue The default value.
    1378     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1379     * @return The associated Calendar list if the key is found.
    1380     *
    1381     * @throws ConversionException is thrown if the key maps to an
    1382     *         object that is not a list of Calendars.
    1383     */
    1384    public List<Calendar> getCalendarList(final String key, final List<Calendar> defaultValue, final String format)
    1385    {
    1386        TEMP_DATE_FORMAT.set(format);
    1387        try
    1388        {
    1389            return getList(Calendar.class, key, defaultValue);
    1390        }
    1391        finally
    1392        {
    1393            TEMP_DATE_FORMAT.remove();
    1394        }
    1395    }
    1396
    1397    /**
    1398     * Get an array of Calendars associated with the given configuration key.
    1399     * If the property is a list of Strings, they will be parsed with the
    1400     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1401     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1402     * If the key doesn't map to an existing object an empty array is returned.
    1403     *
    1404     * @param key The configuration key.
    1405     * @return The associated Calendar array if the key is found.
    1406     *
    1407     * @throws ConversionException is thrown if the key maps to an
    1408     *         object that is not a list of Calendars.
    1409     */
    1410    public Calendar[] getCalendarArray(final String key)
    1411    {
    1412        return getCalendarArray(key, new Calendar[0]);
    1413    }
    1414
    1415    /**
    1416     * Get an array of Calendars associated with the given configuration key.
    1417     * If the property is a list of Strings, they will be parsed with the
    1418     * specified format pattern. If the key doesn't map to an existing object
    1419     * an empty array is returned.
    1420     *
    1421     * @param key    The configuration key.
    1422     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1423     * @return The associated Calendar array if the key is found.
    1424     *
    1425     * @throws ConversionException is thrown if the key maps to an
    1426     *         object that is not a list of Calendars.
    1427     */
    1428    public Calendar[] getCalendarArray(final String key, final String format)
    1429    {
    1430        return getCalendarArray(key, new Calendar[0], format);
    1431    }
    1432
    1433    /**
    1434     * Get an array of Calendars associated with the given configuration key.
    1435     * If the property is a list of Strings, they will be parsed with the
    1436     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1437     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1438     * If the key doesn't map to an existing object an empty array is returned.
    1439     *
    1440     * @param key The configuration key.
    1441     * @param defaultValue the default value, which will be returned if the property is not found
    1442     * @return The associated Calendar array if the key is found.
    1443     *
    1444     * @throws ConversionException is thrown if the key maps to an
    1445     *         object that is not a list of Calendars.
    1446     */
    1447    public Calendar[] getCalendarArray(final String key, final Calendar[] defaultValue)
    1448    {
    1449        return getCalendarArray(key, defaultValue, null);
    1450    }
    1451
    1452    /**
    1453     * Get an array of Calendars associated with the given configuration key.
    1454     * If the property is a list of Strings, they will be parsed with the
    1455     * specified format pattern. If the key doesn't map to an existing object,
    1456     * the default value is returned.
    1457     *
    1458     * @param key          The configuration key.
    1459     * @param defaultValue The default value.
    1460     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1461     * @return The associated Calendar array if the key is found.
    1462     *
    1463     * @throws ConversionException is thrown if the key maps to an
    1464     *         object that is not a list of Calendars.
    1465     */
    1466    public Calendar[] getCalendarArray(final String key, final Calendar[] defaultValue, final String format)
    1467    {
    1468        TEMP_DATE_FORMAT.set(format);
    1469        try
    1470        {
    1471            return get(Calendar[].class, key, defaultValue);
    1472        }
    1473        finally
    1474        {
    1475            TEMP_DATE_FORMAT.remove();
    1476        }
    1477    }
    1478
    1479    /**
    1480     * Returns the date format specified by the user in the DATE_FORMAT_KEY
    1481     * property, or the default format otherwise.
    1482     *
    1483     * @return the default date format
    1484     */
    1485    private String getDefaultDateFormat()
    1486    {
    1487        return getString(DATE_FORMAT_KEY, DEFAULT_DATE_FORMAT);
    1488    }
    1489
    1490    /**
    1491     * Get a Locale associated with the given configuration key.
    1492     *
    1493     * @param key The configuration key.
    1494     * @return The associated Locale.
    1495     *
    1496     * @throws ConversionException is thrown if the key maps to an
    1497     *         object that is not a Locale.
    1498     */
    1499    public Locale getLocale(final String key)
    1500    {
    1501        return get(Locale.class, key);
    1502    }
    1503
    1504    /**
    1505     * Get a Locale associated with the given configuration key.
    1506     * If the key doesn't map to an existing object, the default value
    1507     * is returned.
    1508     *
    1509     * @param key          The configuration key.
    1510     * @param defaultValue The default value.
    1511     * @return The associated Locale.
    1512     *
    1513     * @throws ConversionException is thrown if the key maps to an
    1514     *         object that is not a Locale.
    1515     */
    1516    public Locale getLocale(final String key, final Locale defaultValue)
    1517    {
    1518        return get(Locale.class, key, defaultValue);
    1519    }
    1520
    1521    /**
    1522     * Get a list of Locales associated with the given configuration key.
    1523     * If the key doesn't map to an existing object an empty list is returned.
    1524     *
    1525     * @param key The configuration key.
    1526     * @return The associated Locale list if the key is found.
    1527     *
    1528     * @throws ConversionException is thrown if the key maps to an
    1529     *         object that is not a list of Locales.
    1530     */
    1531    public List<Locale> getLocaleList(final String key)
    1532    {
    1533        return getLocaleList(key, new ArrayList<Locale>());
    1534    }
    1535
    1536    /**
    1537     * Get a list of Locales associated with the given configuration key.
    1538     * If the key doesn't map to an existing object, the default value is
    1539     * returned.
    1540     *
    1541     * @param key The configuration key.
    1542     * @param defaultValue The default value.
    1543     * @return The associated List of Locales.
    1544     *
    1545     * @throws ConversionException is thrown if the key maps to an
    1546     *         object that is not a list of Locales.
    1547     */
    1548    public List<Locale> getLocaleList(final String key, final List<Locale> defaultValue)
    1549    {
    1550        return getList(Locale.class, key, defaultValue);
    1551    }
    1552
    1553    /**
    1554     * Get an array of Locales associated with the given
    1555     * configuration key. If the key doesn't map to an existing object
    1556     * an empty array is returned.
    1557     *
    1558     * @param key The configuration key.
    1559     * @return The associated Locale array if the key is found.
    1560     *
    1561     * @throws ConversionException is thrown if the key maps to an
    1562     *         object that is not a list of Locales.
    1563     */
    1564    public Locale[] getLocaleArray(final String key)
    1565    {
    1566        return getLocaleArray(key, new Locale[0]);
    1567    }
    1568
    1569    /**
    1570     * Get an array of Locales associated with the given
    1571     * configuration key. If the key doesn't map to an existing object
    1572     * an empty array is returned.
    1573     *
    1574     * @param key The configuration key.
    1575     * @param defaultValue the default value, which will be returned if the property is not found
    1576     * @return The associated Locale array if the key is found.
    1577     *
    1578     * @throws ConversionException is thrown if the key maps to an
    1579     *         object that is not a list of Locales.
    1580     */
    1581    public Locale[] getLocaleArray(final String key, final Locale[] defaultValue)
    1582    {
    1583        return get(Locale[].class, key, defaultValue);
    1584    }
    1585
    1586    /**
    1587     * Get a Color associated with the given configuration key.
    1588     *
    1589     * @param key The configuration key.
    1590     * @return The associated Color.
    1591     *
    1592     * @throws ConversionException is thrown if the key maps to an
    1593     *         object that is not a Color.
    1594     */
    1595    public Color getColor(final String key)
    1596    {
    1597        return get(Color.class, key);
    1598    }
    1599
    1600    /**
    1601     * Get a Color associated with the given configuration key.
    1602     * If the key doesn't map to an existing object, the default value
    1603     * is returned.
    1604     *
    1605     * @param key          The configuration key.
    1606     * @param defaultValue The default value.
    1607     * @return The associated Color.
    1608     *
    1609     * @throws ConversionException is thrown if the key maps to an
    1610     *         object that is not a Color.
    1611     */
    1612    public Color getColor(final String key, final Color defaultValue)
    1613    {
    1614        return get(Color.class, key, defaultValue);
    1615    }
    1616
    1617    /**
    1618     * Get a list of Colors associated with the given configuration key.
    1619     * If the key doesn't map to an existing object an empty list is returned.
    1620     *
    1621     * @param key The configuration key.
    1622     * @return The associated Color list if the key is found.
    1623     *
    1624     * @throws ConversionException is thrown if the key maps to an
    1625     *         object that is not a list of Colors.
    1626     */
    1627    public List<Color> getColorList(final String key)
    1628    {
    1629        return getColorList(key, new ArrayList<Color>());
    1630    }
    1631
    1632    /**
    1633     * Get a list of Colors associated with the given configuration key.
    1634     * If the key doesn't map to an existing object, the default value is
    1635     * returned.
    1636     *
    1637     * @param key The configuration key.
    1638     * @param defaultValue The default value.
    1639     * @return The associated List of Colors.
    1640     *
    1641     * @throws ConversionException is thrown if the key maps to an
    1642     *         object that is not a list of Colors.
    1643     */
    1644    public List<Color> getColorList(final String key, final List<Color> defaultValue)
    1645    {
    1646        return getList(Color.class, key, defaultValue);
    1647    }
    1648
    1649    /**
    1650     * Get an array of Colors associated with the given
    1651     * configuration key. If the key doesn't map to an existing object
    1652     * an empty array is returned.
    1653     *
    1654     * @param key The configuration key.
    1655     * @return The associated Color array if the key is found.
    1656     *
    1657     * @throws ConversionException is thrown if the key maps to an
    1658     *         object that is not a list of Colors.
    1659     */
    1660    public Color[] getColorArray(final String key)
    1661    {
    1662        return getColorArray(key, new Color[0]);
    1663    }
    1664
    1665    /**
    1666     * Get an array of Colors associated with the given
    1667     * configuration key. If the key doesn't map to an existing object
    1668     * an empty array is returned.
    1669     *
    1670     * @param key The configuration key.
    1671     * @param defaultValue the default value, which will be returned if the property is not found
    1672     * @return The associated Color array if the key is found.
    1673     *
    1674     * @throws ConversionException is thrown if the key maps to an
    1675     *         object that is not a list of Colors.
    1676     */
    1677    public Color[] getColorArray(final String key, final Color[] defaultValue)
    1678    {
    1679        return get(Color[].class, key, defaultValue);
    1680    }
    1681
    1682    /**
    1683     * Returns the original conversion handler set for this configuration. If
    1684     * this is not a {@code DefaultConversionHandler}, result is <b>null</b>.
    1685     *
    1686     * @return the original conversion handler or <b>null</b>
    1687     */
    1688    private DefaultConversionHandler getOriginalConversionHandler()
    1689    {
    1690        final ConversionHandler handler = super.getConversionHandler();
    1691        return (DefaultConversionHandler) (handler instanceof DefaultConversionHandler ? handler
    1692                : null);
    1693    }
    1694
    1695    /**
    1696     * A specialized {@code ConversionHandler} implementation which allows
    1697     * overriding the date format pattern. This class takes care that the format
    1698     * pattern can be defined as a property of the wrapped configuration or
    1699     * temporarily passed when calling a conversion method.
    1700     */
    1701    private class DataConversionHandler extends DefaultConversionHandler
    1702    {
    1703        /**
    1704         * {@inheritDoc} This implementation checks for a defined data format in
    1705         * the following order:
    1706         * <ul>
    1707         * <li>If a temporary date format is set for the current call, it is
    1708         * used.</li>
    1709         * <li>If a date format is specified in this configuration using the
    1710         * {@code DATE_FORMAT_KEY} property, it is used.</li>
    1711         * <li>Otherwise, the date format set for the original conversion
    1712         * handler is used if available.</li>
    1713         * </ul>
    1714         */
    1715        @Override
    1716        public String getDateFormat()
    1717        {
    1718            if (StringUtils.isNotEmpty(TEMP_DATE_FORMAT.get()))
    1719            {
    1720                return TEMP_DATE_FORMAT.get();
    1721            }
    1722            if (containsKey(DATE_FORMAT_KEY))
    1723            {
    1724                return getDefaultDateFormat();
    1725            }
    1726
    1727            final DefaultConversionHandler orgHandler =
    1728                    getOriginalConversionHandler();
    1729            return orgHandler != null ? orgHandler.getDateFormat() : null;
    1730        }
    1731    }
    1732}