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