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