    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
    018    package org.apache.commons.configuration;
    019
    020    import java.awt.Color;
    021    import java.io.Serializable;
    022    import java.lang.reflect.Array;
    023    import java.math.BigDecimal;
    024    import java.math.BigInteger;
    025    import java.net.URL;
    026    import java.util.ArrayList;
    027    import java.util.Calendar;
    028    import java.util.Collection;
    029    import java.util.Date;
    030    import java.util.Iterator;
    031    import java.util.List;
    032    import java.util.Locale;
    033    import java.util.NoSuchElementException;
    034
    035    import org.apache.commons.lang.ClassUtils;
    036    import org.apache.commons.lang.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>{@link 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.
    053     *
    054     * <h4>Example</h4>
    055     *
    056     * Configuration file <tt>config.properties</tt>:
    057     * <pre>
    058     * title.color = #0000FF
    059     * remote.host = 192.168.0.53
    060     * default.locales = fr,en,de
    061     * email.contact = ebourg@apache.org, oheger@apache.org
    062     * </pre>
    063     *
    064     * Usage:
    065     *
    066     * <pre>
    067     * DataConfiguration config = new DataConfiguration(new PropertiesConfiguration("config.properties"));
    068     *
    069     * // retrieve a property using a specialized getter
    070     * Color color = config.getColor("title.color");
    071     *
    072     * // retrieve a property using a generic getter
    073     * InetAddress host = (InetAddress) config.get(InetAddress.class, "remote.host");
    074     * Locale[] locales = (Locale[]) config.getArray(Locale.class, "default.locales");
    075     * List contacts = config.getList(InternetAddress.class, "email.contact");
    076     * </pre>
    077     *
    078     * <h4>Dates</h4>
    079     *
    080     * Date objects are expected to be formatted with the pattern <tt>yyyy-MM-dd HH:mm:ss</tt>.
    081     * This default format can be changed by specifying another format in the
    082     * getters, or by putting a date format in the configuration under the key
    083     * <tt>org.apache.commons.configuration.format.date</tt>.
    084     *
    085     * @author <a href="ebourg@apache.org">Emmanuel Bourg</a>
    086     * @version $Revision: 681798 $, $Date: 2008-08-01 21:38:42 +0200 (Fr, 01. Aug 2008) $
    087     * @since 1.1
    088     */
    089    public class DataConfiguration extends AbstractConfiguration implements Serializable
    090    {
    091        /** The key of the property storing the user defined date format. */
    092        public static final String DATE_FORMAT_KEY = "org.apache.commons.configuration.format.date";
    093
    094        /** The default format for dates. */
    095        public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    096
    097        /**
    098         * The serial version UID.
    099         */
    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    }