1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.configuration;
19
20 import java.awt.Color;
21 import java.lang.reflect.Array;
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.math.BigDecimal;
26 import java.math.BigInteger;
27 import java.net.InetAddress;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.net.UnknownHostException;
31 import java.text.ParseException;
32 import java.text.SimpleDateFormat;
33 import java.util.ArrayList;
34 import java.util.Calendar;
35 import java.util.Collection;
36 import java.util.Date;
37 import java.util.Iterator;
38 import java.util.List;
39 import java.util.Locale;
40
41 import org.apache.commons.collections.IteratorUtils;
42 import org.apache.commons.collections.iterators.IteratorChain;
43 import org.apache.commons.collections.iterators.SingletonIterator;
44 import org.apache.commons.lang.BooleanUtils;
45 import org.apache.commons.lang.StringUtils;
46 import org.apache.commons.lang.SystemUtils;
47
48 /***
49 * A utility class to convert the configuration properties into any type.
50 *
51 * @author Emmanuel Bourg
52 * @version $Revision: 589380 $, $Date: 2007-10-28 17:37:35 +0100 (So, 28 Okt 2007) $
53 * @since 1.1
54 */
55 public final class PropertyConverter
56 {
57 /*** Constant for the list delimiter as char.*/
58 static final char LIST_ESC_CHAR = '//';
59
60 /*** Constant for the list delimiter escaping character as string.*/
61 static final String LIST_ESCAPE = String.valueOf(LIST_ESC_CHAR);
62
63 /*** Constant for the prefix of hex numbers.*/
64 private static final String HEX_PREFIX = "0x";
65
66 /*** Constant for the radix of hex numbers.*/
67 private static final int HEX_RADIX = 16;
68
69 /*** Constant for the Java version 1.5.*/
70 private static final float JAVA_VERSION_1_5 = 1.5f;
71
72 /*** Constant for the argument classes of the Number constructor that takes a String. */
73 private static final Class[] CONSTR_ARGS = {String.class};
74
75 /*** The fully qualified name of {@link javax.mail.internet.InternetAddress} */
76 private static final String INTERNET_ADDRESS_CLASSNAME = "javax.mail.internet.InternetAddress";
77
78 /***
79 * Private constructor prevents instances from being created.
80 */
81 private PropertyConverter()
82 {
83
84 }
85
86 /***
87 * Converts the specified value to the target class. If the class is a
88 * primitive type (Integer.TYPE, Boolean.TYPE, etc) the value returned
89 * will use the wrapper type (Integer.class, Boolean.class, etc).
90 *
91 * @param cls the target class of the converted value
92 * @param value the value to convert
93 * @param params optional parameters used for the conversion
94 * @return the converted value
95 * @throws ConversionException if the value is not compatible with the requested type
96 *
97 * @since 1.5
98 */
99 static Object to(Class cls, Object value, Object[] params) throws ConversionException
100 {
101 if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls))
102 {
103 return toBoolean(value);
104 }
105 else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive())
106 {
107 if (Integer.class.equals(cls) || Integer.TYPE.equals(cls))
108 {
109 return toInteger(value);
110 }
111 else if (Long.class.equals(cls) || Long.TYPE.equals(cls))
112 {
113 return toLong(value);
114 }
115 else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls))
116 {
117 return toByte(value);
118 }
119 else if (Short.class.equals(cls) || Short.TYPE.equals(cls))
120 {
121 return toShort(value);
122 }
123 else if (Float.class.equals(cls) || Float.TYPE.equals(cls))
124 {
125 return toFloat(value);
126 }
127 else if (Double.class.equals(cls) || Double.TYPE.equals(cls))
128 {
129 return toDouble(value);
130 }
131 else if (BigInteger.class.equals(cls))
132 {
133 return toBigInteger(value);
134 }
135 else if (BigDecimal.class.equals(cls))
136 {
137 return toBigDecimal(value);
138 }
139 }
140 else if (Date.class.equals(cls))
141 {
142 return toDate(value, (String) params[0]);
143 }
144 else if (Calendar.class.equals(cls))
145 {
146 return toCalendar(value, (String) params[0]);
147 }
148 else if (URL.class.equals(cls))
149 {
150 return toURL(value);
151 }
152 else if (Locale.class.equals(cls))
153 {
154 return toLocale(value);
155 }
156 else if (isEnum(cls))
157 {
158 return toEnum(value, cls);
159 }
160 else if (Color.class.equals(cls))
161 {
162 return toColor(value);
163 }
164 else if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME))
165 {
166 return toInternetAddress(value);
167 }
168 else if (InetAddress.class.isAssignableFrom(cls))
169 {
170 return toInetAddress(value);
171 }
172
173 throw new ConversionException("The value '" + value + "' (" + value.getClass() + ")"
174 + " can't be converted to a " + cls.getName() + " object");
175 }
176
177 /***
178 * Convert the specified object into a Boolean. Internally the
179 * <code>org.apache.commons.lang.BooleanUtils</code> class from the
180 * <a href="http://commons.apache.org/lang/">Commons Lang</a>
181 * project is used to perform this conversion. This class accepts some more
182 * tokens for the boolean value of <b>true</b>, e.g. <code>yes</code> and
183 * <code>on</code>. Please refer to the documentation of this class for more
184 * details.
185 *
186 * @param value the value to convert
187 * @return the converted value
188 * @throws ConversionException thrown if the value cannot be converted to a boolean
189 */
190 public static Boolean toBoolean(Object value) throws ConversionException
191 {
192 if (value instanceof Boolean)
193 {
194 return (Boolean) value;
195 }
196 else if (value instanceof String)
197 {
198 Boolean b = BooleanUtils.toBooleanObject((String) value);
199 if (b == null)
200 {
201 throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
202 }
203 return b;
204 }
205 else
206 {
207 throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
208 }
209 }
210
211 /***
212 * Convert the specified object into a Byte.
213 *
214 * @param value the value to convert
215 * @return the converted value
216 * @throws ConversionException thrown if the value cannot be converted to a byte
217 */
218 public static Byte toByte(Object value) throws ConversionException
219 {
220 Number n = toNumber(value, Byte.class);
221 if (n instanceof Byte)
222 {
223 return (Byte) n;
224 }
225 else
226 {
227 return new Byte(n.byteValue());
228 }
229 }
230
231 /***
232 * Convert the specified object into a Short.
233 *
234 * @param value the value to convert
235 * @return the converted value
236 * @throws ConversionException thrown if the value cannot be converted to a short
237 */
238 public static Short toShort(Object value) throws ConversionException
239 {
240 Number n = toNumber(value, Short.class);
241 if (n instanceof Short)
242 {
243 return (Short) n;
244 }
245 else
246 {
247 return new Short(n.shortValue());
248 }
249 }
250
251 /***
252 * Convert the specified object into an Integer.
253 *
254 * @param value the value to convert
255 * @return the converted value
256 * @throws ConversionException thrown if the value cannot be converted to an integer
257 */
258 public static Integer toInteger(Object value) throws ConversionException
259 {
260 Number n = toNumber(value, Integer.class);
261 if (n instanceof Integer)
262 {
263 return (Integer) n;
264 }
265 else
266 {
267 return new Integer(n.intValue());
268 }
269 }
270
271 /***
272 * Convert the specified object into a Long.
273 *
274 * @param value the value to convert
275 * @return the converted value
276 * @throws ConversionException thrown if the value cannot be converted to a Long
277 */
278 public static Long toLong(Object value) throws ConversionException
279 {
280 Number n = toNumber(value, Long.class);
281 if (n instanceof Long)
282 {
283 return (Long) n;
284 }
285 else
286 {
287 return new Long(n.longValue());
288 }
289 }
290
291 /***
292 * Convert the specified object into a Float.
293 *
294 * @param value the value to convert
295 * @return the converted value
296 * @throws ConversionException thrown if the value cannot be converted to a Float
297 */
298 public static Float toFloat(Object value) throws ConversionException
299 {
300 Number n = toNumber(value, Float.class);
301 if (n instanceof Float)
302 {
303 return (Float) n;
304 }
305 else
306 {
307 return new Float(n.floatValue());
308 }
309 }
310
311 /***
312 * Convert the specified object into a Double.
313 *
314 * @param value the value to convert
315 * @return the converted value
316 * @throws ConversionException thrown if the value cannot be converted to a Double
317 */
318 public static Double toDouble(Object value) throws ConversionException
319 {
320 Number n = toNumber(value, Double.class);
321 if (n instanceof Double)
322 {
323 return (Double) n;
324 }
325 else
326 {
327 return new Double(n.doubleValue());
328 }
329 }
330
331 /***
332 * Convert the specified object into a BigInteger.
333 *
334 * @param value the value to convert
335 * @return the converted value
336 * @throws ConversionException thrown if the value cannot be converted to a BigInteger
337 */
338 public static BigInteger toBigInteger(Object value) throws ConversionException
339 {
340 Number n = toNumber(value, BigInteger.class);
341 if (n instanceof BigInteger)
342 {
343 return (BigInteger) n;
344 }
345 else
346 {
347 return BigInteger.valueOf(n.longValue());
348 }
349 }
350
351 /***
352 * Convert the specified object into a BigDecimal.
353 *
354 * @param value the value to convert
355 * @return the converted value
356 * @throws ConversionException thrown if the value cannot be converted to a BigDecimal
357 */
358 public static BigDecimal toBigDecimal(Object value) throws ConversionException
359 {
360 Number n = toNumber(value, BigDecimal.class);
361 if (n instanceof BigDecimal)
362 {
363 return (BigDecimal) n;
364 }
365 else
366 {
367 return new BigDecimal(n.doubleValue());
368 }
369 }
370
371 /***
372 * Tries to convert the specified object into a number object. This method
373 * is used by the conversion methods for number types. Note that the return
374 * value is not in always of the specified target class, but only if a new
375 * object has to be created.
376 *
377 * @param value the value to be converted (must not be <b>null</b>)
378 * @param targetClass the target class of the conversion (must be derived
379 * from <code>java.lang.Number</code>)
380 * @return the converted number
381 * @throws ConversionException if the object cannot be converted
382 */
383 static Number toNumber(Object value, Class targetClass) throws ConversionException
384 {
385 if (value instanceof Number)
386 {
387 return (Number) value;
388 }
389 else
390 {
391 String str = value.toString();
392 if (str.startsWith(HEX_PREFIX))
393 {
394 try
395 {
396 return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX);
397 }
398 catch (NumberFormatException nex)
399 {
400 throw new ConversionException("Could not convert " + str
401 + " to " + targetClass.getName()
402 + "! Invalid hex number.", nex);
403 }
404 }
405
406 try
407 {
408 Constructor constr = targetClass.getConstructor(CONSTR_ARGS);
409 return (Number) constr.newInstance(new Object[]{str});
410 }
411 catch (InvocationTargetException itex)
412 {
413 throw new ConversionException("Could not convert " + str
414 + " to " + targetClass.getName(), itex
415 .getTargetException());
416 }
417 catch (Exception ex)
418 {
419
420 throw new ConversionException(
421 "Conversion error when trying to convert " + str
422 + " to " + targetClass.getName(), ex);
423 }
424 }
425 }
426
427 /***
428 * Convert the specified object into an URL.
429 *
430 * @param value the value to convert
431 * @return the converted value
432 * @throws ConversionException thrown if the value cannot be converted to an URL
433 */
434 public static URL toURL(Object value) throws ConversionException
435 {
436 if (value instanceof URL)
437 {
438 return (URL) value;
439 }
440 else if (value instanceof String)
441 {
442 try
443 {
444 return new URL((String) value);
445 }
446 catch (MalformedURLException e)
447 {
448 throw new ConversionException("The value " + value + " can't be converted to an URL", e);
449 }
450 }
451 else
452 {
453 throw new ConversionException("The value " + value + " can't be converted to an URL");
454 }
455 }
456
457 /***
458 * Convert the specified object into a Locale.
459 *
460 * @param value the value to convert
461 * @return the converted value
462 * @throws ConversionException thrown if the value cannot be converted to a Locale
463 */
464 public static Locale toLocale(Object value) throws ConversionException
465 {
466 if (value instanceof Locale)
467 {
468 return (Locale) value;
469 }
470 else if (value instanceof String)
471 {
472 List elements = split((String) value, '_');
473 int size = elements.size();
474
475 if (size >= 1 && (((String) elements.get(0)).length() == 2 || ((String) elements.get(0)).length() == 0))
476 {
477 String language = (String) elements.get(0);
478 String country = (String) ((size >= 2) ? elements.get(1) : "");
479 String variant = (String) ((size >= 3) ? elements.get(2) : "");
480
481 return new Locale(language, country, variant);
482 }
483 else
484 {
485 throw new ConversionException("The value " + value + " can't be converted to a Locale");
486 }
487 }
488 else
489 {
490 throw new ConversionException("The value " + value + " can't be converted to a Locale");
491 }
492 }
493
494 /***
495 * Split a string on the specified delimiter. To be removed when
496 * commons-lang has a better replacement available (Tokenizer?).
497 *
498 * todo: replace with a commons-lang equivalent
499 *
500 * @param s the string to split
501 * @param delimiter the delimiter
502 * @return a list with the single tokens
503 */
504 public static List split(String s, char delimiter)
505 {
506 if (s == null)
507 {
508 return new ArrayList();
509 }
510
511 List list = new ArrayList();
512
513 StringBuffer token = new StringBuffer();
514 int begin = 0;
515 boolean inEscape = false;
516
517 while (begin < s.length())
518 {
519 char c = s.charAt(begin);
520 if (inEscape)
521 {
522
523
524 if (c != delimiter && c != LIST_ESC_CHAR)
525 {
526
527 token.append(LIST_ESC_CHAR);
528 }
529 token.append(c);
530 inEscape = false;
531 }
532
533 else
534 {
535 if (c == delimiter)
536 {
537
538 list.add(token.toString().trim());
539 token = new StringBuffer();
540 }
541 else if (c == LIST_ESC_CHAR)
542 {
543
544 inEscape = true;
545 }
546 else
547 {
548 token.append(c);
549 }
550 }
551
552 begin++;
553 }
554
555
556 if (inEscape)
557 {
558 token.append(LIST_ESC_CHAR);
559 }
560
561 list.add(token.toString().trim());
562
563 return list;
564 }
565
566 /***
567 * Escapes the delimiters that might be contained in the given string. This
568 * method ensures that list delimiter characters that are part of a
569 * property's value are correctly escaped when a configuration is saved to a
570 * file. Otherwise when loaded again the property will be treated as a list
571 * property. A single backslash will also be escaped.
572 *
573 * @param s the string with the value
574 * @param delimiter the list delimiter to use
575 * @return the correctly esaped string
576 */
577 public static String escapeDelimiters(String s, char delimiter)
578 {
579 String s1 = StringUtils.replace(s, LIST_ESCAPE, LIST_ESCAPE + LIST_ESCAPE);
580 return StringUtils.replace(s1, String.valueOf(delimiter), LIST_ESCAPE + delimiter);
581 }
582
583 /***
584 * Convert the specified object into a Color. If the value is a String,
585 * the format allowed is (#)?[0-9A-F]{6}([0-9A-F]{2})?. Examples:
586 * <ul>
587 * <li>FF0000 (red)</li>
588 * <li>0000FFA0 (semi transparent blue)</li>
589 * <li>#CCCCCC (gray)</li>
590 * <li>#00FF00A0 (semi transparent green)</li>
591 * </ul>
592 *
593 * @param value the value to convert
594 * @return the converted value
595 * @throws ConversionException thrown if the value cannot be converted to a Color
596 */
597 public static Color toColor(Object value) throws ConversionException
598 {
599 if (value instanceof Color)
600 {
601 return (Color) value;
602 }
603 else if (value instanceof String && !StringUtils.isBlank((String) value))
604 {
605 String color = ((String) value).trim();
606
607 int[] components = new int[3];
608
609
610 int minlength = components.length * 2;
611 if (color.length() < minlength)
612 {
613 throw new ConversionException("The value " + value + " can't be converted to a Color");
614 }
615
616
617 if (color.startsWith("#"))
618 {
619 color = color.substring(1);
620 }
621
622 try
623 {
624
625 for (int i = 0; i < components.length; i++)
626 {
627 components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX);
628 }
629
630
631 int alpha;
632 if (color.length() >= minlength + 2)
633 {
634 alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX);
635 }
636 else
637 {
638 alpha = Color.black.getAlpha();
639 }
640
641 return new Color(components[0], components[1], components[2], alpha);
642 }
643 catch (Exception e)
644 {
645 throw new ConversionException("The value " + value + " can't be converted to a Color", e);
646 }
647 }
648 else
649 {
650 throw new ConversionException("The value " + value + " can't be converted to a Color");
651 }
652 }
653
654 /***
655 * Convert the specified value into an internet address.
656 *
657 * @param value the value to convert
658 * @return the converted value
659 * @throws ConversionException thrown if the value cannot be converted to a InetAddress
660 *
661 * @since 1.5
662 */
663 static InetAddress toInetAddress(Object value) throws ConversionException
664 {
665 if (value instanceof InetAddress)
666 {
667 return (InetAddress) value;
668 }
669 else if (value instanceof String)
670 {
671 try
672 {
673 return InetAddress.getByName((String) value);
674 }
675 catch (UnknownHostException e)
676 {
677 throw new ConversionException("The value " + value + " can't be converted to a InetAddress", e);
678 }
679 }
680 else
681 {
682 throw new ConversionException("The value " + value + " can't be converted to a InetAddress");
683 }
684 }
685
686 /***
687 * Convert the specified value into an email address.
688 *
689 * @param value the value to convert
690 * @return the converted value
691 * @throws ConversionException thrown if the value cannot be converted to an email address
692 *
693 * @since 1.5
694 */
695 static Object toInternetAddress(Object value) throws ConversionException
696 {
697 if (value.getClass().getName().equals(INTERNET_ADDRESS_CLASSNAME))
698 {
699 return value;
700 }
701 else if (value instanceof String)
702 {
703 try
704 {
705 Constructor ctor = Class.forName(INTERNET_ADDRESS_CLASSNAME).getConstructor(new Class[] {String.class});
706 return ctor.newInstance(new Object[] {value});
707 }
708 catch (Exception e)
709 {
710 throw new ConversionException("The value " + value + " can't be converted to a InternetAddress", e);
711 }
712 }
713 else
714 {
715 throw new ConversionException("The value " + value + " can't be converted to a InternetAddress");
716 }
717 }
718
719 /***
720 * Calls Class.isEnum() on Java 5, returns false on older JRE.
721 */
722 static boolean isEnum(Class cls)
723 {
724 if (!SystemUtils.isJavaVersionAtLeast(JAVA_VERSION_1_5))
725 {
726 return false;
727 }
728
729 try
730 {
731 Method isEnumMethod = Class.class.getMethod("isEnum", new Class[] {});
732 return ((Boolean) isEnumMethod.invoke(cls, new Object[] {})).booleanValue();
733 }
734 catch (Exception e)
735 {
736
737 throw new RuntimeException(e.getMessage());
738 }
739 }
740
741 /***
742 * Convert the specified value into a Java 5 enum.
743 *
744 * @param value the value to convert
745 * @param cls the type of the enumeration
746 * @return the converted value
747 * @throws ConversionException thrown if the value cannot be converted to an enumeration
748 *
749 * @since 1.5
750 */
751 static Object toEnum(Object value, Class cls) throws ConversionException
752 {
753 if (value.getClass().equals(cls))
754 {
755 return value;
756 }
757 else if (value instanceof String)
758 {
759 try
760 {
761 Method valueOfMethod = cls.getMethod("valueOf", new Class[] {String.class});
762 return valueOfMethod.invoke(null, new Object[] {value});
763 }
764 catch (Exception e)
765 {
766 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
767 }
768 }
769 else if (value instanceof Number)
770 {
771 try
772 {
773 Method valuesMethod = cls.getMethod("values", new Class[] {});
774 Object valuesArray = valuesMethod.invoke(null, new Object[] {});
775
776 return Array.get(valuesArray, ((Number) value).intValue());
777 }
778 catch (Exception e)
779 {
780 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
781 }
782 }
783 else
784 {
785 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
786 }
787 }
788
789 /***
790 * Convert the specified object into a Date.
791 *
792 * @param value the value to convert
793 * @param format the DateFormat pattern to parse String values
794 * @return the converted value
795 * @throws ConversionException thrown if the value cannot be converted to a Calendar
796 */
797 public static Date toDate(Object value, String format) throws ConversionException
798 {
799 if (value instanceof Date)
800 {
801 return (Date) value;
802 }
803 else if (value instanceof Calendar)
804 {
805 return ((Calendar) value).getTime();
806 }
807 else if (value instanceof String)
808 {
809 try
810 {
811 return new SimpleDateFormat(format).parse((String) value);
812 }
813 catch (ParseException e)
814 {
815 throw new ConversionException("The value " + value + " can't be converted to a Date", e);
816 }
817 }
818 else
819 {
820 throw new ConversionException("The value " + value + " can't be converted to a Date");
821 }
822 }
823
824 /***
825 * Convert the specified object into a Calendar.
826 *
827 * @param value the value to convert
828 * @param format the DateFormat pattern to parse String values
829 * @return the converted value
830 * @throws ConversionException thrown if the value cannot be converted to a Calendar
831 */
832 public static Calendar toCalendar(Object value, String format) throws ConversionException
833 {
834 if (value instanceof Calendar)
835 {
836 return (Calendar) value;
837 }
838 else if (value instanceof Date)
839 {
840 Calendar calendar = Calendar.getInstance();
841 calendar.setTime((Date) value);
842 return calendar;
843 }
844 else if (value instanceof String)
845 {
846 try
847 {
848 Calendar calendar = Calendar.getInstance();
849 calendar.setTime(new SimpleDateFormat(format).parse((String) value));
850 return calendar;
851 }
852 catch (ParseException e)
853 {
854 throw new ConversionException("The value " + value + " can't be converted to a Calendar", e);
855 }
856 }
857 else
858 {
859 throw new ConversionException("The value " + value + " can't be converted to a Calendar");
860 }
861 }
862
863 /***
864 * Return an iterator over the simple values of a composite value. The value
865 * specified is handled depending on its type:
866 * <ul>
867 * <li>Strings are checked for delimiter characters and splitted if necessary.</li>
868 * <li>For collections the single elements are checked.</li>
869 * <li>Arrays are treated like collections.</li>
870 * <li>All other types are directly inserted.</li>
871 * <li>Recursive combinations are supported, e.g. a collection containing array that contain strings.</li>
872 * </ul>
873 *
874 * @param value the value to "split"
875 * @param delimiter the delimiter for String values
876 * @return an iterator for accessing the single values
877 */
878 public static Iterator toIterator(Object value, char delimiter)
879 {
880 if (value == null)
881 {
882 return IteratorUtils.emptyIterator();
883 }
884 if (value instanceof String)
885 {
886 String s = (String) value;
887 if (s.indexOf(delimiter) > 0)
888 {
889 return split((String) value, delimiter).iterator();
890 }
891 else
892 {
893 return new SingletonIterator(value);
894 }
895 }
896 else if (value instanceof Collection)
897 {
898 return toIterator(((Collection) value).iterator(), delimiter);
899 }
900 else if (value.getClass().isArray())
901 {
902 return toIterator(IteratorUtils.arrayIterator(value), delimiter);
903 }
904 else if (value instanceof Iterator)
905 {
906 Iterator iterator = (Iterator) value;
907 IteratorChain chain = new IteratorChain();
908 while (iterator.hasNext())
909 {
910 chain.addIterator(toIterator(iterator.next(), delimiter));
911 }
912 return chain;
913 }
914 else
915 {
916 return new SingletonIterator(value);
917 }
918 }
919
920 /***
921 * Performs interpolation of the specified value. This method checks if the
922 * given value contains variables of the form <code>${...}</code>. If
923 * this is the case, all occurrances will be substituted by their current
924 * values.
925 *
926 * @param value the value to be interpolated
927 * @param config the current configuration object
928 * @return the interpolated value
929 */
930 public static Object interpolate(Object value, AbstractConfiguration config)
931 {
932 if (value instanceof String)
933 {
934 return config.getSubstitutor().replace((String) value);
935 }
936 else
937 {
938 return value;
939 }
940 }
941 }