Coverage Report - org.apache.commons.configuration.PropertyConverter
 
Classes in this File Line Coverage Branch Coverage Complexity
PropertyConverter
90%
219/242
94%
81/86
7,5
 
 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: 662269 $, $Date: 2008-06-01 21:30:02 +0200 (So, 01 Jun 2008) $
 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  64
     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  200
     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  1132
         if (value instanceof Boolean)
 193  
         {
 194  43
             return (Boolean) value;
 195  
         }
 196  1089
         else if (value instanceof String)
 197  
         {
 198  1086
             Boolean b = BooleanUtils.toBooleanObject((String) value);
 199  1086
             if (b == null)
 200  
             {
 201  5
                 throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
 202  
             }
 203  1081
             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  1105
         Number n = toNumber(value, Integer.class);
 261  1101
         if (n instanceof Integer)
 262  
         {
 263  1100
             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  48
         Number n = toNumber(value, Long.class);
 281  42
         if (n instanceof Long)
 282  
         {
 283  38
             return (Long) n;
 284  
         }
 285  
         else
 286  
         {
 287  4
             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  53
         Number n = toNumber(value, Double.class);
 321  47
         if (n instanceof Double)
 322  
         {
 323  45
             return (Double) n;
 324  
         }
 325  
         else
 326  
         {
 327  2
             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  1428
         if (value instanceof Number)
 386  
         {
 387  101
             return (Number) value;
 388  
         }
 389  
         else
 390  
         {
 391  1327
             String str = value.toString();
 392  1327
             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  1320
                 Constructor constr = targetClass.getConstructor(CONSTR_ARGS);
 409  1319
                 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  
      * @param trim       a flag whether the single elements should be trimmed
 503  
      * @return a list with the single tokens
 504  
      */
 505  
     public static List split(String s, char delimiter, boolean trim)
 506  
     {
 507  29283
         if (s == null)
 508  
         {
 509  1
             return new ArrayList();
 510  
         }
 511  
 
 512  29282
         List list = new ArrayList();
 513  
 
 514  29282
         StringBuffer token = new StringBuffer();
 515  29282
         int begin = 0;
 516  29282
         boolean inEscape = false;
 517  
 
 518  416787
         while (begin < s.length())
 519  
         {
 520  387505
             char c = s.charAt(begin);
 521  387505
             if (inEscape)
 522  
             {
 523  
                 // last character was the escape marker
 524  
                 // can current character be escaped?
 525  9342
                 if (c != delimiter && c != LIST_ESC_CHAR)
 526  
                 {
 527  
                     // no, also add escape character
 528  5827
                     token.append(LIST_ESC_CHAR);
 529  
                 }
 530  9342
                 token.append(c);
 531  9342
                 inEscape = false;
 532  
             }
 533  
 
 534  
             else
 535  
             {
 536  378163
                 if (c == delimiter)
 537  
                 {
 538  
                     // found a list delimiter -> add token and reset buffer
 539  10895
                     String t = token.toString();
 540  10895
                     if (trim)
 541  
                     {
 542  10893
                         t = t.trim();
 543  
                     }
 544  10895
                     list.add(t);
 545  10895
                     token = new StringBuffer();
 546  
                 }
 547  367268
                 else if (c == LIST_ESC_CHAR)
 548  
                 {
 549  
                     // eventually escape next character
 550  9377
                     inEscape = true;
 551  
                 }
 552  
                 else
 553  
                 {
 554  357891
                     token.append(c);
 555  
                 }
 556  
             }
 557  
 
 558  387505
             begin++;
 559  
         }
 560  
 
 561  
         // Trailing delimiter?
 562  29282
         if (inEscape)
 563  
         {
 564  35
             token.append(LIST_ESC_CHAR);
 565  
         }
 566  
         // Add last token
 567  29282
         String t = token.toString();
 568  29282
         if (trim)
 569  
         {
 570  28061
             t = t.trim();
 571  
         }
 572  29282
         list.add(t);
 573  
 
 574  29282
         return list;
 575  
     }
 576  
 
 577  
     /**
 578  
      * Split a string on the specified delimiter always trimming the elements.
 579  
      * This is a shortcut for <code>split(s, delimiter, true)</code>.
 580  
      *
 581  
      * @param s          the string to split
 582  
      * @param delimiter  the delimiter
 583  
      * @return a list with the single tokens
 584  
      */
 585  
     public static List split(String s, char delimiter)
 586  
     {
 587  15518
         return split(s, delimiter, true);
 588  
     }
 589  
 
 590  
     /**
 591  
      * Escapes the delimiters that might be contained in the given string. This
 592  
      * method ensures that list delimiter characters that are part of a
 593  
      * property's value are correctly escaped when a configuration is saved to a
 594  
      * file. Otherwise when loaded again the property will be treated as a list
 595  
      * property. A single backslash will also be escaped.
 596  
      *
 597  
      * @param s the string with the value
 598  
      * @param delimiter the list delimiter to use
 599  
      * @return the correctly esaped string
 600  
      */
 601  
     public static String escapeDelimiters(String s, char delimiter)
 602  
     {
 603  1046
         String s1 = StringUtils.replace(s, LIST_ESCAPE, LIST_ESCAPE + LIST_ESCAPE);
 604  1046
         return StringUtils.replace(s1, String.valueOf(delimiter), LIST_ESCAPE + delimiter);
 605  
     }
 606  
 
 607  
     /**
 608  
      * Convert the specified object into a Color. If the value is a String,
 609  
      * the format allowed is (#)?[0-9A-F]{6}([0-9A-F]{2})?. Examples:
 610  
      * <ul>
 611  
      *   <li>FF0000 (red)</li>
 612  
      *   <li>0000FFA0 (semi transparent blue)</li>
 613  
      *   <li>#CCCCCC (gray)</li>
 614  
      *   <li>#00FF00A0 (semi transparent green)</li>
 615  
      * </ul>
 616  
      *
 617  
      * @param value the value to convert
 618  
      * @return the converted value
 619  
      * @throws ConversionException thrown if the value cannot be converted to a Color
 620  
      */
 621  
     public static Color toColor(Object value) throws ConversionException
 622  
     {
 623  32
         if (value instanceof Color)
 624  
         {
 625  10
             return (Color) value;
 626  
         }
 627  22
         else if (value instanceof String && !StringUtils.isBlank((String) value))
 628  
         {
 629  20
             String color = ((String) value).trim();
 630  
 
 631  20
             int[] components = new int[3];
 632  
 
 633  
             // check the size of the string
 634  20
             int minlength = components.length * 2;
 635  20
             if (color.length() < minlength)
 636  
             {
 637  0
                 throw new ConversionException("The value " + value + " can't be converted to a Color");
 638  
             }
 639  
 
 640  
             // remove the leading #
 641  20
             if (color.startsWith("#"))
 642  
             {
 643  2
                 color = color.substring(1);
 644  
             }
 645  
 
 646  
             try
 647  
             {
 648  
                 // parse the components
 649  74
                 for (int i = 0; i < components.length; i++)
 650  
                 {
 651  56
                     components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX);
 652  
                 }
 653  
 
 654  
                 // parse the transparency
 655  
                 int alpha;
 656  18
                 if (color.length() >= minlength + 2)
 657  
                 {
 658  1
                     alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX);
 659  
                 }
 660  
                 else
 661  
                 {
 662  17
                     alpha = Color.black.getAlpha();
 663  
                 }
 664  
 
 665  18
                 return new Color(components[0], components[1], components[2], alpha);
 666  
             }
 667  2
             catch (Exception e)
 668  
             {
 669  2
                 throw new ConversionException("The value " + value + " can't be converted to a Color", e);
 670  
             }
 671  
         }
 672  
         else
 673  
         {
 674  2
             throw new ConversionException("The value " + value + " can't be converted to a Color");
 675  
         }
 676  
     }
 677  
 
 678  
     /**
 679  
      * Convert the specified value into an internet address.
 680  
      *
 681  
      * @param value the value to convert
 682  
      * @return the converted value
 683  
      * @throws ConversionException thrown if the value cannot be converted to a InetAddress
 684  
      *
 685  
      * @since 1.5
 686  
      */
 687  
     static InetAddress toInetAddress(Object value) throws ConversionException
 688  
     {
 689  5
         if (value instanceof InetAddress)
 690  
         {
 691  1
             return (InetAddress) value;
 692  
         }
 693  4
         else if (value instanceof String)
 694  
         {
 695  
             try
 696  
             {
 697  3
                 return InetAddress.getByName((String) value);
 698  
             }
 699  1
             catch (UnknownHostException e)
 700  
             {
 701  1
                 throw new ConversionException("The value " + value + " can't be converted to a InetAddress", e);
 702  
             }
 703  
         }
 704  
         else
 705  
         {
 706  1
             throw new ConversionException("The value " + value + " can't be converted to a InetAddress");
 707  
         }
 708  
     }
 709  
 
 710  
     /**
 711  
      * Convert the specified value into an email address.
 712  
      *
 713  
      * @param value the value to convert
 714  
      * @return the converted value
 715  
      * @throws ConversionException thrown if the value cannot be converted to an email address
 716  
      *
 717  
      * @since 1.5
 718  
      */
 719  
     static Object toInternetAddress(Object value) throws ConversionException
 720  
     {
 721  5
         if (value.getClass().getName().equals(INTERNET_ADDRESS_CLASSNAME))
 722  
         {
 723  1
             return value;
 724  
         }
 725  4
         else if (value instanceof String)
 726  
         {
 727  
             try
 728  
             {
 729  3
                 Constructor ctor = Class.forName(INTERNET_ADDRESS_CLASSNAME).getConstructor(new Class[] {String.class});
 730  3
                 return ctor.newInstance(new Object[] {value});
 731  
             }
 732  1
             catch (Exception e)
 733  
             {
 734  1
                 throw new ConversionException("The value " + value + " can't be converted to a InternetAddress", e);
 735  
             }
 736  
         }
 737  
         else
 738  
         {
 739  1
             throw new ConversionException("The value " + value + " can't be converted to a InternetAddress");
 740  
         }
 741  
     }
 742  
 
 743  
     /**
 744  
      * Calls Class.isEnum() on Java 5, returns false on older JRE.
 745  
      */
 746  
     static boolean isEnum(Class cls)
 747  
     {
 748  42
         if (!SystemUtils.isJavaVersionAtLeast(JAVA_VERSION_1_5))
 749  
         {
 750  42
             return false;
 751  
         }
 752  
 
 753  
         try
 754  
         {
 755  0
             Method isEnumMethod = Class.class.getMethod("isEnum", new Class[] {});
 756  0
             return ((Boolean) isEnumMethod.invoke(cls, new Object[] {})).booleanValue();
 757  
         }
 758  0
         catch (Exception e)
 759  
         {
 760  
             // impossible
 761  0
             throw new RuntimeException(e.getMessage());
 762  
         }
 763  
     }
 764  
 
 765  
     /**
 766  
      * Convert the specified value into a Java 5 enum.
 767  
      *
 768  
      * @param value the value to convert
 769  
      * @param cls   the type of the enumeration
 770  
      * @return the converted value
 771  
      * @throws ConversionException thrown if the value cannot be converted to an enumeration
 772  
      *
 773  
      * @since 1.5
 774  
      */
 775  
     static Object toEnum(Object value, Class cls) throws ConversionException
 776  
     {
 777  0
         if (value.getClass().equals(cls))
 778  
         {
 779  0
             return value;
 780  
         }
 781  0
         else if (value instanceof String)
 782  
         {
 783  
             try
 784  
             {
 785  0
                 Method valueOfMethod = cls.getMethod("valueOf", new Class[] {String.class});
 786  0
                 return valueOfMethod.invoke(null, new Object[] {value});
 787  
             }
 788  0
             catch (Exception e)
 789  
             {
 790  0
                 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
 791  
             }
 792  
         }
 793  0
         else if (value instanceof Number)
 794  
         {
 795  
             try
 796  
             {
 797  0
                 Method valuesMethod = cls.getMethod("values", new Class[] {});
 798  0
                 Object valuesArray = valuesMethod.invoke(null, new Object[] {});
 799  
 
 800  0
                 return Array.get(valuesArray, ((Number) value).intValue());
 801  
             }
 802  0
             catch (Exception e)
 803  
             {
 804  0
                 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
 805  
             }
 806  
         }
 807  
         else
 808  
         {
 809  0
             throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
 810  
         }
 811  
     }
 812  
 
 813  
     /**
 814  
      * Convert the specified object into a Date.
 815  
      *
 816  
      * @param value  the value to convert
 817  
      * @param format the DateFormat pattern to parse String values
 818  
      * @return the converted value
 819  
      * @throws ConversionException thrown if the value cannot be converted to a Calendar
 820  
      */
 821  
     public static Date toDate(Object value, String format) throws ConversionException
 822  
     {
 823  49
         if (value instanceof Date)
 824  
         {
 825  15
             return (Date) value;
 826  
         }
 827  34
         else if (value instanceof Calendar)
 828  
         {
 829  5
             return ((Calendar) value).getTime();
 830  
         }
 831  29
         else if (value instanceof String)
 832  
         {
 833  
             try
 834  
             {
 835  26
                 return new SimpleDateFormat(format).parse((String) value);
 836  
             }
 837  3
             catch (ParseException e)
 838  
             {
 839  3
                 throw new ConversionException("The value " + value + " can't be converted to a Date", e);
 840  
             }
 841  
         }
 842  
         else
 843  
         {
 844  3
             throw new ConversionException("The value " + value + " can't be converted to a Date");
 845  
         }
 846  
     }
 847  
 
 848  
     /**
 849  
      * Convert the specified object into a Calendar.
 850  
      *
 851  
      * @param value  the value to convert
 852  
      * @param format the DateFormat pattern to parse String values
 853  
      * @return the converted value
 854  
      * @throws ConversionException thrown if the value cannot be converted to a Calendar
 855  
      */
 856  
     public static Calendar toCalendar(Object value, String format) throws ConversionException
 857  
     {
 858  49
         if (value instanceof Calendar)
 859  
         {
 860  10
             return (Calendar) value;
 861  
         }
 862  39
         else if (value instanceof Date)
 863  
         {
 864  10
             Calendar calendar = Calendar.getInstance();
 865  10
             calendar.setTime((Date) value);
 866  10
             return calendar;
 867  
         }
 868  29
         else if (value instanceof String)
 869  
         {
 870  
             try
 871  
             {
 872  26
                 Calendar calendar = Calendar.getInstance();
 873  26
                 calendar.setTime(new SimpleDateFormat(format).parse((String) value));
 874  23
                 return calendar;
 875  
             }
 876  3
             catch (ParseException e)
 877  
             {
 878  3
                 throw new ConversionException("The value " + value + " can't be converted to a Calendar", e);
 879  
             }
 880  
         }
 881  
         else
 882  
         {
 883  3
             throw new ConversionException("The value " + value + " can't be converted to a Calendar");
 884  
         }
 885  
     }
 886  
 
 887  
     /**
 888  
      * Return an iterator over the simple values of a composite value. The value
 889  
      * specified is handled depending on its type:
 890  
      * <ul>
 891  
      *   <li>Strings are checked for delimiter characters and splitted if necessary.</li>
 892  
      *   <li>For collections the single elements are checked.</li>
 893  
      *   <li>Arrays are treated like collections.</li>
 894  
      *   <li>All other types are directly inserted.</li>
 895  
      *   <li>Recursive combinations are supported, e.g. a collection containing array that contain strings.</li>
 896  
      * </ul>
 897  
      *
 898  
      * @param value     the value to "split"
 899  
      * @param delimiter the delimiter for String values
 900  
      * @return an iterator for accessing the single values
 901  
      */
 902  
     public static Iterator toIterator(Object value, char delimiter)
 903  
     {
 904  139239
         if (value == null)
 905  
         {
 906  5
             return IteratorUtils.emptyIterator();
 907  
         }
 908  139234
         if (value instanceof String)
 909  
         {
 910  129161
             String s = (String) value;
 911  129161
             if (s.indexOf(delimiter) > 0)
 912  
             {
 913  7905
                 return split((String) value, delimiter).iterator();
 914  
             }
 915  
             else
 916  
             {
 917  121256
                 return new SingletonIterator(value);
 918  
             }
 919  
         }
 920  10073
         else if (value instanceof Collection)
 921  
         {
 922  1185
             return toIterator(((Collection) value).iterator(), delimiter);
 923  
         }
 924  8888
         else if (value.getClass().isArray())
 925  
         {
 926  8
             return toIterator(IteratorUtils.arrayIterator(value), delimiter);
 927  
         }
 928  8880
         else if (value instanceof Iterator)
 929  
         {
 930  1193
             Iterator iterator = (Iterator) value;
 931  1193
             IteratorChain chain = new IteratorChain();
 932  4046
             while (iterator.hasNext())
 933  
             {
 934  2853
                 chain.addIterator(toIterator(iterator.next(), delimiter));
 935  
             }
 936  1193
             return chain;
 937  
         }
 938  
         else
 939  
         {
 940  7687
             return new SingletonIterator(value);
 941  
         }
 942  
     }
 943  
 
 944  
     /**
 945  
      * Performs interpolation of the specified value. This method checks if the
 946  
      * given value contains variables of the form <code>${...}</code>. If
 947  
      * this is the case, all occurrances will be substituted by their current
 948  
      * values.
 949  
      *
 950  
      * @param value the value to be interpolated
 951  
      * @param config the current configuration object
 952  
      * @return the interpolated value
 953  
      */
 954  
     public static Object interpolate(Object value, AbstractConfiguration config)
 955  
     {
 956  9583
         if (value instanceof String)
 957  
         {
 958  8628
             return config.getSubstitutor().replace((String) value);
 959  
         }
 960  
         else
 961  
         {
 962  955
             return value;
 963  
         }
 964  
     }
 965  
 }