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