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