Coverage Report - org.apache.commons.configuration.ConfigurationUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ConfigurationUtils
92%
136/148
100%
37/37
4,722
 
 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.io.File;
 21  
 import java.io.IOException;
 22  
 import java.io.InputStream;
 23  
 import java.io.PrintStream;
 24  
 import java.io.PrintWriter;
 25  
 import java.io.StringWriter;
 26  
 import java.lang.reflect.InvocationTargetException;
 27  
 import java.lang.reflect.Method;
 28  
 import java.net.MalformedURLException;
 29  
 import java.net.URL;
 30  
 import java.net.URLDecoder;
 31  
 import java.util.Iterator;
 32  
 
 33  
 import org.apache.commons.lang.StringUtils;
 34  
 import org.apache.commons.logging.Log;
 35  
 import org.apache.commons.logging.LogFactory;
 36  
 
 37  
 /**
 38  
  * Miscellaneous utility methods for configurations.
 39  
  *
 40  
  * @see ConfigurationConverter Utility methods to convert configurations.
 41  
  *
 42  
  * @author <a href="mailto:herve.quiroz@esil.univ-mrs.fr">Herve Quiroz</a>
 43  
  * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
 44  
  * @author Emmanuel Bourg
 45  
  * @version $Revision: 439648 $, $Date: 2006-09-02 22:42:10 +0200 (Sa, 02 Sep 2006) $
 46  
  */
 47  28
 public final class ConfigurationUtils
 48  
 {
 49  
     /** Constant for the file URL protocol.*/
 50  
     static final String PROTOCOL_FILE = "file";
 51  
 
 52  
     /** Constant for the resource path separator.*/
 53  
     static final String RESOURCE_PATH_SEPARATOR = "/";
 54  
 
 55  
     /** Constant for the name of the clone() method.*/
 56  
     private static final String METHOD_CLONE = "clone";
 57  
 
 58  
     /** The logger.*/
 59  28
     private static Log log = LogFactory.getLog(ConfigurationUtils.class);
 60  
 
 61  
     /**
 62  
      * Private constructor. Prevents instances from being created.
 63  
      */
 64  
     private ConfigurationUtils()
 65  0
     {
 66  
         // to prevent instanciation...
 67  0
     }
 68  
 
 69  
     /**
 70  
      * Dump the configuration key/value mappings to some ouput stream.
 71  
      *
 72  
      * @param configuration the configuration
 73  
      * @param out the output stream to dump the configuration to
 74  
      */
 75  
     public static void dump(Configuration configuration, PrintStream out)
 76  
     {
 77  0
         dump(configuration, new PrintWriter(out));
 78  0
     }
 79  
 
 80  
     /**
 81  
      * Dump the configuration key/value mappings to some writer.
 82  
      *
 83  
      * @param configuration the configuration
 84  
      * @param out the writer to dump the configuration to
 85  
      */
 86  
     public static void dump(Configuration configuration, PrintWriter out)
 87  
     {
 88  5
         Iterator keys = configuration.getKeys();
 89  16
         while (keys.hasNext())
 90  
         {
 91  6
             String key = (String) keys.next();
 92  6
             Object value = configuration.getProperty(key);
 93  6
             out.print(key);
 94  6
             out.print("=");
 95  6
             out.print(value);
 96  
 
 97  6
             if (keys.hasNext())
 98  
             {
 99  2
                 out.println();
 100  
             }
 101  
         }
 102  
 
 103  5
         out.flush();
 104  5
     }
 105  
 
 106  
     /**
 107  
      * Get a string representation of the key/value mappings of a
 108  
      * configuration.
 109  
      *
 110  
      * @param configuration the configuration
 111  
      * @return a string representation of the configuration
 112  
      */
 113  
     public static String toString(Configuration configuration)
 114  
     {
 115  5
         StringWriter writer = new StringWriter();
 116  5
         dump(configuration, new PrintWriter(writer));
 117  5
         return writer.toString();
 118  
     }
 119  
 
 120  
     /**
 121  
      * Copy all properties from the source configuration to the target
 122  
      * configuration. Properties in the target configuration are replaced with
 123  
      * the properties with the same key in the source configuration.
 124  
      * <em>Note:</em> This method won't work well on hierarchical configurations
 125  
      * because it is not able to copy information about the properties'
 126  
      * structure. So when dealing with hierarchical configuration objects their
 127  
      * <code>{@link HierarchicalConfiguration#clone() clone()}</code> methods
 128  
      * should be used.
 129  
      *
 130  
      * @param source the source configuration
 131  
      * @param target the target configuration
 132  
      * @since 1.1
 133  
      */
 134  
     public static void copy(Configuration source, Configuration target)
 135  
     {
 136  43
         Iterator keys = source.getKeys();
 137  1182
         while (keys.hasNext())
 138  
         {
 139  1096
             String key = (String) keys.next();
 140  1096
             target.setProperty(key, source.getProperty(key));
 141  
         }
 142  43
     }
 143  
 
 144  
     /**
 145  
      * Append all properties from the source configuration to the target
 146  
      * configuration. Properties in the source configuration are appended to
 147  
      * the properties with the same key in the target configuration.
 148  
      *
 149  
      * @param source the source configuration
 150  
      * @param target the target configuration
 151  
      * @since 1.1
 152  
      */
 153  
     public static void append(Configuration source, Configuration target)
 154  
     {
 155  1
         Iterator keys = source.getKeys();
 156  4
         while (keys.hasNext())
 157  
         {
 158  2
             String key = (String) keys.next();
 159  2
             target.addProperty(key, source.getProperty(key));
 160  
         }
 161  1
     }
 162  
 
 163  
     /**
 164  
      * Converts the passed in configuration to a hierarchical one. If the
 165  
      * configuration is already hierarchical, it is directly returned. Otherwise
 166  
      * all properties are copied into a new hierarchical configuration.
 167  
      *
 168  
      * @param conf the configuration to convert
 169  
      * @return the new hierarchical configuration (the result is <b>null</b> if
 170  
      * and only if the passed in configuration is <b>null</b>)
 171  
      * @since 1.3
 172  
      */
 173  
     public static HierarchicalConfiguration convertToHierarchical(
 174  
             Configuration conf)
 175  
     {
 176  73
         if (conf == null)
 177  
         {
 178  1
             return null;
 179  
         }
 180  
 
 181  72
         if (conf instanceof HierarchicalConfiguration)
 182  
         {
 183  38
             return (HierarchicalConfiguration) conf;
 184  
         }
 185  
         else
 186  
         {
 187  34
             HierarchicalConfiguration hc = new HierarchicalConfiguration();
 188  34
             ConfigurationUtils.copy(conf, hc);
 189  34
             return hc;
 190  
         }
 191  
     }
 192  
 
 193  
     /**
 194  
      * Clones the given configuration object if this is possible. If the passed
 195  
      * in configuration object implements the <code>Cloneable</code>
 196  
      * interface, its <code>clone()</code> method will be invoked. Otherwise
 197  
      * an exception will be thrown.
 198  
      *
 199  
      * @param config the configuration object to be cloned (can be <b>null</b>)
 200  
      * @return the cloned configuration (<b>null</b> if the argument was
 201  
      * <b>null</b>, too)
 202  
      * @throws ConfigurationRuntimeException if cloning is not supported for
 203  
      * this object
 204  
      * @since 1.3
 205  
      */
 206  
     public static Configuration cloneConfiguration(Configuration config)
 207  
             throws ConfigurationRuntimeException
 208  
     {
 209  11
         if (config == null)
 210  
         {
 211  1
             return null;
 212  
         }
 213  
         else
 214  
         {
 215  
             try
 216  
             {
 217  10
                 return (Configuration) clone(config);
 218  
             }
 219  
             catch (CloneNotSupportedException cnex)
 220  
             {
 221  2
                 throw new ConfigurationRuntimeException(cnex);
 222  
             }
 223  
         }
 224  
     }
 225  
 
 226  
     /**
 227  
      * An internally used helper method for cloning objects. This implementation
 228  
      * is not very sophisticated nor efficient. Maybe it can be replaced by an
 229  
      * implementation from Commons Lang later. The method checks whether the
 230  
      * passed in object implements the <code>Cloneable</code> interface. If
 231  
      * this is the case, the <code>clone()</code> method is invoked by
 232  
      * reflection. Errors that occur during the cloning process are re-thrown as
 233  
      * runtime exceptions.
 234  
      *
 235  
      * @param obj the object to be cloned
 236  
      * @return the cloned object
 237  
      * @throws CloneNotSupportedException if the object cannot be cloned
 238  
      */
 239  
     static Object clone(Object obj) throws CloneNotSupportedException
 240  
     {
 241  21
         if (obj instanceof Cloneable)
 242  
         {
 243  
             try
 244  
             {
 245  19
                 Method m = obj.getClass().getMethod(METHOD_CLONE, null);
 246  19
                 return m.invoke(obj, null);
 247  
             }
 248  
             catch (NoSuchMethodException nmex)
 249  
             {
 250  0
                 throw new CloneNotSupportedException(
 251  
                         "No clone() method found for class"
 252  
                                 + obj.getClass().getName());
 253  
             }
 254  
             catch (IllegalAccessException iaex)
 255  
             {
 256  0
                 throw new ConfigurationRuntimeException(iaex);
 257  
             }
 258  
             catch (InvocationTargetException itex)
 259  
             {
 260  0
                 throw new ConfigurationRuntimeException(itex);
 261  
             }
 262  
         }
 263  
         else
 264  
         {
 265  2
             throw new CloneNotSupportedException(obj.getClass().getName()
 266  
                     + " does not implement Cloneable");
 267  
         }
 268  
     }
 269  
 
 270  
     /**
 271  
      * Constructs a URL from a base path and a file name. The file name can
 272  
      * be absolute, relative or a full URL. If necessary the base path URL is
 273  
      * applied.
 274  
      *
 275  
      * @param basePath the base path URL (can be <b>null</b>)
 276  
      * @param file the file name
 277  
      * @return the resulting URL
 278  
      * @throws MalformedURLException if URLs are invalid
 279  
      */
 280  
     public static URL getURL(String basePath, String file) throws MalformedURLException
 281  
     {
 282  8
         File f = new File(file);
 283  8
         if (f.isAbsolute()) // already absolute?
 284  
         {
 285  2
             return f.toURL();
 286  
         }
 287  
 
 288  
         try
 289  
         {
 290  6
             if (basePath == null)
 291  
             {
 292  2
                 return new URL(file);
 293  
             }
 294  
             else
 295  
             {
 296  4
                 URL base = new URL(basePath);
 297  3
                 return new URL(base, file);
 298  
             }
 299  
         }
 300  
         catch (MalformedURLException uex)
 301  
         {
 302  2
             return constructFile(basePath, file).toURL();
 303  
         }
 304  
     }
 305  
 
 306  
     /**
 307  
      * Helper method for constructing a file object from a base path and a
 308  
      * file name. This method is called if the base path passed to
 309  
      * <code>getURL()</code> does not seem to be a valid URL.
 310  
      *
 311  
      * @param basePath the base path
 312  
      * @param fileName the file name
 313  
      * @return the resulting file
 314  
      */
 315  
     static File constructFile(String basePath, String fileName)
 316  
     {
 317  404
         File file = null;
 318  
 
 319  404
         File absolute = null;
 320  404
         if (fileName != null)
 321  
         {
 322  404
             absolute = new File(fileName);
 323  
         }
 324  
 
 325  404
         if (StringUtils.isEmpty(basePath) || (absolute != null && absolute.isAbsolute()))
 326  
         {
 327  49
             file = new File(fileName);
 328  
         }
 329  
         else
 330  
         {
 331  355
             StringBuffer fName = new StringBuffer();
 332  355
             fName.append(basePath);
 333  
 
 334  
             // My best friend. Paranoia.
 335  355
             if (!basePath.endsWith(File.separator))
 336  
             {
 337  355
                 fName.append(File.separator);
 338  
             }
 339  
 
 340  
             //
 341  
             // We have a relative path, and we have
 342  
             // two possible forms here. If we have the
 343  
             // "./" form then just strip that off first
 344  
             // before continuing.
 345  
             //
 346  355
             if (fileName.startsWith("." + File.separator))
 347  
             {
 348  0
                 fName.append(fileName.substring(2));
 349  
             }
 350  
             else
 351  
             {
 352  355
                 fName.append(fileName);
 353  
             }
 354  
 
 355  355
             file = new File(fName.toString());
 356  
         }
 357  
 
 358  404
         return file;
 359  
     }
 360  
 
 361  
     /**
 362  
      * Return the location of the specified resource by searching the user home
 363  
      * directory, the current classpath and the system classpath.
 364  
      *
 365  
      * @param name the name of the resource
 366  
      *
 367  
      * @return the location of the resource
 368  
      */
 369  
     public static URL locate(String name)
 370  
     {
 371  1
         return locate(null, name);
 372  
     }
 373  
 
 374  
     /**
 375  
      * Return the location of the specified resource by searching the user home
 376  
      * directory, the current classpath and the system classpath.
 377  
      *
 378  
      * @param base the base path of the resource
 379  
      * @param name the name of the resource
 380  
      *
 381  
      * @return the location of the resource
 382  
      */
 383  
     public static URL locate(String base, String name)
 384  
     {
 385  933
         if (name == null)
 386  
         {
 387  
             // undefined, always return null
 388  4
             return null;
 389  
         }
 390  
 
 391  929
         URL url = null;
 392  
 
 393  
         // attempt to create an URL directly
 394  
         try
 395  
         {
 396  929
             if (base == null)
 397  
             {
 398  270
                 url = new URL(name);
 399  
             }
 400  
             else
 401  
             {
 402  659
                 URL baseURL = new URL(base);
 403  381
                 url = new URL(baseURL, name);
 404  
 
 405  
                 // check if the file exists
 406  380
                 InputStream in = null;
 407  
                 try
 408  
                 {
 409  380
                     in = url.openStream();
 410  364
                 }
 411  
                 finally
 412  
                 {
 413  16
                     if (in != null)
 414  
                     {
 415  364
                         in.close();
 416  
                     }
 417  
                 }
 418  
             }
 419  
 
 420  364
             log.debug("Configuration loaded from the URL " + url);
 421  364
         }
 422  
         catch (IOException e)
 423  
         {
 424  565
             url = null;
 425  
         }
 426  
 
 427  
         // attempt to load from an absolute path
 428  929
         if (url == null)
 429  
         {
 430  565
             File file = new File(name);
 431  565
             if (file.isAbsolute() && file.exists()) // already absolute?
 432  
             {
 433  
                 try
 434  
                 {
 435  231
                     url = file.toURL();
 436  231
                     log.debug("Configuration loaded from the absolute path " + name);
 437  231
                 }
 438  
                 catch (MalformedURLException e)
 439  
                 {
 440  0
                     e.printStackTrace();
 441  
                 }
 442  
             }
 443  
         }
 444  
 
 445  
         // attempt to load from the base directory
 446  929
         if (url == null)
 447  
         {
 448  
             try
 449  
             {
 450  334
                 File file = constructFile(base, name);
 451  334
                 if (file != null && file.exists())
 452  
                 {
 453  290
                     url = file.toURL();
 454  
                 }
 455  
 
 456  334
                 if (url != null)
 457  
                 {
 458  290
                     log.debug("Configuration loaded from the base path " + name);
 459  
                 }
 460  334
             }
 461  
             catch (IOException e)
 462  
             {
 463  0
                 e.printStackTrace();
 464  
             }
 465  
         }
 466  
 
 467  
         // attempt to load from the user home directory
 468  929
         if (url == null)
 469  
         {
 470  
             try
 471  
             {
 472  44
                 File file = constructFile(System.getProperty("user.home"), name);
 473  44
                 if (file != null && file.exists())
 474  
                 {
 475  1
                     url = file.toURL();
 476  
                 }
 477  
 
 478  44
                 if (url != null)
 479  
                 {
 480  1
                     log.debug("Configuration loaded from the home path " + name);
 481  
                 }
 482  
 
 483  44
             }
 484  
             catch (IOException e)
 485  
             {
 486  0
                 e.printStackTrace();
 487  
             }
 488  
         }
 489  
 
 490  
         // attempt to load from classpath
 491  929
         if (url == null)
 492  
         {
 493  43
             url = locateFromClasspath(name);
 494  
         }
 495  929
         return url;
 496  
     }
 497  
 
 498  
     /**
 499  
      * Tries to find a resource with the given name in the classpath.
 500  
      * @param resourceName the name of the resource
 501  
      * @return the URL to the found resource or <b>null</b> if the resource
 502  
      * cannot be found
 503  
      */
 504  
     static URL locateFromClasspath(String resourceName)
 505  
     {
 506  43
         URL url = null;
 507  
         // attempt to load from the context classpath
 508  43
         ClassLoader loader = Thread.currentThread().getContextClassLoader();
 509  43
         if (loader != null)
 510  
         {
 511  41
             url = loader.getResource(resourceName);
 512  
 
 513  41
             if (url != null)
 514  
             {
 515  18
                 log.debug("Configuration loaded from the context classpath (" + resourceName + ")");
 516  
             }
 517  
         }
 518  
 
 519  
         // attempt to load from the system classpath
 520  43
         if (url == null)
 521  
         {
 522  25
             url = ClassLoader.getSystemResource(resourceName);
 523  
 
 524  25
             if (url != null)
 525  
             {
 526  1
                 log.debug("Configuration loaded from the system classpath (" + resourceName + ")");
 527  
             }
 528  
         }
 529  43
         return url;
 530  
     }
 531  
 
 532  
     /**
 533  
      * Return the path without the file name, for example http://xyz.net/foo/bar.xml
 534  
      * results in http://xyz.net/foo/
 535  
      *
 536  
      * @param url the URL from which to extract the path
 537  
      * @return the path component of the passed in URL
 538  
      */
 539  
     static String getBasePath(URL url)
 540  
     {
 541  19
         if (url == null)
 542  
         {
 543  0
             return null;
 544  
         }
 545  
 
 546  19
         String s = url.toString();
 547  
 
 548  19
         if (s.endsWith("/") || StringUtils.isEmpty(url.getPath()))
 549  
         {
 550  3
             return s;
 551  
         }
 552  
         else
 553  
         {
 554  16
             return s.substring(0, s.lastIndexOf("/") + 1);
 555  
         }
 556  
     }
 557  
 
 558  
     /**
 559  
      * Extract the file name from the specified URL.
 560  
      *
 561  
      * @param url the URL from which to extract the file name
 562  
      * @return the extracted file name
 563  
      */
 564  
     static String getFileName(URL url)
 565  
     {
 566  17
         if (url == null)
 567  
         {
 568  1
             return null;
 569  
         }
 570  
 
 571  16
         String path = url.getPath();
 572  
 
 573  16
         if (path.endsWith("/") || StringUtils.isEmpty(path))
 574  
         {
 575  1
             return null;
 576  
         }
 577  
         else
 578  
         {
 579  15
             return path.substring(path.lastIndexOf("/") + 1);
 580  
         }
 581  
     }
 582  
 
 583  
     /**
 584  
      * Tries to convert the specified base path and file name into a file object.
 585  
      * This method is called e.g. by the save() methods of file based
 586  
      * configurations. The parameter strings can be relative files, absolute
 587  
      * files and URLs as well.
 588  
      *
 589  
      * @param basePath the base path
 590  
      * @param fileName the file name
 591  
      * @return the file object (<b>null</b> if no file can be obtained)
 592  
      */
 593  
     public static File getFile(String basePath, String fileName)
 594  
     {
 595  
         // Check if URLs are involved
 596  
         URL url;
 597  
         try
 598  
         {
 599  29
             url = new URL(new URL(basePath), fileName);
 600  3
         }
 601  
         catch (MalformedURLException mex1)
 602  
         {
 603  26
             try
 604  
             {
 605  26
                 url = new URL(fileName);
 606  2
             }
 607  
             catch (MalformedURLException mex2)
 608  
             {
 609  24
                 url = null;
 610  
             }
 611  
         }
 612  
 
 613  29
         if (url != null)
 614  
         {
 615  5
             return fileFromURL(url);
 616  
         }
 617  
 
 618  24
         return constructFile(basePath, fileName);
 619  
     }
 620  
 
 621  
     /**
 622  
      * Tries to convert the specified URL to a file object. If this fails,
 623  
      * <b>null</b> is returned.
 624  
      *
 625  
      * @param url the URL
 626  
      * @return the resulting file object
 627  
      */
 628  
     public static File fileFromURL(URL url)
 629  
     {
 630  1128
         if (PROTOCOL_FILE.equals(url.getProtocol()))
 631  
         {
 632  1126
             return new File(URLDecoder.decode(url.getPath()));
 633  
         }
 634  
         else
 635  
         {
 636  2
             return null;
 637  
         }
 638  
     }
 639  
 }