View Javadoc

1   /*
2    * Copyright 2004-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.configuration;
18  
19  import java.awt.Color;
20  import java.math.BigDecimal;
21  import java.math.BigInteger;
22  import java.net.URL;
23  import java.util.ArrayList;
24  import java.util.Calendar;
25  import java.util.Collection;
26  import java.util.Date;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Locale;
30  import java.io.Serializable;
31  
32  import org.apache.commons.collections.CollectionUtils;
33  import org.apache.commons.lang.ArrayUtils;
34  import org.apache.commons.lang.StringUtils;
35  
36  /***
37   * Decorator providing additional getters for any Configuration. This extended
38   * Configuration supports more types: URL, Locale, Date, Calendar, Color, as
39   * well as lists and arrays for all types.
40   *
41   * <p>Let us know if you find this useful, the most frequently used getters
42   * are likely to be integrated in the Configuration interface in a future
43   * version.</p>
44   *
45   * @author <a href="ebourg@apache.org">Emmanuel Bourg</a>
46   * @version $Revision$, $Date: 2005-10-09 20:27:12 +0200 (Sun, 09 Oct 2005) $
47   * @since 1.1
48   */
49  public class DataConfiguration extends AbstractConfiguration implements Serializable
50  {
51      /*** The key of the property storing the user defined date format. */
52      public static final String DATE_FORMAT_KEY = "org.apache.commons.configuration.format.date";
53  
54      /*** The default format for dates. */
55      public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
56  
57      /*** Stores the wrapped configuration.*/
58      protected Configuration configuration;
59  
60      /***
61       * Creates a new instance of <code>DataConfiguration</code> and sets the
62       * wrapped configuration.
63       *
64       * @param configuration the wrapped configuration
65       */
66      public DataConfiguration(Configuration configuration)
67      {
68          this.configuration = configuration;
69      }
70  
71      /***
72       * Return the configuration decorated by this DataConfiguration.
73       *
74       * @return the wrapped configuration
75       */
76      public Configuration getConfiguration()
77      {
78          return configuration;
79      }
80  
81      public Object getProperty(String key)
82      {
83          return configuration.getProperty(key);
84      }
85  
86      protected void addPropertyDirect(String key, Object obj)
87      {
88          configuration.addProperty(key, obj);
89      }
90  
91      public boolean isEmpty()
92      {
93          return configuration.isEmpty();
94      }
95  
96      public boolean containsKey(String key)
97      {
98          return configuration.containsKey(key);
99      }
100 
101     public void clearProperty(String key)
102     {
103         configuration.clearProperty(key);
104     }
105 
106     public Iterator getKeys()
107     {
108         return configuration.getKeys();
109     }
110 
111     /***
112      * Get a list of Boolean objects associated with the given
113      * configuration key. If the key doesn't map to an existing object
114      * an empty list is returned.
115      *
116      * @param key The configuration key.
117      * @return The associated Boolean list if the key is found.
118      *
119      * @throws ConversionException is thrown if the key maps to an
120      *         object that is not a list of booleans.
121      */
122     public List getBooleanList(String key)
123     {
124         return getBooleanList(key, new ArrayList());
125     }
126 
127     /***
128      * Get a list of Boolean objects associated with the given
129      * configuration key. If the key doesn't map to an existing object,
130      * the default value is returned.
131      *
132      * @param key The configuration key.
133      * @param defaultValue The default value.
134      * @return The associated List of strings.
135      *
136      * @throws ConversionException is thrown if the key maps to an
137      *         object that is not a list of booleans.
138      */
139     public List getBooleanList(String key, List defaultValue)
140     {
141         Object value = getProperty(key);
142 
143         List list;
144 
145         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
146         {
147             list = defaultValue;
148         }
149         else if (value instanceof boolean[])
150         {
151             list = new ArrayList();
152             CollectionUtils.addAll(list, ArrayUtils.toObject((boolean[]) value));
153         }
154         else if (value instanceof Boolean[])
155         {
156             list = new ArrayList();
157             CollectionUtils.addAll(list, (Boolean[]) value);
158         }
159         else if (value instanceof Collection)
160         {
161             Collection values = (Collection) value;
162             list = new ArrayList();
163 
164             Iterator it = values.iterator();
165             while (it.hasNext())
166             {
167                 list.add(PropertyConverter.toBoolean(interpolate(it.next())));
168             }
169         }
170         else
171         {
172             try
173             {
174                 // attempt to convert a single value
175                 list = new ArrayList();
176                 list.add(PropertyConverter.toBoolean(interpolate(value)));
177             }
178             catch (ConversionException e)
179             {
180                 throw new ConversionException('\'' + key + "' doesn't map to a list of booleans", e);
181             }
182         }
183 
184         return list;
185     }
186 
187     /***
188      * Get an array of boolean primitives associated with the given
189      * configuration key. If the key doesn't map to an existing object
190      * an empty array is returned.
191      *
192      * @param key The configuration key.
193      * @return The associated boolean array if the key is found.
194      *
195      * @throws ConversionException is thrown if the key maps to an
196      *         object that is not a list of booleans.
197      */
198     public boolean[] getBooleanArray(String key)
199     {
200         return getBooleanArray(key, new boolean[0]);
201     }
202 
203     /***
204      * Get an array of boolean primitives associated with the given
205      * configuration key. If the key doesn't map to an existing object,
206      * the default value is returned.
207      *
208      * @param key          The configuration key.
209      * @param defaultValue The default value.
210      * @return The associated boolean array 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 boolean[] getBooleanArray(String key, boolean[] defaultValue)
216     {
217         Object value = getProperty(key);
218 
219         boolean[] array;
220 
221         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
222         {
223             array = defaultValue;
224         }
225         else if (value instanceof boolean[])
226         {
227             array = (boolean[]) value;
228         }
229         else if (value instanceof Boolean[])
230         {
231             array = ArrayUtils.toPrimitive((Boolean[]) value);
232         }
233         else if (value instanceof Collection)
234         {
235             Collection values = (Collection) value;
236             array = new boolean[values.size()];
237 
238             int i = 0;
239             Iterator it = values.iterator();
240             while (it.hasNext())
241             {
242                 array[i++] = PropertyConverter.toBoolean(interpolate(it.next())).booleanValue();
243             }
244         }
245         else
246         {
247             try
248             {
249                 // attempt to convert a single value
250                 array = new boolean[1];
251                 array[0] = PropertyConverter.toBoolean(interpolate(value)).booleanValue();
252             }
253             catch (ConversionException e)
254             {
255                 throw new ConversionException('\'' + key + "' doesn't map to a list of booleans", e);
256             }
257         }
258 
259         return array;
260     }
261 
262     /***
263      * Get a list of Byte objects associated with the given configuration key.
264      * If the key doesn't map to an existing object an empty list is returned.
265      *
266      * @param key The configuration key.
267      * @return The associated Byte list 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 bytes.
271      */
272     public List getByteList(String key)
273     {
274         return getByteList(key, new ArrayList());
275     }
276 
277     /***
278      * Get a list of Byte objects associated with the given configuration key.
279      * If the key doesn't map to an existing object, the default value is
280      * returned.
281      *
282      * @param key The configuration key.
283      * @param defaultValue The default value.
284      * @return The associated List of Bytes.
285      *
286      * @throws ConversionException is thrown if the key maps to an
287      *         object that is not a list of bytes.
288      */
289     public List getByteList(String key, List defaultValue)
290     {
291         Object value = getProperty(key);
292 
293         List list;
294 
295         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
296         {
297             list = defaultValue;
298         }
299         else if (value instanceof byte[])
300         {
301             list = new ArrayList();
302             CollectionUtils.addAll(list, ArrayUtils.toObject((byte[]) value));
303         }
304         else if (value instanceof Byte[])
305         {
306             list = new ArrayList();
307             CollectionUtils.addAll(list, (Byte[]) value);
308         }
309         else if (value instanceof Collection)
310         {
311             Collection values = (Collection) value;
312             list = new ArrayList();
313 
314             Iterator it = values.iterator();
315             while (it.hasNext())
316             {
317                 list.add(PropertyConverter.toByte(interpolate(it.next())));
318             }
319         }
320         else
321         {
322             try
323             {
324                 // attempt to convert a single value
325                 list = new ArrayList();
326                 list.add(PropertyConverter.toByte(interpolate(value)));
327             }
328             catch (ConversionException e)
329             {
330                 throw new ConversionException('\'' + key + "' doesn't map to a list of bytes", e);
331             }
332         }
333 
334         return list;
335     }
336 
337     /***
338      * Get an array of byte primitives associated with the given
339      * configuration key. If the key doesn't map to an existing object
340      * an empty array is returned.
341      *
342      * @param key The configuration key.
343      * @return The associated byte array if the key is found.
344      *
345      * @throws ConversionException is thrown if the key maps to an
346      *         object that is not a list of bytes.
347      */
348     public byte[] getByteArray(String key)
349     {
350         return getByteArray(key, new byte[0]);
351     }
352 
353     /***
354      * Get an array of byte primitives associated with the given
355      * configuration key. If the key doesn't map to an existing object
356      * an empty array is returned.
357      *
358      * @param key The configuration key.
359      * @param defaultValue the default value, which will be returned if the property is not found
360      * @return The associated byte array if the key is found.
361      *
362      * @throws ConversionException is thrown if the key maps to an
363      *         object that is not a list of bytes.
364      */
365     public byte[] getByteArray(String key, byte[] defaultValue)
366     {
367         Object value = getProperty(key);
368 
369         byte[] array;
370 
371         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
372         {
373             array = defaultValue;
374         }
375         else if (value instanceof byte[])
376         {
377             array = (byte[]) value;
378         }
379         else if (value instanceof Byte[])
380         {
381             array = ArrayUtils.toPrimitive((Byte[]) value);
382         }
383         else if (value instanceof Collection)
384         {
385             Collection values = (Collection) value;
386             array = new byte[values.size()];
387 
388             int i = 0;
389             Iterator it = values.iterator();
390             while (it.hasNext())
391             {
392                 array[i++] = PropertyConverter.toByte(interpolate(it.next())).byteValue();
393             }
394         }
395         else
396         {
397             try
398             {
399                 // attempt to convert a single value
400                 array = new byte[1];
401                 array[0] = PropertyConverter.toByte(interpolate(value)).byteValue();
402             }
403             catch (ConversionException e)
404             {
405                 throw new ConversionException('\'' + key + "' doesn't map to a list of bytes", e);
406             }
407         }
408 
409         return array;
410     }
411 
412     /***
413      * Get a list of Short objects associated with the given configuration key.
414      * If the key doesn't map to an existing object an empty list is returned.
415      *
416      * @param key The configuration key.
417      * @return The associated Short list if the key is found.
418      *
419      * @throws ConversionException is thrown if the key maps to an
420      *         object that is not a list of shorts.
421      */
422     public List getShortList(String key)
423     {
424         return getShortList(key, new ArrayList());
425     }
426 
427     /***
428      * Get a list of Short objects associated with the given configuration key.
429      * If the key doesn't map to an existing object, the default value is
430      * returned.
431      *
432      * @param key The configuration key.
433      * @param defaultValue The default value.
434      * @return The associated List of Shorts.
435      *
436      * @throws ConversionException is thrown if the key maps to an
437      *         object that is not a list of shorts.
438      */
439     public List getShortList(String key, List defaultValue)
440     {
441         Object value = getProperty(key);
442 
443         List list;
444 
445         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
446         {
447             list = defaultValue;
448         }
449         else if (value instanceof short[])
450         {
451             list = new ArrayList();
452             CollectionUtils.addAll(list, ArrayUtils.toObject((short[]) value));
453         }
454         else if (value instanceof Short[])
455         {
456             list = new ArrayList();
457             CollectionUtils.addAll(list, (Short[]) value);
458         }
459         else if (value instanceof Collection)
460         {
461             Collection values = (Collection) value;
462             list = new ArrayList();
463 
464             Iterator it = values.iterator();
465             while (it.hasNext())
466             {
467                 list.add(PropertyConverter.toShort(interpolate(it.next())));
468             }
469         }
470         else
471         {
472             try
473             {
474                 // attempt to convert a single value
475                 list = new ArrayList();
476                 list.add(PropertyConverter.toShort(interpolate(value)));
477             }
478             catch (ConversionException e)
479             {
480                 throw new ConversionException('\'' + key + "' doesn't map to a list of shorts", e);
481             }
482         }
483 
484         return list;
485     }
486 
487     /***
488      * Get an array of short primitives associated with the given
489      * configuration key. If the key doesn't map to an existing object
490      * an empty array is returned.
491      *
492      * @param key The configuration key.
493      * @return The associated short array if the key is found.
494      *
495      * @throws ConversionException is thrown if the key maps to an
496      *         object that is not a list of shorts.
497      */
498     public short[] getShortArray(String key)
499     {
500         return getShortArray(key, new short[0]);
501     }
502 
503     /***
504      * Get an array of short primitives associated with the given
505      * configuration key. If the key doesn't map to an existing object
506      * an empty array is returned.
507      *
508      * @param key The configuration key.
509      * @param defaultValue the default value, which will be returned if the property is not found
510      * @return The associated short array if the key is found.
511      *
512      * @throws ConversionException is thrown if the key maps to an
513      *         object that is not a list of shorts.
514      */
515     public short[] getShortArray(String key, short[] defaultValue)
516     {
517         Object value = getProperty(key);
518 
519         short[] array;
520 
521         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
522         {
523             array = defaultValue;
524         }
525         else if (value instanceof short[])
526         {
527             array = (short[]) value;
528         }
529         else if (value instanceof Short[])
530         {
531             array = ArrayUtils.toPrimitive((Short[]) value);
532         }
533         else if (value instanceof Collection)
534         {
535             Collection values = (Collection) value;
536             array = new short[values.size()];
537 
538             int i = 0;
539             Iterator it = values.iterator();
540             while (it.hasNext())
541             {
542                 array[i++] = PropertyConverter.toShort(interpolate(it.next())).shortValue();
543             }
544         }
545         else
546         {
547             try
548             {
549                 // attempt to convert a single value
550                 array = new short[1];
551                 array[0] = PropertyConverter.toShort(interpolate(value)).shortValue();
552             }
553             catch (ConversionException e)
554             {
555                 throw new ConversionException('\'' + key + "' doesn't map to a list of shorts", e);
556             }
557         }
558 
559         return array;
560     }
561 
562     /***
563      * Get a list of Integer objects associated with the given
564      * configuration key. If the key doesn't map to an existing object
565      * an empty list is returned.
566      *
567      * @param key The configuration key.
568      * @return The associated Integer list if the key is found.
569      *
570      * @throws ConversionException is thrown if the key maps to an
571      *         object that is not a list of integers.
572      */
573     public List getIntegerList(String key)
574     {
575         return getIntegerList(key, new ArrayList());
576     }
577 
578     /***
579      * Get a list of Integer objects associated with the given
580      * configuration key. If the key doesn't map to an existing object,
581      * the default value is returned.
582      *
583      * @param key The configuration key.
584      * @param defaultValue The default value.
585      * @return The associated List of Integers.
586      *
587      * @throws ConversionException is thrown if the key maps to an
588      *         object that is not a list of integers.
589      */
590     public List getIntegerList(String key, List defaultValue)
591     {
592         Object value = getProperty(key);
593 
594         List list;
595 
596         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
597         {
598             list = defaultValue;
599         }
600         else if (value instanceof int[])
601         {
602             list = new ArrayList();
603             CollectionUtils.addAll(list, ArrayUtils.toObject((int[]) value));
604         }
605         else if (value instanceof Integer[])
606         {
607             list = new ArrayList();
608             CollectionUtils.addAll(list, (Integer[]) value);
609         }
610         else if (value instanceof Collection)
611         {
612             Collection values = (Collection) value;
613             list = new ArrayList();
614 
615             Iterator it = values.iterator();
616             while (it.hasNext())
617             {
618                 list.add(PropertyConverter.toInteger(interpolate(it.next())));
619             }
620         }
621         else
622         {
623             try
624             {
625                 // attempt to convert a single value
626                 list = new ArrayList();
627                 list.add(PropertyConverter.toInteger(interpolate(value)));
628             }
629             catch (ConversionException e)
630             {
631                 throw new ConversionException('\'' + key + "' doesn't map to a list of integers", e);
632             }
633         }
634 
635         return list;
636     }
637 
638     /***
639      * Get an array of int primitives associated with the given
640      * configuration key. If the key doesn't map to an existing object
641      * an empty array is returned.
642      *
643      * @param key The configuration key.
644      * @return The associated int array if the key is found.
645      *
646      * @throws ConversionException is thrown if the key maps to an
647      *         object that is not a list of integers.
648      */
649     public int[] getIntArray(String key)
650     {
651         return getIntArray(key, new int[0]);
652     }
653 
654     /***
655      * Get an array of int primitives associated with the given
656      * configuration key. If the key doesn't map to an existing object
657      * an empty array is returned.
658      *
659      * @param key The configuration key.
660      * @param defaultValue the default value, which will be returned if the property is not found
661      * @return The associated int array if the key is found.
662      *
663      * @throws ConversionException is thrown if the key maps to an
664      *         object that is not a list of integers.
665      */
666     public int[] getIntArray(String key, int[] defaultValue)
667     {
668         Object value = getProperty(key);
669 
670         int[] array;
671 
672         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
673         {
674             array = defaultValue;
675         }
676         else if (value instanceof int[])
677         {
678             array = (int[]) value;
679         }
680         else if (value instanceof Integer[])
681         {
682             array = ArrayUtils.toPrimitive((Integer[]) value);
683         }
684         else if (value instanceof Collection)
685         {
686             Collection values = (Collection) value;
687             array = new int[values.size()];
688 
689             int i = 0;
690             Iterator it = values.iterator();
691             while (it.hasNext())
692             {
693                 array[i++] = PropertyConverter.toInteger(interpolate(it.next())).intValue();
694             }
695         }
696         else
697         {
698             try
699             {
700                 // attempt to convert a single value
701                 array = new int[1];
702                 array[0] = PropertyConverter.toInteger(interpolate(value)).intValue();
703             }
704             catch (ConversionException e)
705             {
706                 throw new ConversionException('\'' + key + "' doesn't map to a list of integers", e);
707             }
708         }
709 
710         return array;
711     }
712 
713     /***
714      * Get a list of Long objects associated with the given configuration key.
715      * If the key doesn't map to an existing object an empty list is returned.
716      *
717      * @param key The configuration key.
718      * @return The associated Long list if the key is found.
719      *
720      * @throws ConversionException is thrown if the key maps to an
721      *         object that is not a list of longs.
722      */
723     public List getLongList(String key)
724     {
725         return getLongList(key, new ArrayList());
726     }
727 
728     /***
729      * Get a list of Long objects associated with the given configuration key.
730      * If the key doesn't map to an existing object, the default value is
731      * returned.
732      *
733      * @param key The configuration key.
734      * @param defaultValue The default value.
735      * @return The associated List of Longs.
736      *
737      * @throws ConversionException is thrown if the key maps to an
738      *         object that is not a list of longs.
739      */
740     public List getLongList(String key, List defaultValue)
741     {
742         Object value = getProperty(key);
743 
744         List list;
745 
746         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
747         {
748             list = defaultValue;
749         }
750         else if (value instanceof long[])
751         {
752             list = new ArrayList();
753             CollectionUtils.addAll(list, ArrayUtils.toObject((long[]) value));
754         }
755         else if (value instanceof Long[])
756         {
757             list = new ArrayList();
758             CollectionUtils.addAll(list, (Long[]) value);
759         }
760         else if (value instanceof Collection)
761         {
762             Collection values = (Collection) value;
763             list = new ArrayList();
764 
765             Iterator it = values.iterator();
766             while (it.hasNext())
767             {
768                 list.add(PropertyConverter.toLong(interpolate(it.next())));
769             }
770         }
771         else
772         {
773             try
774             {
775                 // attempt to convert a single value
776                 list = new ArrayList();
777                 list.add(PropertyConverter.toLong(interpolate(value)));
778             }
779             catch (ConversionException e)
780             {
781                 throw new ConversionException('\'' + key + "' doesn't map to a list of longs", e);
782             }
783         }
784 
785         return list;
786     }
787 
788     /***
789      * Get an array of long primitives associated with the given
790      * configuration key. If the key doesn't map to an existing object
791      * an empty array is returned.
792      *
793      * @param key The configuration key.
794      * @return The associated long array if the key is found.
795      *
796      * @throws ConversionException is thrown if the key maps to an
797      *         object that is not a list of longs.
798      */
799     public long[] getLongArray(String key)
800     {
801         return getLongArray(key, new long[0]);
802     }
803 
804     /***
805      * Get an array of long primitives associated with the given
806      * configuration key. If the key doesn't map to an existing object
807      * an empty array is returned.
808      *
809      * @param key The configuration key.
810      * @param defaultValue the default value, which will be returned if the property is not found
811      * @return The associated long array if the key is found.
812      *
813      * @throws ConversionException is thrown if the key maps to an
814      *         object that is not a list of longs.
815      */
816     public long[] getLongArray(String key, long[] defaultValue)
817     {
818         Object value = getProperty(key);
819 
820         long[] array;
821 
822         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
823         {
824             array = defaultValue;
825         }
826         else if (value instanceof long[])
827         {
828             array = (long[]) value;
829         }
830         else if (value instanceof Long[])
831         {
832             array = ArrayUtils.toPrimitive((Long[]) value);
833         }
834         else if (value instanceof Collection)
835         {
836             Collection values = (Collection) value;
837             array = new long[values.size()];
838 
839             int i = 0;
840             Iterator it = values.iterator();
841             while (it.hasNext())
842             {
843                 array[i++] = PropertyConverter.toLong(interpolate(it.next())).longValue();
844             }
845         }
846         else
847         {
848             try
849             {
850                 // attempt to convert a single value
851                 array = new long[1];
852                 array[0] = PropertyConverter.toLong(interpolate(value)).longValue();
853             }
854             catch (ConversionException e)
855             {
856                 throw new ConversionException('\'' + key + "' doesn't map to a list of longs", e);
857             }
858         }
859 
860         return array;
861     }
862 
863     /***
864      * Get a list of Float objects associated with the given configuration key.
865      * If the key doesn't map to an existing object an empty list is returned.
866      *
867      * @param key The configuration key.
868      * @return The associated Float list 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 floats.
872      */
873     public List getFloatList(String key)
874     {
875         return getFloatList(key, new ArrayList());
876     }
877 
878     /***
879      * Get a list of Float objects associated with the given
880      * configuration key. If the key doesn't map to an existing object,
881      * the default value is returned.
882      *
883      * @param key The configuration key.
884      * @param defaultValue The default value.
885      * @return The associated List of Floats.
886      *
887      * @throws ConversionException is thrown if the key maps to an
888      *         object that is not a list of floats.
889      */
890     public List getFloatList(String key, List defaultValue)
891     {
892         Object value = getProperty(key);
893 
894         List list;
895 
896         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
897         {
898             list = defaultValue;
899         }
900         else if (value instanceof float[])
901         {
902             list = new ArrayList();
903             CollectionUtils.addAll(list, ArrayUtils.toObject((float[]) value));
904         }
905         else if (value instanceof Float[])
906         {
907             list = new ArrayList();
908             CollectionUtils.addAll(list, (Float[]) value);
909         }
910         else if (value instanceof Collection)
911         {
912             Collection values = (Collection) value;
913             list = new ArrayList();
914 
915             Iterator it = values.iterator();
916             while (it.hasNext())
917             {
918                 list.add(PropertyConverter.toFloat(interpolate(it.next())));
919             }
920         }
921         else
922         {
923             try
924             {
925                 // attempt to convert a single value
926                 list = new ArrayList();
927                 list.add(PropertyConverter.toFloat(interpolate(value)));
928             }
929             catch (ConversionException e)
930             {
931                 throw new ConversionException('\'' + key + "' doesn't map to a list of floats", e);
932             }
933         }
934 
935         return list;
936     }
937 
938     /***
939      * Get an array of float primitives associated with the given
940      * configuration key. If the key doesn't map to an existing object
941      * an empty array is returned.
942      *
943      * @param key The configuration key.
944      * @return The associated float array if the key is found.
945      *
946      * @throws ConversionException is thrown if the key maps to an
947      *         object that is not a list of floats.
948      */
949     public float[] getFloatArray(String key)
950     {
951         return getFloatArray(key, new float[0]);
952     }
953 
954     /***
955      * Get an array of float primitives associated with the given
956      * configuration key. If the key doesn't map to an existing object
957      * an empty array is returned.
958      *
959      * @param key The configuration key.
960      * @param defaultValue the default value, which will be returned if the property is not found
961      * @return The associated float array if the key is found.
962      *
963      * @throws ConversionException is thrown if the key maps to an
964      *         object that is not a list of floats.
965      */
966     public float[] getFloatArray(String key, float[] defaultValue)
967     {
968         Object value = getProperty(key);
969 
970         float[] array;
971 
972         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
973         {
974             array = defaultValue;
975         }
976         else if (value instanceof float[])
977         {
978             array = (float[]) value;
979         }
980         else if (value instanceof Float[])
981         {
982             array = ArrayUtils.toPrimitive((Float[]) value);
983         }
984         else if (value instanceof Collection)
985         {
986             Collection values = (Collection) value;
987             array = new float[values.size()];
988 
989             int i = 0;
990             Iterator it = values.iterator();
991             while (it.hasNext())
992             {
993                 array[i++] = PropertyConverter.toFloat(interpolate(it.next())).floatValue();
994             }
995         }
996         else
997         {
998             try
999             {
1000                 // attempt to convert a single value
1001                 array = new float[1];
1002                 array[0] = PropertyConverter.toFloat(interpolate(value)).floatValue();
1003             }
1004             catch (ConversionException e)
1005             {
1006                 throw new ConversionException('\'' + key + "' doesn't map to a list of floats", e);
1007             }
1008         }
1009 
1010         return array;
1011     }
1012 
1013     /***
1014      * Get a list of Double objects associated with the given
1015      * configuration key. If the key doesn't map to an existing object
1016      * an empty list is returned.
1017      *
1018      * @param key The configuration key.
1019      * @return The associated Double list if the key is found.
1020      *
1021      * @throws ConversionException is thrown if the key maps to an
1022      *         object that is not a list of doubles.
1023      */
1024     public List getDoubleList(String key)
1025     {
1026         return getDoubleList(key, new ArrayList());
1027     }
1028 
1029     /***
1030      * Get a list of Double objects associated with the given
1031      * configuration key. If the key doesn't map to an existing object,
1032      * the default value is returned.
1033      *
1034      * @param key The configuration key.
1035      * @param defaultValue The default value.
1036      * @return The associated List of Doubles.
1037      *
1038      * @throws ConversionException is thrown if the key maps to an
1039      *         object that is not a list of doubles.
1040      */
1041     public List getDoubleList(String key, List defaultValue)
1042     {
1043         Object value = getProperty(key);
1044 
1045         List list;
1046 
1047         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1048         {
1049             list = defaultValue;
1050         }
1051         else if (value instanceof double[])
1052         {
1053             list = new ArrayList();
1054             CollectionUtils.addAll(list, ArrayUtils.toObject((double[]) value));
1055         }
1056         else if (value instanceof Double[])
1057         {
1058             list = new ArrayList();
1059             CollectionUtils.addAll(list, (Double[]) value);
1060         }
1061         else if (value instanceof Collection)
1062         {
1063             Collection values = (Collection) value;
1064             list = new ArrayList();
1065 
1066             Iterator it = values.iterator();
1067             while (it.hasNext())
1068             {
1069                 list.add(PropertyConverter.toDouble(interpolate(it.next())));
1070             }
1071         }
1072         else
1073         {
1074             try
1075             {
1076                 // attempt to convert a single value
1077                 list = new ArrayList();
1078                 list.add(PropertyConverter.toDouble(interpolate(value)));
1079             }
1080             catch (ConversionException e)
1081             {
1082                 throw new ConversionException('\'' + key + "' doesn't map to a list of doubles", e);
1083             }
1084         }
1085 
1086         return list;
1087     }
1088 
1089     /***
1090      * Get an array of double primitives associated with the given
1091      * configuration key. If the key doesn't map to an existing object
1092      * an empty array is returned.
1093      *
1094      * @param key The configuration key.
1095      * @return The associated double array if the key is found.
1096      *
1097      * @throws ConversionException is thrown if the key maps to an
1098      *         object that is not a list of doubles.
1099      */
1100     public double[] getDoubleArray(String key)
1101     {
1102         return getDoubleArray(key, new double[0]);
1103     }
1104 
1105     /***
1106      * Get an array of double primitives associated with the given
1107      * configuration key. If the key doesn't map to an existing object
1108      * an empty array is returned.
1109      *
1110      * @param key The configuration key.
1111      * @param defaultValue the default value, which will be returned if the property is not found
1112      * @return The associated double array if the key is found.
1113      *
1114      * @throws ConversionException is thrown if the key maps to an
1115      *         object that is not a list of doubles.
1116      */
1117     public double[] getDoubleArray(String key, double[] defaultValue)
1118     {
1119         Object value = getProperty(key);
1120 
1121         double[] array;
1122 
1123         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1124         {
1125             array = defaultValue;
1126         }
1127         else if (value instanceof double[])
1128         {
1129             array = (double[]) value;
1130         }
1131         else if (value instanceof Double[])
1132         {
1133             array = ArrayUtils.toPrimitive((Double[]) value);
1134         }
1135         else if (value instanceof Collection)
1136         {
1137             Collection values = (Collection) value;
1138             array = new double[values.size()];
1139 
1140             int i = 0;
1141             Iterator it = values.iterator();
1142             while (it.hasNext())
1143             {
1144                 array[i++] = PropertyConverter.toDouble(interpolate(it.next())).doubleValue();
1145             }
1146         }
1147         else
1148         {
1149             try
1150             {
1151                 // attempt to convert a single value
1152                 array = new double[1];
1153                 array[0] = PropertyConverter.toDouble(interpolate(value)).doubleValue();
1154             }
1155             catch (ConversionException e)
1156             {
1157                 throw new ConversionException('\'' + key + "' doesn't map to a list of doubles", e);
1158             }
1159         }
1160 
1161         return array;
1162     }
1163 
1164     /***
1165      * Get a list of BigIntegers associated with the given configuration key.
1166      * If the key doesn't map to an existing object an empty list is returned.
1167      *
1168      * @param key The configuration key.
1169      * @return The associated BigInteger list if the key is found.
1170      *
1171      * @throws ConversionException is thrown if the key maps to an
1172      *         object that is not a list of BigIntegers.
1173      */
1174     public List getBigIntegerList(String key)
1175     {
1176         return getBigIntegerList(key, new ArrayList());
1177     }
1178 
1179     /***
1180      * Get a list of BigIntegers associated with the given configuration key.
1181      * If the key doesn't map to an existing object, the default value is
1182      * returned.
1183      *
1184      * @param key The configuration key.
1185      * @param defaultValue The default value.
1186      * @return The associated List of BigIntegers.
1187      *
1188      * @throws ConversionException is thrown if the key maps to an
1189      *         object that is not a list of BigIntegers.
1190      */
1191     public List getBigIntegerList(String key, List defaultValue)
1192     {
1193         Object value = getProperty(key);
1194 
1195         List list;
1196 
1197         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1198         {
1199             list = defaultValue;
1200         }
1201         else if (value instanceof BigInteger[])
1202         {
1203             list = new ArrayList();
1204             CollectionUtils.addAll(list, (BigInteger[]) value);
1205         }
1206         else if (value instanceof Collection)
1207         {
1208             Collection values = (Collection) value;
1209             list = new ArrayList();
1210 
1211             Iterator it = values.iterator();
1212             while (it.hasNext())
1213             {
1214                 list.add(PropertyConverter.toBigInteger(interpolate(it.next())));
1215             }
1216         }
1217         else
1218         {
1219             try
1220             {
1221                 // attempt to convert a single value
1222                 list = new ArrayList();
1223                 list.add(PropertyConverter.toBigInteger(interpolate(value)));
1224             }
1225             catch (ConversionException e)
1226             {
1227                 throw new ConversionException('\'' + key + "' doesn't map to a list of big integers", e);
1228             }
1229         }
1230 
1231         return list;
1232     }
1233 
1234     /***
1235      * Get an array of BigIntegers associated with the given
1236      * configuration key. If the key doesn't map to an existing object
1237      * an empty array is returned.
1238      *
1239      * @param key The configuration key.
1240      * @return The associated BigInteger array if the key is found.
1241      *
1242      * @throws ConversionException is thrown if the key maps to an
1243      *         object that is not a list of BigIntegers.
1244      */
1245     public BigInteger[] getBigIntegerArray(String key)
1246     {
1247         return getBigIntegerArray(key, new BigInteger[0]);
1248     }
1249 
1250     /***
1251      * Get an array of BigIntegers associated with the given
1252      * configuration key. If the key doesn't map to an existing object
1253      * an empty array is returned.
1254      *
1255      * @param key The configuration key.
1256      * @param defaultValue the default value, which will be returned if the property is not found
1257      * @return The associated BigInteger array if the key is found.
1258      *
1259      * @throws ConversionException is thrown if the key maps to an
1260      *         object that is not a list of BigIntegers.
1261      */
1262     public BigInteger[] getBigIntegerArray(String key, BigInteger[] defaultValue)
1263     {
1264         List list = getBigIntegerList(key);
1265         if (list.isEmpty())
1266         {
1267             return defaultValue;
1268         }
1269         else
1270         {
1271             return (BigInteger[]) list.toArray(new BigInteger[list.size()]);
1272         }
1273     }
1274 
1275     /***
1276      * Get a list of BigDecimals associated with the given configuration key.
1277      * If the key doesn't map to an existing object an empty list is returned.
1278      *
1279      * @param key The configuration key.
1280      * @return The associated BigDecimal list if the key is found.
1281      *
1282      * @throws ConversionException is thrown if the key maps to an
1283      *         object that is not a list of BigDecimals.
1284      */
1285     public List getBigDecimalList(String key)
1286     {
1287         return getBigDecimalList(key, new ArrayList());
1288     }
1289 
1290     /***
1291      * Get a list of BigDecimals associated with the given configuration key.
1292      * If the key doesn't map to an existing object, the default value is
1293      * returned.
1294      *
1295      * @param key The configuration key.
1296      * @param defaultValue The default value.
1297      * @return The associated List of BigDecimals.
1298      *
1299      * @throws ConversionException is thrown if the key maps to an
1300      *         object that is not a list of BigDecimals.
1301      */
1302     public List getBigDecimalList(String key, List defaultValue)
1303     {
1304         Object value = getProperty(key);
1305 
1306         List list;
1307 
1308         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1309         {
1310             list = defaultValue;
1311         }
1312         else if (value instanceof BigDecimal[])
1313         {
1314             list = new ArrayList();
1315             CollectionUtils.addAll(list, (BigDecimal[]) value);
1316         }
1317         else if (value instanceof Collection)
1318         {
1319             Collection values = (Collection) value;
1320             list = new ArrayList();
1321 
1322             Iterator it = values.iterator();
1323             while (it.hasNext())
1324             {
1325                 list.add(PropertyConverter.toBigDecimal(interpolate(it.next())));
1326             }
1327         }
1328         else
1329         {
1330             try
1331             {
1332                 // attempt to convert a single value
1333                 list = new ArrayList();
1334                 list.add(PropertyConverter.toBigDecimal(interpolate(value)));
1335             }
1336             catch (ConversionException e)
1337             {
1338                 throw new ConversionException('\'' + key + "' doesn't map to a list of big decimals", e);
1339             }
1340         }
1341 
1342         return list;
1343     }
1344 
1345     /***
1346      * Get an array of BigDecimals associated with the given
1347      * configuration key. If the key doesn't map to an existing object
1348      * an empty array is returned.
1349      *
1350      * @param key The configuration key.
1351      * @return The associated BigDecimal array if the key is found.
1352      *
1353      * @throws ConversionException is thrown if the key maps to an
1354      *         object that is not a list of BigDecimals.
1355      */
1356     public BigDecimal[] getBigDecimalArray(String key)
1357     {
1358         return getBigDecimalArray(key, new BigDecimal[0]);
1359     }
1360 
1361     /***
1362      * Get an array of BigDecimals associated with the given
1363      * configuration key. If the key doesn't map to an existing object
1364      * an empty array is returned.
1365      *
1366      * @param key The configuration key.
1367      * @param defaultValue the default value, which will be returned if the property is not found
1368      * @return The associated BigDecimal array if the key is found.
1369      *
1370      * @throws ConversionException is thrown if the key maps to an
1371      *         object that is not a list of BigDecimals.
1372      */
1373     public BigDecimal[] getBigDecimalArray(String key, BigDecimal[] defaultValue)
1374     {
1375         List list = getBigDecimalList(key);
1376         if (list.isEmpty())
1377         {
1378             return defaultValue;
1379         }
1380         else
1381         {
1382             return (BigDecimal[]) list.toArray(new BigDecimal[list.size()]);
1383         }
1384     }
1385 
1386     /***
1387      * Get an URL associated with the given configuration key.
1388      *
1389      * @param key The configuration key.
1390      * @return The associated URL.
1391      *
1392      * @throws ConversionException is thrown if the key maps to an
1393      *         object that is not an URL.
1394      */
1395     public URL getURL(String key)
1396     {
1397         return getURL(key, null);
1398     }
1399 
1400     /***
1401      * Get an URL associated with the given configuration key.
1402      * If the key doesn't map to an existing object, the default value
1403      * is returned.
1404      *
1405      * @param key          The configuration key.
1406      * @param defaultValue The default value.
1407      * @return The associated URL.
1408      *
1409      * @throws ConversionException is thrown if the key maps to an
1410      *         object that is not an URL.
1411      */
1412     public URL getURL(String key, URL defaultValue)
1413     {
1414         Object value = resolveContainerStore(key);
1415 
1416         if (value == null)
1417         {
1418             return defaultValue;
1419         }
1420         else
1421         {
1422             try
1423             {
1424                 return PropertyConverter.toURL(interpolate(value));
1425             }
1426             catch (ConversionException e)
1427             {
1428                 throw new ConversionException('\'' + key + "' doesn't map to an URL", e);
1429             }
1430         }
1431     }
1432 
1433     /***
1434      * Get a list of URLs associated with the given configuration key.
1435      * If the key doesn't map to an existing object an empty list is returned.
1436      *
1437      * @param key The configuration key.
1438      * @return The associated URL list if the key is found.
1439      *
1440      * @throws ConversionException is thrown if the key maps to an
1441      *         object that is not a list of URLs.
1442      */
1443     public List getURLList(String key)
1444     {
1445         return getURLList(key, new ArrayList());
1446     }
1447 
1448     /***
1449      * Get a list of URLs associated with the given configuration key.
1450      * If the key doesn't map to an existing object, the default value is
1451      * returned.
1452      *
1453      * @param key The configuration key.
1454      * @param defaultValue The default value.
1455      * @return The associated List of URLs.
1456      *
1457      * @throws ConversionException is thrown if the key maps to an
1458      *         object that is not a list of URLs.
1459      */
1460     public List getURLList(String key, List defaultValue)
1461     {
1462         Object value = getProperty(key);
1463 
1464         List list;
1465 
1466         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1467         {
1468             list = defaultValue;
1469         }
1470         else if (value instanceof URL[])
1471         {
1472             list = new ArrayList();
1473             CollectionUtils.addAll(list, (URL[]) value);
1474         }
1475         else if (value instanceof Collection)
1476         {
1477             Collection values = (Collection) value;
1478             list = new ArrayList();
1479 
1480             Iterator it = values.iterator();
1481             while (it.hasNext())
1482             {
1483                 list.add(PropertyConverter.toURL(interpolate(it.next())));
1484             }
1485         }
1486         else
1487         {
1488             try
1489             {
1490                 // attempt to convert a single value
1491                 list = new ArrayList();
1492                 list.add(PropertyConverter.toURL(interpolate(value)));
1493             }
1494             catch (ConversionException e)
1495             {
1496                 throw new ConversionException('\'' + key + "' doesn't map to a list of URLs", e);
1497             }
1498         }
1499 
1500         return list;
1501     }
1502 
1503     /***
1504      * Get an array of URLs associated with the given configuration key.
1505      * If the key doesn't map to an existing object an empty array is returned.
1506      *
1507      * @param key The configuration key.
1508      * @return The associated URL array if the key is found.
1509      *
1510      * @throws ConversionException is thrown if the key maps to an
1511      *         object that is not a list of URLs.
1512      */
1513     public URL[] getURLArray(String key)
1514     {
1515         return getURLArray(key, new URL[0]);
1516     }
1517 
1518     /***
1519      * Get an array of URLs associated with the given configuration key.
1520      * If the key doesn't map to an existing object an empty array is returned.
1521      *
1522      * @param key The configuration key.
1523      * @param defaultValue the default value, which will be returned if the property is not found
1524      * @return The associated URL array if the key is found.
1525      *
1526      * @throws ConversionException is thrown if the key maps to an
1527      *         object that is not a list of URLs.
1528      */
1529     public URL[] getURLArray(String key, URL[] defaultValue)
1530     {
1531         List list = getURLList(key);
1532         if (list.isEmpty())
1533         {
1534             return defaultValue;
1535         }
1536         else
1537         {
1538             return (URL[]) list.toArray(new URL[list.size()]);
1539         }
1540     }
1541 
1542     /***
1543      * Get a Date associated with the given configuration key. If the property
1544      * is a String, it will be parsed with the format defined by the user in
1545      * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
1546      * {@link #DEFAULT_DATE_FORMAT} pattern.
1547      *
1548      * @param key The configuration key.
1549      * @return The associated Date.
1550      *
1551      * @throws ConversionException is thrown if the key maps to an
1552      *         object that is not a Date.
1553      */
1554     public Date getDate(String key)
1555     {
1556         return getDate(key, getDefaultDateFormat());
1557     }
1558 
1559     /***
1560      * Get a Date associated with the given configuration key. If the property
1561      * is a String, it will be parsed with the specified format pattern.
1562      *
1563      * @param key    The configuration key.
1564      * @param format The non-localized {@link java.text.DateFormat} pattern.
1565      * @return The associated Date
1566      *
1567      * @throws ConversionException is thrown if the key maps to an
1568      *         object that is not a Date.
1569      */
1570     public Date getDate(String key, String format)
1571     {
1572         return getDate(key, null, format);
1573     }
1574 
1575     /***
1576      * Get a Date associated with the given configuration key. If the property
1577      * is a String, it will be parsed with the format defined by the user in
1578      * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
1579      * {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map to an
1580      * existing object, the default value is returned.
1581      *
1582      * @param key          The configuration key.
1583      * @param defaultValue The default value.
1584      * @return The associated Date.
1585      *
1586      * @throws ConversionException is thrown if the key maps to an
1587      *         object that is not a Date.
1588      */
1589     public Date getDate(String key, Date defaultValue)
1590     {
1591         return getDate(key, defaultValue, getDefaultDateFormat());
1592     }
1593 
1594     /***
1595      * Get a Date associated with the given configuration key. If the property
1596      * is a String, it will be parsed with the specified format pattern.
1597      * If the key doesn't map to an existing object, the default value
1598      * is returned.
1599      *
1600      * @param key          The configuration key.
1601      * @param defaultValue The default value.
1602      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1603      * @return The associated Date.
1604      *
1605      * @throws ConversionException is thrown if the key maps to an
1606      *         object that is not a Date.
1607      */
1608     public Date getDate(String key, Date defaultValue, String format)
1609     {
1610         Object value = resolveContainerStore(key);
1611 
1612         if (value == null)
1613         {
1614             return defaultValue;
1615         }
1616         else
1617         {
1618             try
1619             {
1620                 return PropertyConverter.toDate(interpolate(value), format);
1621             }
1622             catch (ConversionException e)
1623             {
1624                 throw new ConversionException('\'' + key + "' doesn't map to a Date", e);
1625             }
1626         }
1627     }
1628 
1629     /***
1630      * Get a list of Dates associated with the given configuration key.
1631      * If the property is a list of Strings, they will be parsed with the
1632      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1633      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1634      * If the key doesn't map to an existing object an empty list is returned.
1635      *
1636      * @param key The configuration key.
1637      * @return The associated Date list if the key is found.
1638      *
1639      * @throws ConversionException is thrown if the key maps to an
1640      *         object that is not a list of Dates.
1641      */
1642     public List getDateList(String key)
1643     {
1644         return getDateList(key, new ArrayList());
1645     }
1646 
1647     /***
1648      * Get a list of Dates associated with the given configuration key.
1649      * If the property is a list of Strings, they will be parsed with the
1650      * specified format pattern. If the key doesn't map to an existing object
1651      * an empty list is returned.
1652      *
1653      * @param key    The configuration key.
1654      * @param format The non-localized {@link java.text.DateFormat} pattern.
1655      * @return The associated Date list if the key is found.
1656      *
1657      * @throws ConversionException is thrown if the key maps to an
1658      *         object that is not a list of Dates.
1659      */
1660     public List getDateList(String key, String format)
1661     {
1662         return getDateList(key, new ArrayList(), format);
1663     }
1664 
1665     /***
1666      * Get a list of Dates associated with the given configuration key.
1667      * If the property is a list of Strings, they will be parsed with the
1668      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1669      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1670      * If the key doesn't map to an existing object, the default value is
1671      * returned.
1672      *
1673      * @param key          The configuration key.
1674      * @param defaultValue The default value.
1675      * @return The associated Date list if the key is found.
1676      *
1677      * @throws ConversionException is thrown if the key maps to an
1678      *         object that is not a list of Dates.
1679      */
1680     public List getDateList(String key, List defaultValue)
1681     {
1682         return getDateList(key, defaultValue, getDefaultDateFormat());
1683     }
1684 
1685     /***
1686      * Get a list of Dates associated with the given configuration key.
1687      * If the property is a list of Strings, they will be parsed with the
1688      * specified format pattern. If the key doesn't map to an existing object,
1689      * the default value is returned.
1690      *
1691      * @param key          The configuration key.
1692      * @param defaultValue The default value.
1693      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1694      * @return The associated Date list if the key is found.
1695      *
1696      * @throws ConversionException is thrown if the key maps to an
1697      *         object that is not a list of Dates.
1698      */
1699     public List getDateList(String key, List defaultValue, String format)
1700     {
1701         Object value = getProperty(key);
1702 
1703         List list;
1704 
1705         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1706         {
1707             list = defaultValue;
1708         }
1709         else if (value instanceof Date[])
1710         {
1711             list = new ArrayList();
1712             CollectionUtils.addAll(list, (Date[]) value);
1713         }
1714         else if (value instanceof Calendar[])
1715         {
1716             list = new ArrayList();
1717             Calendar[] values = (Calendar[]) value;
1718 
1719             for (int i = 0; i < values.length; i++)
1720             {
1721                 list.add(values[i].getTime());
1722             }
1723         }
1724         else if (value instanceof Collection)
1725         {
1726             Collection values = (Collection) value;
1727             list = new ArrayList();
1728 
1729             Iterator it = values.iterator();
1730             while (it.hasNext())
1731             {
1732                 list.add(PropertyConverter.toDate(interpolate(it.next()), format));
1733             }
1734         }
1735         else
1736         {
1737             try
1738             {
1739                 // attempt to convert a single value
1740                 list = new ArrayList();
1741                 list.add(PropertyConverter.toDate(interpolate(value), format));
1742             }
1743             catch (ConversionException e)
1744             {
1745                 throw new ConversionException('\'' + key + "' doesn't map to a list of Dates", e);
1746             }
1747         }
1748 
1749         return list;
1750     }
1751 
1752     /***
1753      * Get an array of Dates associated with the given configuration key.
1754      * If the property is a list of Strings, they will be parsed with the
1755      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1756      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1757      * If the key doesn't map to an existing object an empty array is returned.
1758      *
1759      * @param key The configuration key.
1760      * @return The associated Date array if the key is found.
1761      *
1762      * @throws ConversionException is thrown if the key maps to an
1763      *         object that is not a list of Dates.
1764      */
1765     public Date[] getDateArray(String key)
1766     {
1767         return getDateArray(key, new Date[0]);
1768     }
1769 
1770     /***
1771      * Get an array of Dates associated with the given configuration key.
1772      * If the property is a list of Strings, they will be parsed with the
1773      * specified format pattern. If the key doesn't map to an existing object
1774      * an empty array is returned.
1775      *
1776      * @param key    The configuration key.
1777      * @param format The non-localized {@link java.text.DateFormat} pattern.
1778      * @return The associated Date array if the key is found.
1779      *
1780      * @throws ConversionException is thrown if the key maps to an
1781      *         object that is not a list of Dates.
1782      */
1783     public Date[] getDateArray(String key, String format)
1784     {
1785         return getDateArray(key, new Date[0], format);
1786     }
1787 
1788     /***
1789      * Get an array of Dates associated with the given configuration key.
1790      * If the property is a list of Strings, they will be parsed with the
1791      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1792      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1793      * If the key doesn't map to an existing object an empty array is returned.
1794      *
1795      * @param key The configuration key.
1796      * @param defaultValue the default value, which will be returned if the property is not found
1797      * @return The associated Date array if the key is found.
1798      *
1799      * @throws ConversionException is thrown if the key maps to an
1800      *         object that is not a list of Dates.
1801      */
1802     public Date[] getDateArray(String key, Date[] defaultValue)
1803     {
1804         return getDateArray(key, defaultValue, getDefaultDateFormat());
1805     }
1806 
1807     /***
1808      * Get an array of Dates associated with the given configuration key.
1809      * If the property is a list of Strings, they will be parsed with the
1810      * specified format pattern. If the key doesn't map to an existing object,
1811      * the default value is returned.
1812      *
1813      * @param key          The configuration key.
1814      * @param defaultValue The default value.
1815      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1816      * @return The associated Date array if the key is found.
1817      *
1818      * @throws ConversionException is thrown if the key maps to an
1819      *         object that is not a list of Dates.
1820      */
1821     public Date[] getDateArray(String key, Date[] defaultValue, String format)
1822     {
1823         List list = getDateList(key);
1824         if (list.isEmpty())
1825         {
1826             return defaultValue;
1827         }
1828         else
1829         {
1830             return (Date[]) list.toArray(new Date[list.size()]);
1831         }
1832     }
1833 
1834     /***
1835      * Get a Calendar associated with the given configuration key. If the
1836      * property is a String, it will be parsed with the format defined by the
1837      * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
1838      * with the {@link #DEFAULT_DATE_FORMAT} pattern.
1839      *
1840      * @param key The configuration key.
1841      * @return The associated Calendar.
1842      *
1843      * @throws ConversionException is thrown if the key maps to an
1844      *         object that is not a Calendar.
1845      */
1846     public Calendar getCalendar(String key)
1847     {
1848         return getCalendar(key, getDefaultDateFormat());
1849     }
1850 
1851     /***
1852      * Get a Calendar associated with the given configuration key. If the
1853      * property is a String, it will be parsed with the specified format
1854      * pattern.
1855      *
1856      * @param key    The configuration key.
1857      * @param format The non-localized {@link java.text.DateFormat} pattern.
1858      * @return The associated Calendar
1859      *
1860      * @throws ConversionException is thrown if the key maps to an
1861      *         object that is not a Calendar.
1862      */
1863     public Calendar getCalendar(String key, String format)
1864     {
1865         return getCalendar(key, null, format);
1866     }
1867 
1868     /***
1869      * Get a Calendar associated with the given configuration key. If the
1870      * property is a String, it will be parsed with the format defined by the
1871      * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
1872      * with the {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map
1873      * to an existing object, the default value is returned.
1874      *
1875      * @param key          The configuration key.
1876      * @param defaultValue The default value.
1877      * @return The associated Calendar.
1878      *
1879      * @throws ConversionException is thrown if the key maps to an
1880      *         object that is not a Calendar.
1881      */
1882     public Calendar getCalendar(String key, Calendar defaultValue)
1883     {
1884         return getCalendar(key, defaultValue, getDefaultDateFormat());
1885     }
1886 
1887     /***
1888      * Get a Calendar associated with the given configuration key. If the
1889      * property is a String, it will be parsed with the specified format
1890      * pattern. If the key doesn't map to an existing object, the default
1891      * value is returned.
1892      *
1893      * @param key          The configuration key.
1894      * @param defaultValue The default value.
1895      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1896      * @return The associated Calendar.
1897      *
1898      * @throws ConversionException is thrown if the key maps to an
1899      *         object that is not a Calendar.
1900      */
1901     public Calendar getCalendar(String key, Calendar defaultValue, String format)
1902     {
1903         Object value = resolveContainerStore(key);
1904 
1905         if (value == null)
1906         {
1907             return defaultValue;
1908         }
1909         else
1910         {
1911             try
1912             {
1913                 return PropertyConverter.toCalendar(interpolate(value), format);
1914             }
1915             catch (ConversionException e)
1916             {
1917                 throw new ConversionException('\'' + key + "' doesn't map to a Calendar", e);
1918             }
1919         }
1920     }
1921 
1922     /***
1923      * Get a list of Calendars associated with the given configuration key.
1924      * If the property is a list of Strings, they will be parsed with the
1925      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1926      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1927      * If the key doesn't map to an existing object an empty list is returned.
1928      *
1929      * @param key The configuration key.
1930      * @return The associated Calendar list if the key is found.
1931      *
1932      * @throws ConversionException is thrown if the key maps to an
1933      *         object that is not a list of Calendars.
1934      */
1935     public List getCalendarList(String key)
1936     {
1937         return getCalendarList(key, new ArrayList());
1938     }
1939 
1940     /***
1941      * Get a list of Calendars associated with the given configuration key.
1942      * If the property is a list of Strings, they will be parsed with the
1943      * specified format pattern. If the key doesn't map to an existing object
1944      * an empty list is returned.
1945      *
1946      * @param key    The configuration key.
1947      * @param format The non-localized {@link java.text.DateFormat} pattern.
1948      * @return The associated Calendar list if the key is found.
1949      *
1950      * @throws ConversionException is thrown if the key maps to an
1951      *         object that is not a list of Calendars.
1952      */
1953     public List getCalendarList(String key, String format)
1954     {
1955         return getCalendarList(key, new ArrayList(), format);
1956     }
1957 
1958     /***
1959      * Get a list of Calendars associated with the given configuration key.
1960      * If the property is a list of Strings, they will be parsed with the
1961      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
1962      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
1963      * If the key doesn't map to an existing object, the default value is
1964      * returned.
1965      *
1966      * @param key The configuration key.
1967      * @param defaultValue The default value.
1968      * @return The associated Calendar list if the key is found.
1969      *
1970      * @throws ConversionException is thrown if the key maps to an
1971      *         object that is not a list of Calendars.
1972      */
1973     public List getCalendarList(String key, List defaultValue)
1974     {
1975         return getCalendarList(key, defaultValue, getDefaultDateFormat());
1976     }
1977 
1978     /***
1979      * Get a list of Calendars associated with the given configuration key.
1980      * If the property is a list of Strings, they will be parsed with the
1981      * specified format pattern. If the key doesn't map to an existing object,
1982      * the default value is returned.
1983      *
1984      * @param key          The configuration key.
1985      * @param defaultValue The default value.
1986      * @param format       The non-localized {@link java.text.DateFormat} pattern.
1987      * @return The associated Calendar list if the key is found.
1988      *
1989      * @throws ConversionException is thrown if the key maps to an
1990      *         object that is not a list of Calendars.
1991      */
1992     public List getCalendarList(String key, List defaultValue, String format)
1993     {
1994         Object value = getProperty(key);
1995 
1996         List list;
1997 
1998         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
1999         {
2000             list = defaultValue;
2001         }
2002         else if (value instanceof Calendar[])
2003         {
2004             list = new ArrayList();
2005             CollectionUtils.addAll(list, (Calendar[]) value);
2006         }
2007         else if (value instanceof Date[])
2008         {
2009             list = new ArrayList();
2010             Date[] values = (Date[]) value;
2011 
2012             for (int i = 0; i < values.length; i++)
2013             {
2014                 Calendar calendar = Calendar.getInstance();
2015                 calendar.setTime(values[i]);
2016                 list.add(calendar);
2017             }
2018         }
2019         else if (value instanceof Collection)
2020         {
2021             Collection values = (Collection) value;
2022             list = new ArrayList();
2023 
2024             Iterator it = values.iterator();
2025             while (it.hasNext())
2026             {
2027                 list.add(PropertyConverter.toCalendar(interpolate(it.next()), format));
2028             }
2029         }
2030         else
2031         {
2032             try
2033             {
2034                 // attempt to convert a single value
2035                 list = new ArrayList();
2036                 list.add(PropertyConverter.toCalendar(interpolate(value), format));
2037             }
2038             catch (ConversionException e)
2039             {
2040                 throw new ConversionException('\'' + key + "' doesn't map to a list of Calendars", e);
2041             }
2042         }
2043 
2044         return list;
2045     }
2046 
2047     /***
2048      * Get an array of Calendars associated with the given configuration key.
2049      * If the property is a list of Strings, they will be parsed with the
2050      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
2051      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
2052      * If the key doesn't map to an existing object an empty array is returned.
2053      *
2054      * @param key The configuration key.
2055      * @return The associated Calendar array if the key is found.
2056      *
2057      * @throws ConversionException is thrown if the key maps to an
2058      *         object that is not a list of Calendars.
2059      */
2060     public Calendar[] getCalendarArray(String key)
2061     {
2062         return getCalendarArray(key, new Calendar[0]);
2063     }
2064 
2065     /***
2066      * Get an array of Calendars associated with the given configuration key.
2067      * If the property is a list of Strings, they will be parsed with the
2068      * specified format pattern. If the key doesn't map to an existing object
2069      * an empty array is returned.
2070      *
2071      * @param key    The configuration key.
2072      * @param format The non-localized {@link java.text.DateFormat} pattern.
2073      * @return The associated Calendar array if the key is found.
2074      *
2075      * @throws ConversionException is thrown if the key maps to an
2076      *         object that is not a list of Calendars.
2077      */
2078     public Calendar[] getCalendarArray(String key, String format)
2079     {
2080         return getCalendarArray(key, new Calendar[0], format);
2081     }
2082 
2083     /***
2084      * Get an array of Calendars associated with the given configuration key.
2085      * If the property is a list of Strings, they will be parsed with the
2086      * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
2087      * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
2088      * If the key doesn't map to an existing object an empty array is returned.
2089      *
2090      * @param key The configuration key.
2091      * @param defaultValue the default value, which will be returned if the property is not found
2092      * @return The associated Calendar array if the key is found.
2093      *
2094      * @throws ConversionException is thrown if the key maps to an
2095      *         object that is not a list of Calendars.
2096      */
2097     public Calendar[] getCalendarArray(String key, Calendar[] defaultValue)
2098     {
2099         return getCalendarArray(key, defaultValue, getDefaultDateFormat());
2100     }
2101 
2102     /***
2103      * Get an array of Calendars associated with the given configuration key.
2104      * If the property is a list of Strings, they will be parsed with the
2105      * specified format pattern. If the key doesn't map to an existing object,
2106      * the default value is returned.
2107      *
2108      * @param key          The configuration key.
2109      * @param defaultValue The default value.
2110      * @param format       The non-localized {@link java.text.DateFormat} pattern.
2111      * @return The associated Calendar array if the key is found.
2112      *
2113      * @throws ConversionException is thrown if the key maps to an
2114      *         object that is not a list of Calendars.
2115      */
2116     public Calendar[] getCalendarArray(String key, Calendar[] defaultValue, String format)
2117     {
2118         List list = getCalendarList(key, format);
2119         if (list.isEmpty())
2120         {
2121             return defaultValue;
2122         }
2123         else
2124         {
2125             return (Calendar[]) list.toArray(new Calendar[list.size()]);
2126         }
2127     }
2128 
2129     /***
2130      * Returns the date format specified by the user in the DATE_FORMAT_KEY
2131      * property, or the default format otherwise.
2132      *
2133      * @return the default date format
2134      */
2135     private String getDefaultDateFormat()
2136     {
2137         return getString(DATE_FORMAT_KEY, DEFAULT_DATE_FORMAT);
2138     }
2139 
2140     /***
2141      * Get a Locale associated with the given configuration key.
2142      *
2143      * @param key The configuration key.
2144      * @return The associated Locale.
2145      *
2146      * @throws ConversionException is thrown if the key maps to an
2147      *         object that is not a Locale.
2148      */
2149     public Locale getLocale(String key)
2150     {
2151         return getLocale(key, null);
2152     }
2153 
2154     /***
2155      * Get a Locale associated with the given configuration key.
2156      * If the key doesn't map to an existing object, the default value
2157      * is returned.
2158      *
2159      * @param key          The configuration key.
2160      * @param defaultValue The default value.
2161      * @return The associated Locale.
2162      *
2163      * @throws ConversionException is thrown if the key maps to an
2164      *         object that is not a Locale.
2165      */
2166     public Locale getLocale(String key, Locale defaultValue)
2167     {
2168         Object value = resolveContainerStore(key);
2169 
2170         if (value == null)
2171         {
2172             return defaultValue;
2173         }
2174         else
2175         {
2176             try
2177             {
2178                 return PropertyConverter.toLocale(interpolate(value));
2179             }
2180             catch (ConversionException e)
2181             {
2182                 throw new ConversionException('\'' + key + "' doesn't map to a Locale", e);
2183             }
2184         }
2185     }
2186 
2187     /***
2188      * Get a list of Locales associated with the given configuration key.
2189      * If the key doesn't map to an existing object an empty list is returned.
2190      *
2191      * @param key The configuration key.
2192      * @return The associated Locale list if the key is found.
2193      *
2194      * @throws ConversionException is thrown if the key maps to an
2195      *         object that is not a list of Locales.
2196      */
2197     public List getLocaleList(String key)
2198     {
2199         return getLocaleList(key, new ArrayList());
2200     }
2201 
2202     /***
2203      * Get a list of Locales associated with the given configuration key.
2204      * If the key doesn't map to an existing object, the default value is
2205      * returned.
2206      *
2207      * @param key The configuration key.
2208      * @param defaultValue The default value.
2209      * @return The associated List of Locales.
2210      *
2211      * @throws ConversionException is thrown if the key maps to an
2212      *         object that is not a list of Locales.
2213      */
2214     public List getLocaleList(String key, List defaultValue)
2215     {
2216         Object value = getProperty(key);
2217 
2218         List list;
2219 
2220         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
2221         {
2222             list = defaultValue;
2223         }
2224         else if (value instanceof Locale[])
2225         {
2226             list = new ArrayList();
2227             CollectionUtils.addAll(list, (Locale[]) value);
2228         }
2229         else if (value instanceof Collection)
2230         {
2231             Collection values = (Collection) value;
2232             list = new ArrayList();
2233 
2234             Iterator it = values.iterator();
2235             while (it.hasNext())
2236             {
2237                 list.add(PropertyConverter.toLocale(interpolate(it.next())));
2238             }
2239         }
2240         else
2241         {
2242             try
2243             {
2244                 // attempt to convert a single value
2245                 list = new ArrayList();
2246                 list.add(PropertyConverter.toLocale(interpolate(value)));
2247             }
2248             catch (ConversionException e)
2249             {
2250                 throw new ConversionException('\'' + key + "' doesn't map to a list of Locales", e);
2251             }
2252         }
2253 
2254         return list;
2255     }
2256 
2257     /***
2258      * Get an array of Locales associated with the given
2259      * configuration key. If the key doesn't map to an existing object
2260      * an empty array is returned.
2261      *
2262      * @param key The configuration key.
2263      * @return The associated Locale array if the key is found.
2264      *
2265      * @throws ConversionException is thrown if the key maps to an
2266      *         object that is not a list of Locales.
2267      */
2268     public Locale[] getLocaleArray(String key)
2269     {
2270         return getLocaleArray(key, new Locale[0]);
2271     }
2272 
2273     /***
2274      * Get an array of Locales associated with the given
2275      * configuration key. If the key doesn't map to an existing object
2276      * an empty array is returned.
2277      *
2278      * @param key The configuration key.
2279      * @param defaultValue the default value, which will be returned if the property is not found
2280      * @return The associated Locale array if the key is found.
2281      *
2282      * @throws ConversionException is thrown if the key maps to an
2283      *         object that is not a list of Locales.
2284      */
2285     public Locale[] getLocaleArray(String key, Locale[] defaultValue)
2286     {
2287         List list = getLocaleList(key);
2288         if (list.isEmpty())
2289         {
2290             return defaultValue;
2291         }
2292         else
2293         {
2294             return (Locale[]) list.toArray(new Locale[list.size()]);
2295         }
2296     }
2297 
2298     /***
2299      * Get a Color associated with the given configuration key.
2300      *
2301      * @param key The configuration key.
2302      * @return The associated Color.
2303      *
2304      * @throws ConversionException is thrown if the key maps to an
2305      *         object that is not a Color.
2306      */
2307     public Color getColor(String key)
2308     {
2309         return getColor(key, null);
2310     }
2311 
2312     /***
2313      * Get a Color associated with the given configuration key.
2314      * If the key doesn't map to an existing object, the default value
2315      * is returned.
2316      *
2317      * @param key          The configuration key.
2318      * @param defaultValue The default value.
2319      * @return The associated Color.
2320      *
2321      * @throws ConversionException is thrown if the key maps to an
2322      *         object that is not a Color.
2323      */
2324     public Color getColor(String key, Color defaultValue)
2325     {
2326         Object value = resolveContainerStore(key);
2327 
2328         if (value == null)
2329         {
2330             return defaultValue;
2331         }
2332         else
2333         {
2334             try
2335             {
2336                 return PropertyConverter.toColor(interpolate(value));
2337             }
2338             catch (ConversionException e)
2339             {
2340                 throw new ConversionException('\'' + key + "' doesn't map to a Color", e);
2341             }
2342         }
2343     }
2344 
2345     /***
2346      * Get a list of Colors associated with the given configuration key.
2347      * If the key doesn't map to an existing object an empty list is returned.
2348      *
2349      * @param key The configuration key.
2350      * @return The associated Color list if the key is found.
2351      *
2352      * @throws ConversionException is thrown if the key maps to an
2353      *         object that is not a list of Colors.
2354      */
2355     public List getColorList(String key)
2356     {
2357         return getColorList(key, new ArrayList());
2358     }
2359 
2360     /***
2361      * Get a list of Colors associated with the given configuration key.
2362      * If the key doesn't map to an existing object, the default value is
2363      * returned.
2364      *
2365      * @param key The configuration key.
2366      * @param defaultValue The default value.
2367      * @return The associated List of Colors.
2368      *
2369      * @throws ConversionException is thrown if the key maps to an
2370      *         object that is not a list of Colors.
2371      */
2372     public List getColorList(String key, List defaultValue)
2373     {
2374         Object value = getProperty(key);
2375 
2376         List list;
2377 
2378         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
2379         {
2380             list = defaultValue;
2381         }
2382         else if (value instanceof Color[])
2383         {
2384             list = new ArrayList();
2385             CollectionUtils.addAll(list, (Color[]) value);
2386         }
2387         else if (value instanceof Collection)
2388         {
2389             Collection values = (Collection) value;
2390             list = new ArrayList();
2391 
2392             Iterator it = values.iterator();
2393             while (it.hasNext())
2394             {
2395                 list.add(PropertyConverter.toColor(interpolate(it.next())));
2396             }
2397         }
2398         else
2399         {
2400             try
2401             {
2402                 // attempt to convert a single value
2403                 list = new ArrayList();
2404                 list.add(PropertyConverter.toColor(interpolate(value)));
2405             }
2406             catch (ConversionException e)
2407             {
2408                 throw new ConversionException('\'' + key + "' doesn't map to a list of Colors", e);
2409             }
2410         }
2411 
2412         return list;
2413     }
2414 
2415     /***
2416      * Get an array of Colors associated with the given
2417      * configuration key. If the key doesn't map to an existing object
2418      * an empty array is returned.
2419      *
2420      * @param key The configuration key.
2421      * @return The associated Color array if the key is found.
2422      *
2423      * @throws ConversionException is thrown if the key maps to an
2424      *         object that is not a list of Colors.
2425      */
2426     public Color[] getColorArray(String key)
2427     {
2428         return getColorArray(key, new Color[0]);
2429     }
2430 
2431     /***
2432      * Get an array of Colors associated with the given
2433      * configuration key. If the key doesn't map to an existing object
2434      * an empty array is returned.
2435      *
2436      * @param key The configuration key.
2437      * @param defaultValue the default value, which will be returned if the property is not found
2438      * @return The associated Color array if the key is found.
2439      *
2440      * @throws ConversionException is thrown if the key maps to an
2441      *         object that is not a list of Colors.
2442      */
2443     public Color[] getColorArray(String key, Color[] defaultValue)
2444     {
2445         List list = getColorList(key);
2446         if (list.isEmpty())
2447         {
2448             return defaultValue;
2449         }
2450         else
2451         {
2452             return (Color[]) list.toArray(new Color[list.size()]);
2453         }
2454     }
2455 
2456 }