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

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