Coverage report

  %line %branch
org.apache.commons.configuration.ConfigurationFactory$HierarchicalConfigurationNodeConverter
100% 
100% 

 1  
 /*
 2  
  * Copyright 2001-2004 The Apache Software Foundation.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License")
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.apache.commons.configuration;
 18  
 
 19  
 import java.io.File;
 20  
 import java.io.IOException;
 21  
 import java.io.InputStream;
 22  
 import java.net.URL;
 23  
 import java.util.Collection;
 24  
 import java.util.Iterator;
 25  
 import java.util.LinkedList;
 26  
 import java.util.Stack;
 27  
 
 28  
 import org.apache.commons.digester.AbstractObjectCreationFactory;
 29  
 import org.apache.commons.digester.Digester;
 30  
 import org.apache.commons.digester.ObjectCreationFactory;
 31  
 import org.apache.commons.digester.xmlrules.DigesterLoader;
 32  
 import org.apache.commons.lang.StringUtils;
 33  
 import org.apache.commons.logging.Log;
 34  
 import org.apache.commons.logging.LogFactory;
 35  
 import org.xml.sax.Attributes;
 36  
 import org.xml.sax.SAXException;
 37  
 
 38  
 /**
 39  
  * Factory class to create a CompositeConfiguration from a .xml file using
 40  
  * Digester.  By default it can handle the Configurations from commons-
 41  
  * configuration.  If you need to add your own, then you can pass in your own
 42  
  * digester rules to use.  It is also namespace aware, by providing a
 43  
  * digesterRuleNamespaceURI.
 44  
  *
 45  
  * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
 46  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 47  
  * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
 48  
  * @version $Id: ConfigurationFactory.java 155408 2005-02-26 12:56:39Z dirkv $
 49  
  */
 50  
 public class ConfigurationFactory
 51  
 {
 52  
     /** Constant for the root element in the info file.*/
 53  
     private static final String SEC_ROOT = "configuration/";
 54  
 
 55  
     /** Constant for the override section.*/
 56  
     private static final String SEC_OVERRIDE = SEC_ROOT + "override/";
 57  
 
 58  
     /** Constant for the additional section.*/
 59  
     private static final String SEC_ADDITIONAL = SEC_ROOT + "additional/";
 60  
     
 61  
     /** Constant for the optional attribute.*/
 62  
     private static final String ATTR_OPTIONAL = "optional";
 63  
     
 64  
     /** Constant for the fileName attribute.*/
 65  
     private static final String ATTR_FILENAME = "fileName";
 66  
 
 67  
     /** Constant for the default base path (points to actual directory).*/
 68  
     private static final String DEF_BASE_PATH = ".";
 69  
 
 70  
     /** static logger */
 71  
     private static Log log = LogFactory.getLog(ConfigurationFactory.class);
 72  
 
 73  
     /** The XML file with the details about the configuration to load */
 74  
     private String configurationFileName;
 75  
 
 76  
     /** The URL to the XML file with the details about the configuration to load. */
 77  
     private URL configurationURL;
 78  
 
 79  
     /**
 80  
      * The implicit base path for included files. This path is determined by
 81  
      * the configuration to load and used unless no other base path was
 82  
      * explicitely specified.
 83  
      */
 84  
     private String implicitBasePath;
 85  
 
 86  
     /** The basePath to prefix file paths for file based property files. */
 87  
     private String basePath;
 88  
 
 89  
     /** URL for xml digester rules file */
 90  
     private URL digesterRules;
 91  
 
 92  
     /** The digester namespace to parse */
 93  
     private String digesterRuleNamespaceURI;
 94  
 
 95  
     /**
 96  
      * Constructor
 97  
      */
 98  
     public ConfigurationFactory()
 99  
     {
 100  
         setBasePath(DEF_BASE_PATH);
 101  
     }
 102  
     /**
 103  
      * Constructor with ConfigurationFile Name passed
 104  
      *
 105  
      * @param configurationFileName The path to the configuration file
 106  
      */
 107  
     public ConfigurationFactory(String configurationFileName)
 108  
     {
 109  
         this.configurationFileName = configurationFileName;
 110  
     }
 111  
 
 112  
     /**
 113  
      * Return the configuration provided by this factory. It loads the
 114  
      * configuration file which is a XML description of the actual
 115  
      * configurations to load. It can contain various different types of
 116  
      * configuration, currently Properties, XML and JNDI.
 117  
      *
 118  
      * @return A Configuration object
 119  
      * @throws ConfigurationException A generic exception that we had trouble during the
 120  
      * loading of the configuration data.
 121  
      */
 122  
     public Configuration getConfiguration() throws ConfigurationException
 123  
     {
 124  
         Digester digester;
 125  
         InputStream input = null;
 126  
         ConfigurationBuilder builder = new ConfigurationBuilder();
 127  
         URL url = getConfigurationURL();
 128  
         try
 129  
         {
 130  
             if (url == null)
 131  
             {
 132  
                 url = ConfigurationUtils.locate(implicitBasePath, getConfigurationFileName());
 133  
             }
 134  
             input = url.openStream();
 135  
         }
 136  
         catch (Exception e)
 137  
         {
 138  
             log.error("Exception caught opening stream to URL", e);
 139  
             throw new ConfigurationException("Exception caught opening stream to URL", e);
 140  
         }
 141  
 
 142  
         if (getDigesterRules() == null)
 143  
         {
 144  
             digester = new Digester();
 145  
             configureNamespace(digester);
 146  
             initDefaultDigesterRules(digester);
 147  
         }
 148  
         else
 149  
         {
 150  
             digester = DigesterLoader.createDigester(getDigesterRules());
 151  
             // This might already be too late. As far as I can see, the namespace
 152  
             // awareness must be configured before the digester rules are loaded.
 153  
             configureNamespace(digester);
 154  
         }
 155  
         
 156  
         // Configure digester to always enable the context class loader
 157  
         digester.setUseContextClassLoader(true);
 158  
         // Put the composite builder object below all of the other objects.
 159  
         digester.push(builder);
 160  
         // Parse the input stream to configure our mappings
 161  
         try
 162  
         {
 163  
             digester.parse(input);
 164  
             input.close();
 165  
         }
 166  
         catch (SAXException saxe)
 167  
         {
 168  
             log.error("SAX Exception caught", saxe);
 169  
             throw new ConfigurationException("SAX Exception caught", saxe);
 170  
         }
 171  
         catch (IOException ioe)
 172  
         {
 173  
             log.error("IO Exception caught", ioe);
 174  
             throw new ConfigurationException("IO Exception caught", ioe);
 175  
         }
 176  
         return builder.getConfiguration();
 177  
     }
 178  
 
 179  
     /**
 180  
      * Returns the configurationFile.
 181  
      *
 182  
      * @return The name of the configuration file. Can be null.
 183  
      */
 184  
     public String getConfigurationFileName()
 185  
     {
 186  
         return configurationFileName;
 187  
     }
 188  
 
 189  
     /**
 190  
      * Sets the configurationFile.
 191  
      *
 192  
      * @param configurationFileName  The name of the configurationFile to use.
 193  
      */
 194  
     public void setConfigurationFileName(String configurationFileName)
 195  
     {
 196  
         File file = new File(configurationFileName).getAbsoluteFile();
 197  
         this.configurationFileName = file.getName();
 198  
         implicitBasePath = file.getParent();
 199  
     }
 200  
 
 201  
     /**
 202  
      * Returns the URL of the configuration file to be loaded.
 203  
      *
 204  
      * @return the URL of the configuration to load
 205  
      */
 206  
     public URL getConfigurationURL()
 207  
     {
 208  
         return configurationURL;
 209  
     }
 210  
 
 211  
     /**
 212  
      * Sets the URL of the configuration to load. This configuration can be
 213  
      * either specified by a file name or by a URL.
 214  
      *
 215  
      * @param url the URL of the configuration to load
 216  
      */
 217  
     public void setConfigurationURL(URL url)
 218  
     {
 219  
         configurationURL = url;
 220  
         implicitBasePath = url.toString();
 221  
 
 222  
         // The following is a hack caused by the need to keep backwards
 223  
         // compatibility: Per default the base path is set to the current
 224  
         // directory. For loading from a URL this makes no sense. So
 225  
         // unless no specific base path was set we clear it.
 226  
         if (DEF_BASE_PATH.equals(getBasePath()))
 227  
         {
 228  
             setBasePath(null);
 229  
         }
 230  
     }
 231  
 
 232  
     /**
 233  
      * Returns the digesterRules.
 234  
      *
 235  
      * @return URL
 236  
      */
 237  
     public URL getDigesterRules()
 238  
     {
 239  
         return digesterRules;
 240  
     }
 241  
 
 242  
     /**
 243  
      * Sets the digesterRules.
 244  
      *
 245  
      * @param digesterRules The digesterRules to set
 246  
      */
 247  
     public void setDigesterRules(URL digesterRules)
 248  
     {
 249  
         this.digesterRules = digesterRules;
 250  
     }
 251  
 
 252  
     /**
 253  
      * Initializes the parsing rules for the default digester
 254  
      *
 255  
      * This allows the Configuration Factory to understand the
 256  
      * default types: Properties, XML and JNDI. Two special sections are
 257  
      * introduced: <code>&lt;override&gt;</code> and
 258  
      * <code>&lt;additional&gt;</code>.
 259  
      *
 260  
      * @param digester The digester to configure
 261  
      */
 262  
     protected void initDefaultDigesterRules(Digester digester)
 263  
     {
 264  
         initDigesterSectionRules(digester, SEC_ROOT, false);
 265  
         initDigesterSectionRules(digester, SEC_OVERRIDE, false);
 266  
         initDigesterSectionRules(digester, SEC_ADDITIONAL, true);
 267  
     }
 268  
 
 269  
     /**
 270  
      * Sets up digester rules for a specified section of the configuration
 271  
      * info file.
 272  
      *
 273  
      * @param digester the current digester instance
 274  
      * @param matchString specifies the section
 275  
      * @param additional a flag if rules for the additional section are to be
 276  
      * added
 277  
      */
 278  
     protected void initDigesterSectionRules(Digester digester, String matchString, boolean additional)
 279  
     {
 280  
         setupDigesterInstance(
 281  
             digester,
 282  
             matchString + "properties",
 283  
             new FileConfigurationFactory(PropertiesConfiguration.class),
 284  
             null,
 285  
             additional);
 286  
 
 287  
         setupDigesterInstance(
 288  
             digester,
 289  
             matchString + "xml",
 290  
             new FileConfigurationFactory(XMLConfiguration.class),
 291  
             null,
 292  
             additional);
 293  
 
 294  
         setupDigesterInstance(
 295  
             digester,
 296  
             matchString + "hierarchicalXml",
 297  
             new FileConfigurationFactory(XMLConfiguration.class),
 298  
             null,
 299  
             additional);
 300  
 
 301  
         setupDigesterInstance(
 302  
             digester,
 303  
             matchString + "jndi",
 304  
             new JNDIConfigurationFactory(),
 305  
             null,
 306  
             additional);
 307  
 
 308  
         setupDigesterInstance(
 309  
             digester,
 310  
             matchString + "system",
 311  
             new SystemConfigurationFactory(),
 312  
             null,
 313  
             additional);
 314  
     }
 315  
 
 316  
     /**
 317  
      * Sets up digester rules for a configuration to be loaded.
 318  
      *
 319  
      * @param digester the current digester
 320  
      * @param matchString the pattern to match with this rule
 321  
      * @param factory an ObjectCreationFactory instance to use for creating new
 322  
      * objects
 323  
      * @param method the name of a method to be called or <b>null</b> for none
 324  
      * @param additional a flag if rules for the additional section are to be
 325  
      * added
 326  
      */
 327  
     protected void setupDigesterInstance(
 328  
             Digester digester,
 329  
             String matchString,
 330  
             ObjectCreationFactory factory,
 331  
             String method,
 332  
             boolean additional)
 333  
     {
 334  
         if (additional)
 335  
         {
 336  
             setupUnionRules(digester, matchString);
 337  
         }
 338  
         digester.addFactoryCreate(matchString, factory);
 339  
         digester.addSetProperties(matchString);
 340  
         if (method != null)
 341  
         {
 342  
             digester.addCallMethod(matchString, method);
 343  
         }
 344  
         digester.addSetNext(
 345  
             matchString,
 346  
             "addConfiguration",
 347  
             Configuration.class.getName());
 348  
     }
 349  
 
 350  
     /**
 351  
      * Sets up rules for configurations in the additional section.
 352  
      *
 353  
      * @param digester the current digester
 354  
      * @param matchString the pattern to match with this rule
 355  
      */
 356  
     protected void setupUnionRules(Digester digester, String matchString)
 357  
     {
 358  
         digester.addObjectCreate(matchString,
 359  
         AdditionalConfigurationData.class);
 360  
         digester.addSetProperties(matchString);
 361  
         digester.addSetNext(matchString, "addAdditionalConfig",
 362  
         AdditionalConfigurationData.class.getName());
 363  
     }
 364  
 
 365  
     /**
 366  
      * Returns the digesterRuleNamespaceURI.
 367  
      *
 368  
      * @return A String with the digesterRuleNamespaceURI.
 369  
      */
 370  
     public String getDigesterRuleNamespaceURI()
 371  
     {
 372  
         return digesterRuleNamespaceURI;
 373  
     }
 374  
 
 375  
     /**
 376  
      * Sets the digesterRuleNamespaceURI.
 377  
      *
 378  
      * @param digesterRuleNamespaceURI The new digesterRuleNamespaceURI to use
 379  
      */
 380  
     public void setDigesterRuleNamespaceURI(String digesterRuleNamespaceURI)
 381  
     {
 382  
         this.digesterRuleNamespaceURI = digesterRuleNamespaceURI;
 383  
     }
 384  
 
 385  
     /**
 386  
      * Configure the current digester to be namespace aware and to have
 387  
      * a Configuration object to which all of the other configurations
 388  
      * should be added
 389  
      *
 390  
      * @param digester The Digester to configure
 391  
      */
 392  
     private void configureNamespace(Digester digester)
 393  
     {
 394  
         if (getDigesterRuleNamespaceURI() != null)
 395  
         {
 396  
             digester.setNamespaceAware(true);
 397  
             digester.setRuleNamespaceURI(getDigesterRuleNamespaceURI());
 398  
         }
 399  
         else
 400  
         {
 401  
             digester.setNamespaceAware(false);
 402  
         }
 403  
         digester.setValidating(false);
 404  
     }
 405  
 
 406  
     /**
 407  
      * Returns the Base path from which this Configuration Factory operates.
 408  
      * This is never null. If you set the BasePath to null, then a base path
 409  
      * according to the configuration to load is returned.
 410  
      *
 411  
      * @return The base Path of this configuration factory.
 412  
      */
 413  
     public String getBasePath()
 414  
     {
 415  
         String path = StringUtils.isEmpty(basePath) ? implicitBasePath : basePath;
 416  
         return StringUtils.isEmpty(path) ? "." : path;
 417  
     }
 418  
 
 419  
     /**
 420  
      * Sets the basePath for all file references from this Configuration Factory.
 421  
      * Normally a base path need not to be set because it is determined by
 422  
      * the location of the configuration file to load. All relative pathes in
 423  
      * this file are resolved relative to this file. Setting a base path makes
 424  
      * sense if such relative pathes should be otherwise resolved, e.g. if
 425  
      * the configuration file is loaded from the class path and all sub
 426  
      * configurations it refers to are stored in a special config directory.
 427  
      *
 428  
      * @param basePath The new basePath to set.
 429  
      */
 430  
     public void setBasePath(String basePath)
 431  
     {
 432  
         this.basePath = basePath;
 433  
     }
 434  
 
 435  
     /**
 436  
      * A base class for digester factory classes. This base class maintains
 437  
      * a default class for the objects to be created.
 438  
      * There will be sub classes for specific configuration implementations.
 439  
      */
 440  
     public class DigesterConfigurationFactory extends AbstractObjectCreationFactory
 441  
     {
 442  
         /** Actual class to use. */
 443  
         private Class clazz;
 444  
 
 445  
         /**
 446  
          * Creates a new instance of <code>DigesterConfigurationFactory</code>.
 447  
          *
 448  
          * @param clazz the class which we should instantiate
 449  
          */
 450  
         public DigesterConfigurationFactory(Class clazz)
 451  
         {
 452  
             this.clazz = clazz;
 453  
         }
 454  
 
 455  
         /**
 456  
          * Creates an instance of the specified class.
 457  
          *
 458  
          * @param attribs the attributes (ignored)
 459  
          * @return the new object
 460  
          * @throws Exception if object creation fails
 461  
          */
 462  
         public Object createObject(Attributes attribs) throws Exception
 463  
         {
 464  
             return clazz.newInstance();
 465  
         }
 466  
     }
 467  
 
 468  
     /**
 469  
      * A tiny inner class that allows the Configuration Factory to
 470  
      * let the digester construct FileConfiguration objects
 471  
      * that already have the correct base Path set.
 472  
      *
 473  
      */
 474  
     public class FileConfigurationFactory extends DigesterConfigurationFactory
 475  
     {
 476  
         /**
 477  
          * C'tor
 478  
          *
 479  
          * @param clazz The class which we should instantiate.
 480  
          */
 481  
         public FileConfigurationFactory(Class clazz)
 482  
         {
 483  
             super(clazz);
 484  
         }
 485  
 
 486  
         /**
 487  
          * Gets called by the digester.
 488  
          *
 489  
          * @param attributes the actual attributes
 490  
          * @return the new object
 491  
          * @throws Exception Couldn't instantiate the requested object.
 492  
          */
 493  
         public Object createObject(Attributes attributes) throws Exception
 494  
         {
 495  
             FileConfiguration conf = (FileConfiguration) super.createObject(attributes);
 496  
             conf.setBasePath(getBasePath());
 497  
             conf.setFileName(attributes.getValue(ATTR_FILENAME));
 498  
             try
 499  
             {
 500  
                 log.info("Trying to load configuration " + conf.getFileName());
 501  
                 conf.load();
 502  
             }
 503  
             catch(ConfigurationException cex)
 504  
             {
 505  
                 if(attributes.getValue(ATTR_OPTIONAL) != null
 506  
                         && PropertyConverter.toBoolean(attributes.getValue(ATTR_OPTIONAL)).booleanValue())
 507  
                 {
 508  
                     log.warn("Could not load optional configuration " + conf.getFileName());
 509  
                 }
 510  
                 else
 511  
                 {
 512  
                     throw cex;
 513  
                 }
 514  
             }
 515  
             return conf;
 516  
         }
 517  
     }
 518  
 
 519  
     /**
 520  
      * A tiny inner class that allows the Configuration Factory to
 521  
      * let the digester construct JNDIConfiguration objects.
 522  
      */
 523  
     private class JNDIConfigurationFactory extends DigesterConfigurationFactory
 524  
     {
 525  
         public JNDIConfigurationFactory()
 526  
         {
 527  
             super(JNDIConfiguration.class);
 528  
         }
 529  
     }
 530  
 
 531  
     /**
 532  
      * A tiny inner class that allows the Configuration Factory to
 533  
      * let the digester construct SystemConfiguration objects.
 534  
      */
 535  
     private class SystemConfigurationFactory extends DigesterConfigurationFactory
 536  
     {
 537  
         public SystemConfigurationFactory()
 538  
         {
 539  
             super(SystemConfiguration.class);
 540  
         }
 541  
     }
 542  
 
 543  
     /**
 544  
      * A simple data class that holds all information about a configuration
 545  
      * from the <code>&lt;additional&gt;</code> section.
 546  
      */
 547  
     public static class AdditionalConfigurationData
 548  
     {
 549  
         /** Stores the configuration object.*/
 550  
         private Configuration configuration;
 551  
 
 552  
         /** Stores the location of this configuration in the global tree.*/
 553  
         private String at;
 554  
 
 555  
         /**
 556  
          * Returns the value of the <code>at</code> attribute.
 557  
          *
 558  
          * @return the at attribute
 559  
          */
 560  
         public String getAt()
 561  
         {
 562  
             return at;
 563  
         }
 564  
 
 565  
         /**
 566  
          * Sets the value of the <code>at</code> attribute.
 567  
          *
 568  
          * @param string the attribute value
 569  
          */
 570  
         public void setAt(String string)
 571  
         {
 572  
             at = string;
 573  
         }
 574  
 
 575  
         /**
 576  
          * Returns the configuration object.
 577  
          *
 578  
          * @return the configuration
 579  
          */
 580  
         public Configuration getConfiguration()
 581  
         {
 582  
             return configuration;
 583  
         }
 584  
 
 585  
         /**
 586  
          * Sets the configuration object. Note: Normally this method should be
 587  
          * named <code>setConfiguration()</code>, but the name
 588  
          * <code>addConfiguration()</code> is required by some of the digester
 589  
          * rules.
 590  
          *
 591  
          * @param config the configuration to set
 592  
          */
 593  
         public void addConfiguration(Configuration config)
 594  
         {
 595  
             configuration = config;
 596  
         }
 597  
     }
 598  
 
 599  
     /**
 600  
      * An internally used helper class for constructing the composite
 601  
      * configuration object.
 602  
      */
 603  
     public static class ConfigurationBuilder
 604  
     {
 605  
         /** Stores the composite configuration.*/
 606  
         private CompositeConfiguration config;
 607  
 
 608  
         /** Stores a collection with the configs from the additional section.*/
 609  
         private Collection additionalConfigs;
 610  
 
 611  
         /**
 612  
          * Creates a new instance of <code>ConfigurationBuilder</code>.
 613  
          */
 614  
         public ConfigurationBuilder()
 615  
         {
 616  
             config = new CompositeConfiguration();
 617  
             additionalConfigs = new LinkedList();
 618  
         }
 619  
 
 620  
         /**
 621  
          * Adds a new configuration to this object. This method is called by
 622  
          * Digester.
 623  
          *
 624  
          * @param conf the configuration to be added
 625  
          */
 626  
         public void addConfiguration(Configuration conf)
 627  
         {
 628  
             config.addConfiguration(conf);
 629  
         }
 630  
 
 631  
         /**
 632  
          * Adds information about an additional configuration. This method is
 633  
          * called by Digester.
 634  
          *
 635  
          * @param data the data about the additional configuration
 636  
          */
 637  
         public void addAdditionalConfig(AdditionalConfigurationData data)
 638  
         {
 639  
             additionalConfigs.add(data);
 640  
         }
 641  
 
 642  
         /**
 643  
          * Returns the final composite configuration.
 644  
          *
 645  
          * @return the final configuration object
 646  
          */
 647  
         public CompositeConfiguration getConfiguration()
 648  
         {
 649  
             if (!additionalConfigs.isEmpty())
 650  
             {
 651  
                 Configuration unionConfig = createAdditionalConfiguration(additionalConfigs);
 652  
                 if (unionConfig != null)
 653  
                 {
 654  
                     addConfiguration(unionConfig);
 655  
                 }
 656  
                 additionalConfigs.clear();
 657  
             }
 658  
 
 659  
             return config;
 660  
         }
 661  
 
 662  
         /**
 663  
          * Creates a configuration object with the union of all properties
 664  
          * defined in the <code>&lt;additional&gt;</code> section. This
 665  
          * implementation returns a <code>HierarchicalConfiguration</code>
 666  
          * object.
 667  
          *
 668  
          * @param configs a collection with
 669  
          * <code>AdditionalConfigurationData</code> objects
 670  
          * @return the union configuration (can be <b>null</b>)
 671  
          */
 672  
         protected Configuration createAdditionalConfiguration(Collection configs)
 673  
         {
 674  
             HierarchicalConfiguration result = new HierarchicalConfiguration();
 675  
 
 676  
             for (Iterator it = configs.iterator(); it.hasNext();)
 677  
             {
 678  
                 AdditionalConfigurationData cdata =
 679  
                 (AdditionalConfigurationData) it.next();
 680  
                 result.addNodes(cdata.getAt(),
 681  
                 createRootNode(cdata).getChildren());
 682  
             }
 683  
 
 684  
             return result.isEmpty() ? null : result;
 685  
         }
 686  
 
 687  
         /**
 688  
          * Creates a configuration root node for the specified configuration.
 689  
          *
 690  
          * @param cdata the configuration data object
 691  
          * @return a root node for this configuration
 692  
          */
 693  
         private HierarchicalConfiguration.Node createRootNode(AdditionalConfigurationData cdata)
 694  
         {
 695  
             if (cdata.getConfiguration() instanceof HierarchicalConfiguration)
 696  
             {
 697  
                 // we can directly use this configuration's root node
 698  
                 return ((HierarchicalConfiguration) cdata.getConfiguration()).getRoot();
 699  
             }
 700  
             else
 701  
             {
 702  
                 // transform configuration to a hierarchical root node
 703  
                 HierarchicalConfigurationNodeConverter conv =
 704  
                 new HierarchicalConfigurationNodeConverter();
 705  
                 conv.process(cdata.getConfiguration());
 706  
                 return conv.getRootNode();
 707  
             }
 708  
         }
 709  
     }
 710  
 
 711  
     /**
 712  
      * A specialized <code>HierarchicalConfigurationConverter</code> class
 713  
      * that creates a <code>HierarchicalConfiguration</code> root node from
 714  
      * an arbitrary <code>Configuration</code> object. This class is used to
 715  
      * add additional configuration objects to the hierarchical configuration
 716  
      * managed by the <code>ConfigurationBuilder</code>.
 717  
      */
 718  
     static class HierarchicalConfigurationNodeConverter extends HierarchicalConfigurationConverter
 719  
     {
 720  
         /** A stack for constructing the hierarchy.*/
 721  
         private Stack nodes;
 722  
 
 723  
         /** Stores the root node.*/
 724  
         private HierarchicalConfiguration.Node root;
 725  
 
 726  
         /**
 727  32
          * Default constructor.
 728  32
          */
 729  32
         public HierarchicalConfigurationNodeConverter()
 730  184
         {
 731  184
             nodes = new Stack();
 732  152
             root = new HierarchicalConfiguration.Node();
 733  152
             nodes.push(root);
 734  152
         }
 735  
 
 736  
         /**
 737  
          * Callback for an element start event. Creates a new node and adds
 738  
          * it to the actual parent.
 739  
          *
 740  
          * @param name the name of the new node
 741  
          * @param value the node's value
 742  692
          */
 743  692
         protected void elementStart(String name, Object value)
 744  692
         {
 745  3287
             HierarchicalConfiguration.Node parent = (HierarchicalConfiguration.Node) nodes.peek();
 746  3651
             HierarchicalConfiguration.Node child = new HierarchicalConfiguration.Node(name);
 747  3287
             if (value != null)
 748  692
             {
 749  2421
                 child.setValue(value);
 750  692
             }
 751  3287
             parent.addChild(child);
 752  3287
             nodes.push(child);
 753  3287
         }
 754  
 
 755  
         /**
 756  
          * Callback for an element end event. Clears the stack.
 757  
          *
 758  
          * @param name the name of the element
 759  692
          */
 760  692
         protected void elementEnd(String name)
 761  
         {
 762  3287
             nodes.pop();
 763  3287
         }
 764  
 
 765  
         /**
 766  
          * Returns the constructed root node.
 767  
          *
 768  
          * @return the root node
 769  32
          */
 770  
         public HierarchicalConfiguration.Node getRootNode()
 771  
         {
 772  152
             return root;
 773  
         }
 774  
     }
 775  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.