Coverage report

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

 1  
 /*
 2  
  * Copyright 2001-2005 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.configuration.plist.PropertyListConfiguration;
 29  
 import org.apache.commons.configuration.plist.XMLPropertyListConfiguration;
 30  
 import org.apache.commons.digester.AbstractObjectCreationFactory;
 31  
 import org.apache.commons.digester.Digester;
 32  
 import org.apache.commons.digester.ObjectCreationFactory;
 33  
 import org.apache.commons.digester.xmlrules.DigesterLoader;
 34  
 import org.apache.commons.lang.StringUtils;
 35  
 import org.apache.commons.logging.Log;
 36  
 import org.apache.commons.logging.LogFactory;
 37  
 import org.xml.sax.Attributes;
 38  
 import org.xml.sax.SAXException;
 39  
 
 40  
 /**
 41  
  * Factory class to create a CompositeConfiguration from a .xml file using
 42  
  * Digester.  By default it can handle the Configurations from commons-
 43  
  * configuration.  If you need to add your own, then you can pass in your own
 44  
  * digester rules to use.  It is also namespace aware, by providing a
 45  
  * digesterRuleNamespaceURI.
 46  
  *
 47  
  * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
 48  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 49  
  * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
 50  
  * @version $Id: ConfigurationFactory.java 295090 2005-10-05 19:36:15Z oheger $
 51  
  */
 52  
 public class ConfigurationFactory
 53  
 {
 54  
     /** Constant for the root element in the info file.*/
 55  
     private static final String SEC_ROOT = "configuration/";
 56  
 
 57  
     /** Constant for the override section.*/
 58  
     private static final String SEC_OVERRIDE = SEC_ROOT + "override/";
 59  
 
 60  
     /** Constant for the additional section.*/
 61  
     private static final String SEC_ADDITIONAL = SEC_ROOT + "additional/";
 62  
 
 63  
     /** Constant for the optional attribute.*/
 64  
     private static final String ATTR_OPTIONAL = "optional";
 65  
 
 66  
     /** Constant for the fileName attribute.*/
 67  
     private static final String ATTR_FILENAME = "fileName";
 68  
 
 69  
     /** Constant for the default base path (points to actual directory).*/
 70  
     private static final String DEF_BASE_PATH = ".";
 71  
 
 72  
     /** static logger */
 73  
     private static Log log = LogFactory.getLog(ConfigurationFactory.class);
 74  
 
 75  
     /** The XML file with the details about the configuration to load */
 76  
     private String configurationFileName;
 77  
 
 78  
     /** The URL to the XML file with the details about the configuration to load. */
 79  
     private URL configurationURL;
 80  
 
 81  
     /**
 82  
      * The implicit base path for included files. This path is determined by
 83  
      * the configuration to load and used unless no other base path was
 84  
      * explicitely specified.
 85  
      */
 86  
     private String implicitBasePath;
 87  
 
 88  
     /** The basePath to prefix file paths for file based property files. */
 89  
     private String basePath;
 90  
 
 91  
     /** URL for xml digester rules file */
 92  
     private URL digesterRules;
 93  
 
 94  
     /** The digester namespace to parse */
 95  
     private String digesterRuleNamespaceURI;
 96  
 
 97  
     /**
 98  
      * Constructor
 99  
      */
 100  
     public ConfigurationFactory()
 101  
     {
 102  
         setBasePath(DEF_BASE_PATH);
 103  
     }
 104  
     /**
 105  
      * Constructor with ConfigurationFile Name passed
 106  
      *
 107  
      * @param configurationFileName The path to the configuration file
 108  
      */
 109  
     public ConfigurationFactory(String configurationFileName)
 110  
     {
 111  
         setConfigurationFileName(configurationFileName);
 112  
     }
 113  
 
 114  
     /**
 115  
      * Return the configuration provided by this factory. It loads the
 116  
      * configuration file which is a XML description of the actual
 117  
      * configurations to load. It can contain various different types of
 118  
      * configuration, e.g. Properties, XML and JNDI.
 119  
      *
 120  
      * @return A Configuration object
 121  
      * @throws ConfigurationException A generic exception that we had trouble during the
 122  
      * loading of the configuration data.
 123  
      */
 124  
     public Configuration getConfiguration() throws ConfigurationException
 125  
     {
 126  
         Digester digester;
 127  
         InputStream input = null;
 128  
         ConfigurationBuilder builder = new ConfigurationBuilder();
 129  
         URL url = getConfigurationURL();
 130  
         try
 131  
         {
 132  
             if (url == null)
 133  
             {
 134  
                 url = ConfigurationUtils.locate(implicitBasePath, getConfigurationFileName());
 135  
             }
 136  
             input = url.openStream();
 137  
         }
 138  
         catch (Exception e)
 139  
         {
 140  
             log.error("Exception caught opening stream to URL", e);
 141  
             throw new ConfigurationException("Exception caught opening stream to URL", e);
 142  
         }
 143  
 
 144  
         if (getDigesterRules() == null)
 145  
         {
 146  
             digester = new Digester();
 147  
             configureNamespace(digester);
 148  
             initDefaultDigesterRules(digester);
 149  
         }
 150  
         else
 151  
         {
 152  
             digester = DigesterLoader.createDigester(getDigesterRules());
 153  
             // This might already be too late. As far as I can see, the namespace
 154  
             // awareness must be configured before the digester rules are loaded.
 155  
             configureNamespace(digester);
 156  
         }
 157  
 
 158  
         // Configure digester to always enable the context class loader
 159  
         digester.setUseContextClassLoader(true);
 160  
         // Put the composite builder object below all of the other objects.
 161  
         digester.push(builder);
 162  
         // Parse the input stream to configure our mappings
 163  
         try
 164  
         {
 165  
             digester.parse(input);
 166  
             input.close();
 167  
         }
 168  
         catch (SAXException saxe)
 169  
         {
 170  
             log.error("SAX Exception caught", saxe);
 171  
             throw new ConfigurationException("SAX Exception caught", saxe);
 172  
         }
 173  
         catch (IOException ioe)
 174  
         {
 175  
             log.error("IO Exception caught", ioe);
 176  
             throw new ConfigurationException("IO Exception caught", ioe);
 177  
         }
 178  
         return builder.getConfiguration();
 179  
     }
 180  
 
 181  
     /**
 182  
      * Returns the configurationFile.
 183  
      *
 184  
      * @return The name of the configuration file. Can be null.
 185  
      */
 186  
     public String getConfigurationFileName()
 187  
     {
 188  
         return configurationFileName;
 189  
     }
 190  
 
 191  
     /**
 192  
      * Sets the configurationFile.
 193  
      *
 194  
      * @param configurationFileName  The name of the configurationFile to use.
 195  
      */
 196  
     public void setConfigurationFileName(String configurationFileName)
 197  
     {
 198  
         File file = new File(configurationFileName).getAbsoluteFile();
 199  
         this.configurationFileName = file.getName();
 200  
         implicitBasePath = file.getParent();
 201  
     }
 202  
 
 203  
     /**
 204  
      * Returns the URL of the configuration file to be loaded.
 205  
      *
 206  
      * @return the URL of the configuration to load
 207  
      */
 208  
     public URL getConfigurationURL()
 209  
     {
 210  
         return configurationURL;
 211  
     }
 212  
 
 213  
     /**
 214  
      * Sets the URL of the configuration to load. This configuration can be
 215  
      * either specified by a file name or by a URL.
 216  
      *
 217  
      * @param url the URL of the configuration to load
 218  
      */
 219  
     public void setConfigurationURL(URL url)
 220  
     {
 221  
         configurationURL = url;
 222  
         implicitBasePath = url.toString();
 223  
     }
 224  
 
 225  
     /**
 226  
      * Returns the digesterRules.
 227  
      *
 228  
      * @return URL
 229  
      */
 230  
     public URL getDigesterRules()
 231  
     {
 232  
         return digesterRules;
 233  
     }
 234  
 
 235  
     /**
 236  
      * Sets the digesterRules.
 237  
      *
 238  
      * @param digesterRules The digesterRules to set
 239  
      */
 240  
     public void setDigesterRules(URL digesterRules)
 241  
     {
 242  
         this.digesterRules = digesterRules;
 243  
     }
 244  
 
 245  
     /**
 246  
      * Initializes the parsing rules for the default digester
 247  
      *
 248  
      * This allows the Configuration Factory to understand the
 249  
      * default types: Properties, XML and JNDI. Two special sections are
 250  
      * introduced: <code>&lt;override&gt;</code> and
 251  
      * <code>&lt;additional&gt;</code>.
 252  
      *
 253  
      * @param digester The digester to configure
 254  
      */
 255  
     protected void initDefaultDigesterRules(Digester digester)
 256  
     {
 257  
         initDigesterSectionRules(digester, SEC_ROOT, false);
 258  
         initDigesterSectionRules(digester, SEC_OVERRIDE, false);
 259  
         initDigesterSectionRules(digester, SEC_ADDITIONAL, true);
 260  
     }
 261  
 
 262  
     /**
 263  
      * Sets up digester rules for a specified section of the configuration
 264  
      * info file.
 265  
      *
 266  
      * @param digester the current digester instance
 267  
      * @param matchString specifies the section
 268  
      * @param additional a flag if rules for the additional section are to be
 269  
      * added
 270  
      */
 271  
     protected void initDigesterSectionRules(Digester digester, String matchString, boolean additional)
 272  
     {
 273  
         setupDigesterInstance(
 274  
             digester,
 275  
             matchString + "properties",
 276  
             new PropertiesConfigurationFactory(),
 277  
             null,
 278  
             additional);
 279  
 
 280  
         setupDigesterInstance(
 281  
             digester,
 282  
             matchString + "plist",
 283  
             new PropertyListConfigurationFactory(),
 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  
 
 339  
         digester.addFactoryCreate(matchString, factory);
 340  
         digester.addSetProperties(matchString);
 341  
 
 342  
         if (method != null)
 343  
         {
 344  
             digester.addCallMethod(matchString, method);
 345  
         }
 346  
 
 347  
         digester.addSetNext(matchString, "addConfiguration", 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)
 416  
                 || DEF_BASE_PATH.equals(basePath) ? implicitBasePath : basePath;
 417  
         return StringUtils.isEmpty(path) ? DEF_BASE_PATH : path;
 418  
     }
 419  
 
 420  
     /**
 421  
      * Sets the basePath for all file references from this Configuration Factory.
 422  
      * Normally a base path need not to be set because it is determined by
 423  
      * the location of the configuration file to load. All relative pathes in
 424  
      * this file are resolved relative to this file. Setting a base path makes
 425  
      * sense if such relative pathes should be otherwise resolved, e.g. if
 426  
      * the configuration file is loaded from the class path and all sub
 427  
      * configurations it refers to are stored in a special config directory.
 428  
      *
 429  
      * @param basePath The new basePath to set.
 430  
      */
 431  
     public void setBasePath(String basePath)
 432  
     {
 433  
         this.basePath = basePath;
 434  
     }
 435  
 
 436  
     /**
 437  
      * A base class for digester factory classes. This base class maintains
 438  
      * a default class for the objects to be created.
 439  
      * There will be sub classes for specific configuration implementations.
 440  
      */
 441  
     public class DigesterConfigurationFactory extends AbstractObjectCreationFactory
 442  
     {
 443  
         /** Actual class to use. */
 444  
         private Class clazz;
 445  
 
 446  
         /**
 447  
          * Creates a new instance of <code>DigesterConfigurationFactory</code>.
 448  
          *
 449  
          * @param clazz the class which we should instantiate
 450  
          */
 451  
         public DigesterConfigurationFactory(Class clazz)
 452  
         {
 453  
             this.clazz = clazz;
 454  
         }
 455  
 
 456  
         /**
 457  
          * Creates an instance of the specified class.
 458  
          *
 459  
          * @param attribs the attributes (ignored)
 460  
          * @return the new object
 461  
          * @throws Exception if object creation fails
 462  
          */
 463  
         public Object createObject(Attributes attribs) throws Exception
 464  
         {
 465  
             return clazz.newInstance();
 466  
         }
 467  
     }
 468  
 
 469  
     /**
 470  
      * A tiny inner class that allows the Configuration Factory to
 471  
      * let the digester construct FileConfiguration objects
 472  
      * that already have the correct base Path set.
 473  
      *
 474  
      */
 475  
     public class FileConfigurationFactory extends DigesterConfigurationFactory
 476  
     {
 477  
         /**
 478  
          * C'tor
 479  
          *
 480  
          * @param clazz The class which we should instantiate.
 481  
          */
 482  
         public FileConfigurationFactory(Class clazz)
 483  900
         {
 484  900
             super(clazz);
 485  900
         }
 486  
 
 487  
         /**
 488  
          * Gets called by the digester.
 489  
          *
 490  
          * @param attributes the actual attributes
 491  
          * @return the new object
 492  
          * @throws Exception Couldn't instantiate the requested object.
 493  
          */
 494  
         public Object createObject(Attributes attributes) throws Exception
 495  
         {
 496  159
             FileConfiguration conf = createConfiguration(attributes);
 497  159
             conf.setBasePath(getBasePath());
 498  159
             conf.setFileName(attributes.getValue(ATTR_FILENAME));
 499  
             try
 500  
             {
 501  159
                 log.info("Trying to load configuration " + conf.getFileName());
 502  159
                 conf.load();
 503  132
             }
 504  
             catch (ConfigurationException cex)
 505  
             {
 506  27
                 if (attributes.getValue(ATTR_OPTIONAL) != null
 507  
                         && PropertyConverter.toBoolean(attributes.getValue(ATTR_OPTIONAL)).booleanValue())
 508  
                 {
 509  24
                     log.warn("Could not load optional configuration " + conf.getFileName());
 510  
                 }
 511  
                 else
 512  
                 {
 513  3
                     throw cex;
 514  
                 }
 515  
             }
 516  156
             return conf;
 517  
         }
 518  
 
 519  
         /**
 520  
          * Creates the object, a <code>FileConfiguration</code>.
 521  
          *
 522  
          * @param attributes the actual attributes
 523  
          * @return the file configuration
 524  
          * @throws Exception if the object could not be created
 525  
          */
 526  
         protected FileConfiguration createConfiguration(Attributes attributes) throws Exception
 527  
         {
 528  57
             return (FileConfiguration) super.createObject(attributes);
 529  
         }
 530  
     }
 531  
 
 532  
     /**
 533  
      * A factory that returns an XMLPropertiesConfiguration for .xml files
 534  
      * and a PropertiesConfiguration for the others.
 535  
      *
 536  
      * @since 1.2
 537  
      */
 538  
     public class PropertiesConfigurationFactory extends FileConfigurationFactory
 539  
     {
 540  
         /**
 541  
          * Creates a new instance of <code>PropertiesConfigurationFactory</code>.
 542  
          */
 543  
         public PropertiesConfigurationFactory()
 544  
         {
 545  
             super(null);
 546  
         }
 547  
 
 548  
         /**
 549  
          * Creates the new configuration object. Based on the file name
 550  
          * provided in the attributes either a <code>PropertiesConfiguration</code>
 551  
          * or a <code>XMLPropertiesConfiguration</code> object will be
 552  
          * returned.
 553  
          *
 554  
          * @param attributes the attributes
 555  
          * @return the new configuration object
 556  
          * @throws Exception if an error occurs
 557  
          */
 558  
         protected FileConfiguration createConfiguration(Attributes attributes) throws Exception
 559  
         {
 560  
             String filename = attributes.getValue(ATTR_FILENAME);
 561  
 
 562  
             if (filename != null && filename.toLowerCase().trim().endsWith(".xml"))
 563  
             {
 564  
                 return new XMLPropertiesConfiguration();
 565  
             }
 566  
             else
 567  
             {
 568  
                 return new PropertiesConfiguration();
 569  
             }
 570  
         }
 571  
     }
 572  
 
 573  
     /**
 574  
      * A factory that returns an XMLPropertyListConfiguration for .xml files
 575  
      * and a PropertyListConfiguration for the others.
 576  
      *
 577  
      * @since 1.2
 578  
      */
 579  
     public class PropertyListConfigurationFactory extends FileConfigurationFactory
 580  
     {
 581  
         /**
 582  
          * Creates a new instance of <code>PropertyListConfigurationFactory</code>.
 583  
          */
 584  
         public PropertyListConfigurationFactory()
 585  
         {
 586  
             super(null);
 587  
         }
 588  
 
 589  
         /**
 590  
          * Creates the new configuration object. Based on the file name
 591  
          * provided in the attributes either a <code>XMLPropertyListConfiguration</code>
 592  
          * or a <code>PropertyListConfiguration</code> object will be
 593  
          * returned.
 594  
          *
 595  
          * @param attributes the attributes
 596  
          * @return the new configuration object
 597  
          * @throws Exception if an error occurs
 598  
          */
 599  
         protected FileConfiguration createConfiguration(Attributes attributes) throws Exception
 600  
         {
 601  
             String filename = attributes.getValue(ATTR_FILENAME);
 602  
 
 603  
             if (filename != null && filename.toLowerCase().trim().endsWith(".xml"))
 604  
             {
 605  
                 return new XMLPropertyListConfiguration();
 606  
             }
 607  
             else
 608  
             {
 609  
                 return new PropertyListConfiguration();
 610  
             }
 611  
         }
 612  
     }
 613  
 
 614  
     /**
 615  
      * A tiny inner class that allows the Configuration Factory to
 616  
      * let the digester construct JNDIConfiguration objects.
 617  
      */
 618  
     private class JNDIConfigurationFactory extends DigesterConfigurationFactory
 619  
     {
 620  
         /**
 621  
          * Creates a new instance of <code>JNDIConfigurationFactory</code>.
 622  
          */
 623  
         public JNDIConfigurationFactory()
 624  
         {
 625  
             super(JNDIConfiguration.class);
 626  
         }
 627  
     }
 628  
 
 629  
     /**
 630  
      * A tiny inner class that allows the Configuration Factory to
 631  
      * let the digester construct SystemConfiguration objects.
 632  
      */
 633  
     private class SystemConfigurationFactory extends DigesterConfigurationFactory
 634  
     {
 635  
         /**
 636  
          * Creates a new instance of <code>SystemConfigurationFactory</code>.
 637  
          */
 638  
         public SystemConfigurationFactory()
 639  
         {
 640  
             super(SystemConfiguration.class);
 641  
         }
 642  
     }
 643  
 
 644  
     /**
 645  
      * A simple data class that holds all information about a configuration
 646  
      * from the <code>&lt;additional&gt;</code> section.
 647  
      */
 648  
     public static class AdditionalConfigurationData
 649  
     {
 650  
         /** Stores the configuration object.*/
 651  
         private Configuration configuration;
 652  
 
 653  
         /** Stores the location of this configuration in the global tree.*/
 654  
         private String at;
 655  
 
 656  
         /**
 657  
          * Returns the value of the <code>at</code> attribute.
 658  
          *
 659  
          * @return the at attribute
 660  
          */
 661  
         public String getAt()
 662  
         {
 663  
             return at;
 664  
         }
 665  
 
 666  
         /**
 667  
          * Sets the value of the <code>at</code> attribute.
 668  
          *
 669  
          * @param string the attribute value
 670  
          */
 671  
         public void setAt(String string)
 672  
         {
 673  
             at = string;
 674  
         }
 675  
 
 676  
         /**
 677  
          * Returns the configuration object.
 678  
          *
 679  
          * @return the configuration
 680  
          */
 681  
         public Configuration getConfiguration()
 682  
         {
 683  
             return configuration;
 684  
         }
 685  
 
 686  
         /**
 687  
          * Sets the configuration object. Note: Normally this method should be
 688  
          * named <code>setConfiguration()</code>, but the name
 689  
          * <code>addConfiguration()</code> is required by some of the digester
 690  
          * rules.
 691  
          *
 692  
          * @param config the configuration to set
 693  
          */
 694  
         public void addConfiguration(Configuration config)
 695  
         {
 696  
             configuration = config;
 697  
         }
 698  
     }
 699  
 
 700  
     /**
 701  
      * An internally used helper class for constructing the composite
 702  
      * configuration object.
 703  
      */
 704  
     public static class ConfigurationBuilder
 705  
     {
 706  
         /** Stores the composite configuration.*/
 707  
         private CompositeConfiguration config;
 708  
 
 709  
         /** Stores a collection with the configs from the additional section.*/
 710  
         private Collection additionalConfigs;
 711  
 
 712  
         /**
 713  
          * Creates a new instance of <code>ConfigurationBuilder</code>.
 714  
          */
 715  
         public ConfigurationBuilder()
 716  
         {
 717  
             config = new CompositeConfiguration();
 718  
             additionalConfigs = new LinkedList();
 719  
         }
 720  
 
 721  
         /**
 722  
          * Adds a new configuration to this object. This method is called by
 723  
          * Digester.
 724  
          *
 725  
          * @param conf the configuration to be added
 726  
          */
 727  
         public void addConfiguration(Configuration conf)
 728  
         {
 729  
             config.addConfiguration(conf);
 730  
         }
 731  
 
 732  
         /**
 733  
          * Adds information about an additional configuration. This method is
 734  
          * called by Digester.
 735  
          *
 736  
          * @param data the data about the additional configuration
 737  
          */
 738  
         public void addAdditionalConfig(AdditionalConfigurationData data)
 739  
         {
 740  
             additionalConfigs.add(data);
 741  
         }
 742  
 
 743  
         /**
 744  
          * Returns the final composite configuration.
 745  
          *
 746  
          * @return the final configuration object
 747  
          */
 748  
         public CompositeConfiguration getConfiguration()
 749  
         {
 750  
             if (!additionalConfigs.isEmpty())
 751  
             {
 752  
                 Configuration unionConfig = createAdditionalConfiguration(additionalConfigs);
 753  
                 if (unionConfig != null)
 754  
                 {
 755  
                     addConfiguration(unionConfig);
 756  
                 }
 757  
                 additionalConfigs.clear();
 758  
             }
 759  
 
 760  
             return config;
 761  
         }
 762  
 
 763  
         /**
 764  
          * Creates a configuration object with the union of all properties
 765  
          * defined in the <code>&lt;additional&gt;</code> section. This
 766  
          * implementation returns a <code>HierarchicalConfiguration</code>
 767  
          * object.
 768  
          *
 769  
          * @param configs a collection with
 770  
          * <code>AdditionalConfigurationData</code> objects
 771  
          * @return the union configuration (can be <b>null</b>)
 772  
          */
 773  
         protected Configuration createAdditionalConfiguration(Collection configs)
 774  
         {
 775  
             HierarchicalConfiguration result = new HierarchicalConfiguration();
 776  
 
 777  
             for (Iterator it = configs.iterator(); it.hasNext();)
 778  
             {
 779  
                 AdditionalConfigurationData cdata =
 780  
                 (AdditionalConfigurationData) it.next();
 781  
                 result.addNodes(cdata.getAt(),
 782  
                 createRootNode(cdata).getChildren());
 783  
             }
 784  
 
 785  
             return result.isEmpty() ? null : result;
 786  
         }
 787  
 
 788  
         /**
 789  
          * Creates a configuration root node for the specified configuration.
 790  
          *
 791  
          * @param cdata the configuration data object
 792  
          * @return a root node for this configuration
 793  
          */
 794  
         private HierarchicalConfiguration.Node createRootNode(AdditionalConfigurationData cdata)
 795  
         {
 796  
             if (cdata.getConfiguration() instanceof HierarchicalConfiguration)
 797  
             {
 798  
                 // we can directly use this configuration's root node
 799  
                 return ((HierarchicalConfiguration) cdata.getConfiguration()).getRoot();
 800  
             }
 801  
             else
 802  
             {
 803  
                 // transform configuration to a hierarchical root node
 804  
                 HierarchicalConfigurationNodeConverter conv =
 805  
                 new HierarchicalConfigurationNodeConverter();
 806  
                 conv.process(cdata.getConfiguration());
 807  
                 return conv.getRootNode();
 808  
             }
 809  
         }
 810  
     }
 811  
 
 812  
     /**
 813  
      * A specialized <code>HierarchicalConfigurationConverter</code> class
 814  
      * that creates a <code>HierarchicalConfiguration</code> root node from
 815  
      * an arbitrary <code>Configuration</code> object. This class is used to
 816  
      * add additional configuration objects to the hierarchical configuration
 817  
      * managed by the <code>ConfigurationBuilder</code>.
 818  
      */
 819  
     static class HierarchicalConfigurationNodeConverter extends HierarchicalConfigurationConverter
 820  
     {
 821  
         /** A stack for constructing the hierarchy.*/
 822  
         private Stack nodes;
 823  
 
 824  
         /** Stores the root node.*/
 825  
         private HierarchicalConfiguration.Node root;
 826  
 
 827  
         /**
 828  
          * Default constructor.
 829  
          */
 830  
         public HierarchicalConfigurationNodeConverter()
 831  
         {
 832  
             nodes = new Stack();
 833  
             root = new HierarchicalConfiguration.Node();
 834  
             nodes.push(root);
 835  
         }
 836  
 
 837  
         /**
 838  
          * Callback for an element start event. Creates a new node and adds
 839  
          * it to the actual parent.
 840  
          *
 841  
          * @param name the name of the new node
 842  
          * @param value the node's value
 843  
          */
 844  
         protected void elementStart(String name, Object value)
 845  
         {
 846  
             HierarchicalConfiguration.Node parent = (HierarchicalConfiguration.Node) nodes.peek();
 847  
             HierarchicalConfiguration.Node child = new HierarchicalConfiguration.Node(name);
 848  
             if (value != null)
 849  
             {
 850  
                 child.setValue(value);
 851  
             }
 852  
             parent.addChild(child);
 853  
             nodes.push(child);
 854  
         }
 855  
 
 856  
         /**
 857  
          * Callback for an element end event. Clears the stack.
 858  
          *
 859  
          * @param name the name of the element
 860  
          */
 861  
         protected void elementEnd(String name)
 862  
         {
 863  
             nodes.pop();
 864  
         }
 865  
 
 866  
         /**
 867  
          * Returns the constructed root node.
 868  
          *
 869  
          * @return the root node
 870  
          */
 871  
         public HierarchicalConfiguration.Node getRootNode()
 872  
         {
 873  
             return root;
 874  
         }
 875  
     }
 876  
 }

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