##### Coverage Report - org.apache.commons.configuration.PropertyConverter

Classes in this File | Line Coverage | Branch Coverage | Complexity
PropertyConverter |
96% | 232/241
100% | 84/84
| 7.68;7,68

1 |  |
     /*
2 |  |
      * Licensed to the Apache Software Foundation (ASF) under one or more
3 |  |
      * contributor license agreements.  See the NOTICE file distributed with
4 |  |
      * this work for additional information regarding copyright ownership.
5 |  |
      * The ASF licenses this file to You under the Apache License, Version 2.0
6 |  |
      * (the "License"); you may not use this file except in compliance with
7 |  |
      * the License.  You may obtain a copy of the License at
8 |  |
      *
9 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
10 |  |
      *
11 |  |
      * Unless required by applicable law or agreed to in writing, software
12 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
13 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |  |
      * See the License for the specific language governing permissions and
15 |  |
      * limitations under the License.
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 | 60 |
         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 | 187 |
         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 | 0 |
         {
83 |  |
             // to prevent instanciation...
84 | 0 |
         }
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 | 378 |
             if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls))
102 |  |
             {
103 | 29 |
                 return toBoolean(value);
104 |  |
             }
105 | 349 |
             else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive())
106 |  |
             {
107 | 224 |
                 if (Integer.class.equals(cls) || Integer.TYPE.equals(cls))
108 |  |
                 {
109 | 28 |
                     return toInteger(value);
110 |  |
                 }
111 | 196 |
                 else if (Long.class.equals(cls) || Long.TYPE.equals(cls))
112 |  |
                 {
113 | 28 |
                     return toLong(value);
114 |  |
                 }
115 | 168 |
                 else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls))
116 |  |
                 {
117 | 28 |
                     return toByte(value);
118 |  |
                 }
119 | 140 |
                 else if (Short.class.equals(cls) || Short.TYPE.equals(cls))
120 |  |
                 {
121 | 28 |
                     return toShort(value);
122 |  |
                 }
123 | 112 |
                 else if (Float.class.equals(cls) || Float.TYPE.equals(cls))
124 |  |
                 {
125 | 28 |
                     return toFloat(value);
126 |  |
                 }
127 | 84 |
                 else if (Double.class.equals(cls) || Double.TYPE.equals(cls))
128 |  |
                 {
129 | 28 |
                     return toDouble(value);
130 |  |
                 }
131 | 56 |
                 else if (BigInteger.class.equals(cls))
132 |  |
                 {
133 | 28 |
                     return toBigInteger(value);
134 |  |
                 }
135 | 28 |
                 else if (BigDecimal.class.equals(cls))
136 |  |
                 {
137 | 28 |
                     return toBigDecimal(value);
138 |  |
                 }
139 |  |
             }
140 | 125 |
             else if (Date.class.equals(cls))
141 |  |
             {
142 | 8 |
                 return toDate(value, (String) params[0]);
143 |  |
             }
144 | 117 |
             else if (Calendar.class.equals(cls))
145 |  |
             {
146 | 8 |
                 return toCalendar(value, (String) params[0]);
147 |  |
             }
148 | 109 |
             else if (URL.class.equals(cls))
149 |  |
             {
150 | 31 |
                 return toURL(value);
151 |  |
             }
152 | 78 |
             else if (Locale.class.equals(cls))
153 |  |
             {
154 | 36 |
                 return toLocale(value);
155 |  |
             }
156 | 42 |
             else if (isEnum(cls))
157 |  |
             {
158 | 0 |
                 return toEnum(value, cls);
159 |  |
             }
160 | 42 |
             else if (Color.class.equals(cls))
161 |  |
             {
162 | 32 |
                 return toColor(value);
163 |  |
             }
164 | 10 |
             else if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME))
165 |  |
             {
166 | 5 |
                 return toInternetAddress(value);
167 |  |
             }
168 | 5 |
             else if (InetAddress.class.isAssignableFrom(cls))
169 |  |
             {
170 | 5 |
                 return toInetAddress(value);
171 |  |
             }
172 |  |
173 | 0 |
             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 | 125 |
             if (value instanceof Boolean)
193 |  |
             {
194 | 41 |
                 return (Boolean) value;
195 |  |
             }
196 | 84 |
             else if (value instanceof String)
197 |  |
             {
198 | 81 |
                 Boolean b = BooleanUtils.toBooleanObject((String) value);
199 | 81 |
                 if (b == null)
200 |  |
                 {
201 | 5 |
                     throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
202 |  |
                 }
203 | 76 |
                 return b;
204 |  |
             }
205 |  |
             else
206 |  |
             {
207 | 3 |
                 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 | 46 |
             Number n = toNumber(value, Byte.class);
221 | 40 |
             if (n instanceof Byte)
222 |  |
             {
223 | 38 |
                 return (Byte) n;
224 |  |
             }
225 |  |
             else
226 |  |
             {
227 | 2 |
                 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 | 50 |
             Number n = toNumber(value, Short.class);
241 | 44 |
             if (n instanceof Short)
242 |  |
             {
243 | 43 |
                 return (Short) n;
244 |  |
             }
245 |  |
             else
246 |  |
             {
247 | 1 |
                 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 | 86 |
             Number n = toNumber(value, Integer.class);
261 | 82 |
             if (n instanceof Integer)
262 |  |
             {
263 | 81 |
                 return (Integer) n;
264 |  |
             }
265 |  |
             else
266 |  |
             {
267 | 1 |
                 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 | 47 |
             Number n = toNumber(value, Long.class);
281 | 41 |
             if (n instanceof Long)
282 |  |
             {
283 | 38 |
                 return (Long) n;
284 |  |
             }
285 |  |
             else
286 |  |
             {
287 | 3 |
                 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 | 45 |
             Number n = toNumber(value, Float.class);
301 | 39 |
             if (n instanceof Float)
302 |  |
             {
303 | 38 |
                 return (Float) n;
304 |  |
             }
305 |  |
             else
306 |  |
             {
307 | 1 |
                 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 | 48 |
             Number n = toNumber(value, Double.class);
321 | 42 |
             if (n instanceof Double)
322 |  |
             {
323 | 41 |
                 return (Double) n;
324 |  |
             }
325 |  |
             else
326 |  |
             {
327 | 1 |
                 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 | 37 |
             Number n = toNumber(value, BigInteger.class);
341 | 31 |
             if (n instanceof BigInteger)
342 |  |
             {
343 | 30 |
                 return (BigInteger) n;
344 |  |
             }
345 |  |
             else
346 |  |
             {
347 | 1 |
                 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 | 36 |
             Number n = toNumber(value, BigDecimal.class);
361 | 30 |
             if (n instanceof BigDecimal)
362 |  |
             {
363 | 29 |
                 return (BigDecimal) n;
364 |  |
             }
365 |  |
             else
366 |  |
             {
367 | 1 |
                 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 | 403 |
             if (value instanceof Number)
386 |  |
             {
387 | 101 |
                 return (Number) value;
388 |  |
             }
389 |  |
             else
390 |  |
             {
391 | 302 |
                 String str = value.toString();
392 | 302 |
                 if (str.startsWith(HEX_PREFIX))
393 |  |
                 {
394 |  |
                     try
395 |  |
                     {
396 | 7 |
                         return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX);
397 |  |
                     }
398 | 1 |
                     catch (NumberFormatException nex)
399 |  |
                     {
400 | 1 |
                         throw new ConversionException("Could not convert " + str
401 |  |
                                 + " to " + targetClass.getName()
402 |  |
                                 + "! Invalid hex number.", nex);
403 |  |
                     }
404 |  |
                 }
405 |  |
406 |  |
                 try
407 |  |
                 {
408 | 295 |
                     Constructor constr = targetClass.getConstructor(CONSTR_ARGS);
409 | 294 |
                     return (Number) constr.newInstance(new Object[]{str});
410 |  |
                 }
411 | 47 |
                 catch (InvocationTargetException itex)
412 |  |
                 {
413 | 47 |
                     throw new ConversionException("Could not convert " + str
414 |  |
                             + " to " + targetClass.getName(), itex
415 |  |
                             .getTargetException());
416 |  |
                 }
417 | 1 |
                 catch (Exception ex)
418 |  |
                 {
419 |  |
                     // Treat all possible exceptions the same way
420 | 1 |
                     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 | 31 |
             if (value instanceof URL)
437 |  |
             {
438 | 11 |
                 return (URL) value;
439 |  |
             }
440 | 20 |
             else if (value instanceof String)
441 |  |
             {
442 |  |
                 try
443 |  |
                 {
444 | 18 |
                     return new URL((String) value);
445 |  |
                 }
446 | 2 |
                 catch (MalformedURLException e)
447 |  |
                 {
448 | 2 |
                     throw new ConversionException("The value " + value + " can't be converted to an URL", e);
449 |  |
                 }
450 |  |
             }
451 |  |
             else
452 |  |
             {
453 | 2 |
                 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 | 36 |
             if (value instanceof Locale)
467 |  |
             {
468 | 10 |
                 return (Locale) value;
469 |  |
             }
470 | 26 |
             else if (value instanceof String)
471 |  |
             {
472 | 24 |
                 List elements = split((String) value, '_');
473 | 24 |
                 int size = elements.size();
474 |  |
475 | 24 |
                 if (size >= 1 && (((String) elements.get(0)).length() == 2 || ((String) elements.get(0)).length() == 0))
476 |  |
                 {
477 | 22 |
                     String language = (String) elements.get(0);
478 | 22 |
                     String country = (String) ((size >= 2) ? elements.get(1) : "");
479 | 22 |
                     String variant = (String) ((size >= 3) ? elements.get(2) : "");
480 |  |
481 | 22 |
                     return new Locale(language, country, variant);
482 |  |
                 }
483 |  |
                 else
484 |  |
                 {
485 | 2 |
                     throw new ConversionException("The value " + value + " can't be converted to a Locale");
486 |  |
                 }
487 |  |
             }
488 |  |
             else
489 |  |
             {
490 | 2 |
                 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 | 14899 |
             if (s == null)
507 |  |
             {
508 | 1 |
                 return new ArrayList();
509 |  |
             }
510 |  |
511 | 14898 |
             List list = new ArrayList();
512 |  |
513 | 14898 |
             StringBuffer token = new StringBuffer();
514 | 14898 |
             int begin = 0;
515 | 14898 |
             boolean inEscape = false;
516 |  |
517 | 182690 |
             while (begin < s.length())
518 |  |
             {
519 | 167792 |
                 char c = s.charAt(begin);
520 | 167792 |
                 if (inEscape)
521 |  |
                 {
522 |  |
                     // last character was the escape marker
523 |  |
                     // can current character be escaped?
524 | 4856 |
                     if (c != delimiter && c != LIST_ESC_CHAR)
525 |  |
                     {
526 |  |
                         // no, also add escape character
527 | 3600 |
                         token.append(LIST_ESC_CHAR);
528 |  |
                     }
529 | 4856 |
                     token.append(c);
530 | 4856 |
                     inEscape = false;
531 | 4856 |
                 }
532 |  |
533 |  |
                 else
534 |  |
                 {
535 | 162936 |
                     if (c == delimiter)
536 |  |
                     {
537 |  |
                         // found a list delimiter -> add token and reset buffer
538 | 4142 |
                         list.add(token.toString().trim());
539 | 4142 |
                         token = new StringBuffer();
540 | 4142 |
                     }
541 | 158794 |
                     else if (c == LIST_ESC_CHAR)
542 |  |
                     {
543 |  |
                         // eventually escape next character
544 | 4879 |
                         inEscape = true;
545 | 4879 |
                     }
546 |  |
                     else
547 |  |
                     {
548 | 153915 |
                         token.append(c);
549 |  |
                     }
550 |  |
                 }
551 |  |
552 | 167792 |
                 begin++;
553 | 167792 |
             }
554 |  |
555 |  |
             // Trailing delimiter?
556 | 14898 |
             if (inEscape)
557 |  |
             {
558 | 23 |
                 token.append(LIST_ESC_CHAR);
559 |  |
             }
560 |  |
             // Add last token
561 | 14898 |
             list.add(token.toString().trim());
562 |  |
563 | 14898 |
             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 | 628 |
             String s1 = StringUtils.replace(s, LIST_ESCAPE, LIST_ESCAPE + LIST_ESCAPE);
580 | 628 |
             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 | 32 |
             if (value instanceof Color)
600 |  |
             {
601 | 10 |
                 return (Color) value;
602 |  |
             }
603 | 22 |
             else if (value instanceof String && !StringUtils.isBlank((String) value))
604 |  |
             {
605 | 20 |
                 String color = ((String) value).trim();
606 |  |
607 | 20 |
                 int[] components = new int[3];
608 |  |
609 |  |
                 // check the size of the string
610 | 20 |
                 int minlength = components.length * 2;
611 | 20 |
                 if (color.length() < minlength)
612 |  |
                 {
613 | 0 |
                     throw new ConversionException("The value " + value + " can't be converted to a Color");
614 |  |
                 }
615 |  |
616 |  |
                 // remove the leading #
617 | 20 |
                 if (color.startsWith("#"))
618 |  |
                 {
619 | 2 |
                     color = color.substring(1);
620 |  |
                 }
621 |  |
622 |  |
                 try
623 |  |
                 {
624 |  |
                     // parse the components
625 | 74 |
                     for (int i = 0; i < components.length; i++)
626 |  |
                     {
627 | 56 |
                         components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX);
628 |  |
                     }
629 |  |
630 |  |
                     // parse the transparency
631 |  |
                     int alpha;
632 | 18 |
                     if (color.length() >= minlength + 2)
633 |  |
                     {
634 | 1 |
                         alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX);
635 | 1 |
                     }
636 |  |
                     else
637 |  |
                     {
638 | 17 |
                         alpha = Color.black.getAlpha();
639 |  |
                     }
640 |  |
641 | 18 |
                     return new Color(components[0], components[1], components[2], alpha);
642 |  |
                 }
643 | 2 |
                 catch (Exception e)
644 |  |
                 {
645 | 2 |
                     throw new ConversionException("The value " + value + " can't be converted to a Color", e);
646 |  |
                 }
647 |  |
             }
648 |  |
             else
649 |  |
             {
650 | 2 |
                 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 | 5 |
             if (value instanceof InetAddress)
666 |  |
             {
667 | 1 |
                 return (InetAddress) value;
668 |  |
             }
669 | 4 |
             else if (value instanceof String)
670 |  |
             {
671 |  |
                 try
672 |  |
                 {
673 | 3 |
                     return InetAddress.getByName((String) value);
674 |  |
                 }
675 | 1 |
                 catch (UnknownHostException e)
676 |  |
                 {
677 | 1 |
                     throw new ConversionException("The value " + value + " can't be converted to a InetAddress", e);
678 |  |
                 }
679 |  |
             }
680 |  |
             else
681 |  |
             {
682 | 1 |
                 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 | 5 |
             if (value.getClass().getName().equals(INTERNET_ADDRESS_CLASSNAME))
698 |  |
             {
699 | 1 |
                 return value;
700 |  |
             }
701 | 4 |
             else if (value instanceof String)
702 |  |
             {
703 |  |
                 try
704 |  |
                 {
705 | 3 |
                     Constructor ctor = Class.forName(INTERNET_ADDRESS_CLASSNAME).getConstructor(new Class[] {String.class});
706 | 3 |
                     return ctor.newInstance(new Object[] {value});
707 |  |
                 }
708 | 1 |
                 catch (Exception e)
709 |  |
                 {
710 | 1 |
                     throw new ConversionException("The value " + value + " can't be converted to a InternetAddress", e);
711 |  |
                 }
712 |  |
             }
713 |  |
             else
714 |  |
             {
715 | 1 |
                 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 | 42 |
             if (!SystemUtils.isJavaVersionAtLeast(JAVA_VERSION_1_5))
725 |  |
             {
726 | 0 |
                 return false;
727 |  |
             }
728 |  |
729 |  |
             try
730 |  |
             {
731 | 42 |
                 Method isEnumMethod = Class.class.getMethod("isEnum", new Class[] {});
732 | 42 |
                 return ((Boolean) isEnumMethod.invoke(cls, new Object[] {})).booleanValue();
733 |  |
             }
734 | 0 |
             catch (Exception e)
735 |  |
             {
736 |  |
                 // impossible
737 | 0 |
                 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 | 5 |
             if (value.getClass().equals(cls))
754 |  |
             {
755 | 1 |
                 return value;
756 |  |
             }
757 | 4 |
             else if (value instanceof String)
758 |  |
             {
759 |  |
                 try
760 |  |
                 {
761 | 2 |
                     Method valueOfMethod = cls.getMethod("valueOf", new Class[] {String.class});
762 | 2 |
                     return valueOfMethod.invoke(null, new Object[] {value});
763 |  |
                 }
764 | 1 |
                 catch (Exception e)
765 |  |
                 {
766 | 1 |
                     throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
767 |  |
                 }
768 |  |
             }
769 | 2 |
             else if (value instanceof Number)
770 |  |
             {
771 |  |
                 try
772 |  |
                 {
773 | 2 |
                     Method valuesMethod = cls.getMethod("values", new Class[] {});
774 | 2 |
                     Object valuesArray = valuesMethod.invoke(null, new Object[] {});
775 |  |
776 | 2 |
                     return Array.get(valuesArray, ((Number) value).intValue());
777 |  |
                 }
778 | 1 |
                 catch (Exception e)
779 |  |
                 {
780 | 1 |
                     throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
781 |  |
                 }
782 |  |
             }
783 |  |
             else
784 |  |
             {
785 | 0 |
                 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 | 49 |
             if (value instanceof Date)
800 |  |
             {
801 | 15 |
                 return (Date) value;
802 |  |
             }
803 | 34 |
             else if (value instanceof Calendar)
804 |  |
             {
805 | 5 |
                 return ((Calendar) value).getTime();
806 |  |
             }
807 | 29 |
             else if (value instanceof String)
808 |  |
             {
809 |  |
                 try
810 |  |
                 {
811 | 26 |
                     return new SimpleDateFormat(format).parse((String) value);
812 |  |
                 }
813 | 3 |
                 catch (ParseException e)
814 |  |
                 {
815 | 3 |
                     throw new ConversionException("The value " + value + " can't be converted to a Date", e);
816 |  |
                 }
817 |  |
             }
818 |  |
             else
819 |  |
             {
820 | 3 |
                 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 | 49 |
             if (value instanceof Calendar)
835 |  |
             {
836 | 10 |
                 return (Calendar) value;
837 |  |
             }
838 | 39 |
             else if (value instanceof Date)
839 |  |
             {
840 | 10 |
                 Calendar calendar = Calendar.getInstance();
841 | 10 |
                 calendar.setTime((Date) value);
842 | 10 |
                 return calendar;
843 |  |
             }
844 | 29 |
             else if (value instanceof String)
845 |  |
             {
846 |  |
                 try
847 |  |
                 {
848 | 26 |
                     Calendar calendar = Calendar.getInstance();
849 | 26 |
                     calendar.setTime(new SimpleDateFormat(format).parse((String) value));
850 | 23 |
                     return calendar;
851 |  |
                 }
852 | 3 |
                 catch (ParseException e)
853 |  |
                 {
854 | 3 |
                     throw new ConversionException("The value " + value + " can't be converted to a Calendar", e);
855 |  |
                 }
856 |  |
             }
857 |  |
             else
858 |  |
             {
859 | 3 |
                 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 | 37625 |
             if (value == null)
881 |  |
             {
882 | 5 |
                 return IteratorUtils.emptyIterator();
883 |  |
             }
884 | 37620 |
             if (value instanceof String)
885 |  |
             {
886 | 28539 |
                 String s = (String) value;
887 | 28539 |
                 if (s.indexOf(delimiter) > 0)
888 |  |
                 {
889 | 2431 |
                     return split((String) value, delimiter).iterator();
890 |  |
                 }
891 |  |
                 else
892 |  |
                 {
893 | 26108 |
                     return new SingletonIterator(value);
894 |  |
                 }
895 |  |
             }
896 | 9081 |
             else if (value instanceof Collection)
897 |  |
             {
898 | 747 |
                 return toIterator(((Collection) value).iterator(), delimiter);
899 |  |
             }
900 | 8334 |
             else if (value.getClass().isArray())
901 |  |
             {
902 | 8 |
                 return toIterator(IteratorUtils.arrayIterator(value), delimiter);
903 |  |
             }
904 | 8326 |
             else if (value instanceof Iterator)
905 |  |
             {
906 | 755 |
                 Iterator iterator = (Iterator) value;
907 | 755 |
                 IteratorChain chain = new IteratorChain();
908 | 2563 |
                 while (iterator.hasNext())
909 |  |
                 {
910 | 1808 |
                     chain.addIterator(toIterator(iterator.next(), delimiter));
911 | 1808 |
                 }
912 | 755 |
                 return chain;
913 |  |
             }
914 |  |
             else
915 |  |
             {
916 | 7571 |
                 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 | 2866 |
             if (value instanceof String)
933 |  |
             {
934 | 2077 |
                 return config.getSubstitutor().replace((String) value);
935 |  |
             }
936 |  |
             else
937 |  |
             {
938 | 789 |
                 return value;
939 |  |
             }
940 |  |
         }
941 |  |
     }