Coverage Report - org.apache.commons.configuration.DefaultConfigurationBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultConfigurationBuilder
98%
153/155
100%
46/46
1,956
DefaultConfigurationBuilder$1
80%
4/5
50%
2/4
1,956
DefaultConfigurationBuilder$ConfigurationBeanFactory
96%
25/26
87%
7/8
1,956
DefaultConfigurationBuilder$ConfigurationBuilderProvider
100%
24/24
100%
4/4
1,956
DefaultConfigurationBuilder$ConfigurationDeclaration
100%
17/17
100%
16/16
1,956
DefaultConfigurationBuilder$ConfigurationProvider
70%
14/20
75%
3/4
1,956
DefaultConfigurationBuilder$FileConfigurationProvider
91%
21/23
66%
4/6
1,956
DefaultConfigurationBuilder$FileExtensionConfigurationProvider
90%
18/20
62%
5/8
1,956
DefaultConfigurationBuilder$XMLConfigurationProvider
100%
9/9
100%
2/2
1,956
 
 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  
 package org.apache.commons.configuration;
 18  
 
 19  
 import java.io.File;
 20  
 import java.net.URL;
 21  
 import java.util.ArrayList;
 22  
 import java.util.Collections;
 23  
 import java.util.HashMap;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 
 28  
 import org.apache.commons.configuration.beanutils.BeanDeclaration;
 29  
 import org.apache.commons.configuration.beanutils.BeanFactory;
 30  
 import org.apache.commons.configuration.beanutils.BeanHelper;
 31  
 import org.apache.commons.configuration.beanutils.DefaultBeanFactory;
 32  
 import org.apache.commons.configuration.beanutils.XMLBeanDeclaration;
 33  
 import org.apache.commons.configuration.event.ConfigurationErrorListener;
 34  
 import org.apache.commons.configuration.event.ConfigurationListener;
 35  
 import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
 36  
 import org.apache.commons.configuration.resolver.CatalogResolver;
 37  
 import org.apache.commons.configuration.resolver.EntityRegistry;
 38  
 import org.apache.commons.configuration.resolver.EntityResolverSupport;
 39  
 import org.apache.commons.configuration.tree.ConfigurationNode;
 40  
 import org.apache.commons.configuration.tree.DefaultExpressionEngine;
 41  
 import org.apache.commons.configuration.tree.OverrideCombiner;
 42  
 import org.apache.commons.configuration.tree.UnionCombiner;
 43  
 import org.apache.commons.lang.text.StrLookup;
 44  
 import org.apache.commons.logging.Log;
 45  
 import org.apache.commons.logging.LogFactory;
 46  
 import org.xml.sax.EntityResolver;
 47  
 
 48  
 /**
 49  
  * <p>
 50  
  * A factory class that creates a composite configuration from an XML based
 51  
  * <em>configuration definition file</em>.
 52  
  * </p>
 53  
  * <p>
 54  
  * This class provides an easy and flexible means for loading multiple
 55  
  * configuration sources and combining the results into a single configuration
 56  
  * object. The sources to be loaded are defined in an XML document that can
 57  
  * contain certain tags representing the different supported configuration
 58  
  * classes. If such a tag is found, the corresponding {@code Configuration}
 59  
  * class is instantiated and initialized using the classes of the
 60  
  * {@code beanutils} package (namely
 61  
  * {@link org.apache.commons.configuration.beanutils.XMLBeanDeclaration XMLBeanDeclaration}
 62  
  * will be used to extract the configuration's initialization parameters, which
 63  
  * allows for complex initialization scenarios).
 64  
  * </p>
 65  
  * <p>
 66  
  * It is also possible to add custom tags to the configuration definition file.
 67  
  * For this purpose register your own {@code ConfigurationProvider}
 68  
  * implementation for your tag using the {@code addConfigurationProvider()}
 69  
  * method. This provider will then be called when the corresponding custom tag
 70  
  * is detected. For the default configuration classes providers are already
 71  
  * registered.
 72  
  * </p>
 73  
  * <p>
 74  
  * The configuration definition file has the following basic structure:
 75  
  * </p>
 76  
  * <p>
 77  
  *
 78  
  * <pre>
 79  
  * &lt;configuration systemProperties="properties file name"&gt;
 80  
  *   &lt;header&gt;
 81  
  *     &lt;!-- Optional meta information about the composite configuration --&gt;
 82  
  *   &lt;/header&gt;
 83  
  *   &lt;override&gt;
 84  
  *     &lt;!-- Declarations for override configurations --&gt;
 85  
  *   &lt;/override&gt;
 86  
  *   &lt;additional&gt;
 87  
  *     &lt;!-- Declarations for union configurations --&gt;
 88  
  *   &lt;/additional&gt;
 89  
  * &lt;/configuration&gt;
 90  
  * </pre>
 91  
  *
 92  
  * </p>
 93  
  * <p>
 94  
  * The name of the root element (here {@code configuration}) is
 95  
  * arbitrary. The optional systemProperties attribute identifies the path to
 96  
  * a property file containing properties that should be added to the system
 97  
  * properties. If specified on the root element, the system properties are
 98  
  * set before the rest of the configuration is processed.
 99  
  * </p>
 100  
  * <p>
 101  
  * There are two sections (both of them are optional) for declaring
 102  
  * <em>override</em> and <em>additional</em> configurations. Configurations
 103  
  * in the former section are evaluated in the order of their declaration, and
 104  
  * properties of configurations declared earlier hide those of configurations
 105  
  * declared later. Configurations in the latter section are combined to a union
 106  
  * configuration, i.e. all of their properties are added to a large hierarchical
 107  
  * configuration. Configuration declarations that occur as direct children of
 108  
  * the root element are treated as override declarations.
 109  
  * </p>
 110  
  * <p>
 111  
  * Each configuration declaration consists of a tag whose name is associated
 112  
  * with a {@code ConfigurationProvider}. This can be one of the
 113  
  * predefined tags like {@code properties}, or {@code xml}, or
 114  
  * a custom tag, for which a configuration provider was registered. Attributes
 115  
  * and sub elements with specific initialization parameters can be added. There
 116  
  * are some reserved attributes with a special meaning that can be used in every
 117  
  * configuration declaration:
 118  
  * </p>
 119  
  * <p>
 120  
  * <table border="1">
 121  
  * <tr>
 122  
  * <th>Attribute</th>
 123  
  * <th>Meaning</th>
 124  
  * </tr>
 125  
  * <tr>
 126  
  * <td valign="top">{@code config-name}</td>
 127  
  * <td>Allows to specify a name for this configuration. This name can be used
 128  
  * to obtain a reference to the configuration from the resulting combined
 129  
  * configuration (see below).</td>
 130  
  * </tr>
 131  
  * <tr>
 132  
  * <td valign="top">{@code config-at}</td>
 133  
  * <td>With this attribute an optional prefix can be specified for the
 134  
  * properties of the corresponding configuration.</td>
 135  
  * </tr>
 136  
  * <tr>
 137  
  * <td valign="top">{@code config-optional}</td>
 138  
  * <td>Declares a configuration as optional. This means that errors that occur
 139  
  * when creating the configuration are ignored. (However
 140  
  * {@link org.apache.commons.configuration.event.ConfigurationErrorListener}s
 141  
  * registered at the builder instance will get notified about this error: they
 142  
  * receive an event of type {@code EVENT_ERR_LOAD_OPTIONAL}. The key
 143  
  * property of this event contains the name of the optional configuration source
 144  
  * that caused this problem.)</td>
 145  
  * </tr>
 146  
  * </table>
 147  
  * </p>
 148  
  * <p>
 149  
  * The optional <em>header</em> section can contain some meta data about the
 150  
  * created configuration itself. For instance, it is possible to set further
 151  
  * properties of the {@code NodeCombiner} objects used for constructing
 152  
  * the resulting configuration.
 153  
  * </p>
 154  
  * <p>
 155  
  * The default configuration object returned by this builder is an instance of the
 156  
  * {@link CombinedConfiguration} class. The return value of the
 157  
  * {@code getConfiguration()} method can be casted to this type, and the
 158  
  * {@code getConfiguration(boolean)} method directly declares
 159  
  * {@code CombinedConfiguration} as return type. This allows for
 160  
  * convenient access to the configuration objects maintained by the combined
 161  
  * configuration (e.g. for updates of single configuration objects). It has also
 162  
  * the advantage that the properties stored in all declared configuration
 163  
  * objects are collected and transformed into a single hierarchical structure,
 164  
  * which can be accessed using different expression engines. The actual CombinedConfiguration
 165  
  * implementation can be overridden by specifying the class in the <em>config-class</em>
 166  
  * attribute of the result element.
 167  
  * </p>
 168  
  * <p>
 169  
  * A custom EntityResolver can be used for all XMLConfigurations by adding
 170  
  * <pre>
 171  
  * &lt;entity-resolver config-class="EntityResolver fully qualified class name"&gt;
 172  
  * </pre>
 173  
  * The CatalogResolver can be used for all XMLConfiguration by adding
 174  
  * <pre>
 175  
  * &lt;entity-resolver catalogFiles="comma separated list of catalog files"&gt;
 176  
  * </pre>
 177  
  * </p>
 178  
  * <p>
 179  
  * Additional ConfigurationProviders can be added by configuring them in the <em>header</em>
 180  
  * section.
 181  
  * <pre>
 182  
  * &lt;providers&gt;
 183  
  *   &lt;provider config-tag="tag name" config-class="provider fully qualified class name"/&gt;
 184  
  * &lt;/providers&gt;
 185  
  * </pre>
 186  
  * </p>
 187  
  * <p>
 188  
  * Additional variable resolvers can be added by configuring them in the <em>header</em>
 189  
  * section.
 190  
  * <pre>
 191  
  * &lt;lookups&gt;
 192  
  *   &lt;lookup config-prefix="prefix" config-class="StrLookup fully qualified class name"/&gt;
 193  
  * &lt;/lookups&gt;
 194  
  * </pre>
 195  
  * </p>
 196  
  * <p>
 197  
  * All declared override configurations are directly added to the resulting
 198  
  * combined configuration. If they are given names (using the
 199  
  * {@code config-name} attribute), they can directly be accessed using
 200  
  * the {@code getConfiguration(String)} method of
 201  
  * {@code CombinedConfiguration}. The additional configurations are
 202  
  * altogether added to another combined configuration, which uses a union
 203  
  * combiner. Then this union configuration is added to the resulting combined
 204  
  * configuration under the name defined by the {@code ADDITIONAL_NAME}
 205  
  * constant.
 206  
  * </p>
 207  
  * <p>
 208  
  * Implementation note: This class is not thread-safe. Especially the
 209  
  * {@code getConfiguration()} methods should be called by a single thread
 210  
  * only.
 211  
  * </p>
 212  
  *
 213  
  * @since 1.3
 214  
  * @author <a
 215  
  * href="http://commons.apache.org/configuration/team-list.html">Commons
 216  
  * Configuration team</a>
 217  
  * @version $Id: org.apache.commons.configuration.DefaultConfigurationBuilder.html 910708 2014-05-31 19:13:45Z oheger $
 218  
  */
 219  270
 public class DefaultConfigurationBuilder extends XMLConfiguration implements
 220  
         ConfigurationBuilder
 221  
 {
 222  
     /**
 223  
      * Constant for the name of the additional configuration. If the
 224  
      * configuration definition file contains an {@code additional}
 225  
      * section, a special union configuration is created and added under this
 226  
      * name to the resulting combined configuration.
 227  
      */
 228  1
     public static final String ADDITIONAL_NAME = DefaultConfigurationBuilder.class
 229  
             .getName()
 230  
             + "/ADDITIONAL_CONFIG";
 231  
 
 232  
     /**
 233  
      * Constant for the type of error events caused by optional configurations
 234  
      * that cannot be loaded.
 235  
      */
 236  
     public static final int EVENT_ERR_LOAD_OPTIONAL = 51;
 237  
 
 238  
     /** Constant for the name of the configuration bean factory. */
 239  1
     static final String CONFIG_BEAN_FACTORY_NAME = DefaultConfigurationBuilder.class
 240  
             .getName()
 241  
             + ".CONFIG_BEAN_FACTORY_NAME";
 242  
 
 243  
     /** Constant for the reserved name attribute. */
 244  
     static final String ATTR_NAME = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
 245  
             + XMLBeanDeclaration.RESERVED_PREFIX
 246  
             + "name"
 247  
             + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 248  
 
 249  
     /** Constant for the name of the at attribute. */
 250  
     static final String ATTR_ATNAME = "at";
 251  
 
 252  
     /** Constant for the reserved at attribute. */
 253  
     static final String ATTR_AT_RES = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
 254  
             + XMLBeanDeclaration.RESERVED_PREFIX
 255  
             + ATTR_ATNAME
 256  
             + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 257  
 
 258  
     /** Constant for the at attribute without the reserved prefix. */
 259  
     static final String ATTR_AT = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
 260  
             + ATTR_ATNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 261  
 
 262  
     /** Constant for the name of the optional attribute. */
 263  
     static final String ATTR_OPTIONALNAME = "optional";
 264  
 
 265  
     /** Constant for the reserved optional attribute. */
 266  
     static final String ATTR_OPTIONAL_RES = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
 267  
             + XMLBeanDeclaration.RESERVED_PREFIX
 268  
             + ATTR_OPTIONALNAME
 269  
             + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 270  
 
 271  
     /** Constant for the optional attribute without the reserved prefix. */
 272  
     static final String ATTR_OPTIONAL = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
 273  
             + ATTR_OPTIONALNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 274  
 
 275  
     /** Constant for the file name attribute. */
 276  
     static final String ATTR_FILENAME = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
 277  
             + "fileName" + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 278  
 
 279  
     /** Constant for the forceCreate attribute. */
 280  
     static final String ATTR_FORCECREATE = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
 281  
             + XMLBeanDeclaration.RESERVED_PREFIX
 282  
             + "forceCreate"
 283  
             + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 284  
 
 285  
     /**
 286  
      * Constant for the tag attribute for providers.
 287  
      */
 288  
     static final String KEY_SYSTEM_PROPS = "[@systemProperties]";
 289  
 
 290  
     /** Constant for the name of the header section. */
 291  
     static final String SEC_HEADER = "header";
 292  
 
 293  
     /** Constant for an expression that selects the union configurations. */
 294  
     static final String KEY_UNION = "additional";
 295  
 
 296  
     /** An array with the names of top level configuration sections.*/
 297  1
     static final String[] CONFIG_SECTIONS = {
 298  
         "additional", "override", SEC_HEADER
 299  
     };
 300  
 
 301  
     /**
 302  
      * Constant for an expression that selects override configurations in the
 303  
      * override section.
 304  
      */
 305  
     static final String KEY_OVERRIDE = "override";
 306  
 
 307  
     /**
 308  
      * Constant for the key that points to the list nodes definition of the
 309  
      * override combiner.
 310  
      */
 311  
     static final String KEY_OVERRIDE_LIST = SEC_HEADER
 312  
             + ".combiner.override.list-nodes.node";
 313  
 
 314  
     /**
 315  
      * Constant for the key that points to the list nodes definition of the
 316  
      * additional combiner.
 317  
      */
 318  
     static final String KEY_ADDITIONAL_LIST = SEC_HEADER
 319  
             + ".combiner.additional.list-nodes.node";
 320  
 
 321  
     /**
 322  
      * Constant for the key for defining providers in the configuration file.
 323  
      */
 324  
     static final String KEY_CONFIGURATION_PROVIDERS = SEC_HEADER
 325  
             + ".providers.provider";
 326  
 
 327  
     /**
 328  
      * Constant for the tag attribute for providers.
 329  
      */
 330  
     static final String KEY_PROVIDER_KEY = XMLBeanDeclaration.ATTR_PREFIX + "tag]";
 331  
 
 332  
     /**
 333  
      * Constant for the key for defining variable resolvers
 334  
      */
 335  
     static final String KEY_CONFIGURATION_LOOKUPS = SEC_HEADER
 336  
             + ".lookups.lookup";
 337  
 
 338  
     /**
 339  
      * Constant for the key for defining entity resolvers
 340  
      */
 341  
     static final String KEY_ENTITY_RESOLVER = SEC_HEADER + ".entity-resolver";
 342  
 
 343  
     /**
 344  
      * Constant for the prefix attribute for lookups.
 345  
      */
 346  
     static final String KEY_LOOKUP_KEY = XMLBeanDeclaration.ATTR_PREFIX + "prefix]";
 347  
 
 348  
     /**
 349  
      * Constance for the FileSystem.
 350  
      */
 351  
     static final String FILE_SYSTEM = SEC_HEADER + ".fileSystem";
 352  
 
 353  
     /**
 354  
      * Constant for the key of the result declaration. This key can point to a
 355  
      * bean declaration, which defines properties of the resulting combined
 356  
      * configuration.
 357  
      */
 358  
     static final String KEY_RESULT = SEC_HEADER + ".result";
 359  
 
 360  
     /** Constant for the key of the combiner in the result declaration.*/
 361  
     static final String KEY_COMBINER = KEY_RESULT + ".nodeCombiner";
 362  
 
 363  
     /** Constant for the XML file extension. */
 364  
     static final String EXT_XML = ".xml";
 365  
 
 366  
     /** Constant for the provider for properties files. */
 367  1
     private static final ConfigurationProvider PROPERTIES_PROVIDER = new FileExtensionConfigurationProvider(
 368  
             XMLPropertiesConfiguration.class, PropertiesConfiguration.class,
 369  
             EXT_XML);
 370  
 
 371  
     /** Constant for the provider for XML files. */
 372  1
     private static final ConfigurationProvider XML_PROVIDER = new XMLConfigurationProvider();
 373  
 
 374  
     /** Constant for the provider for JNDI sources. */
 375  1
     private static final ConfigurationProvider JNDI_PROVIDER = new ConfigurationProvider(
 376  
             JNDIConfiguration.class);
 377  
 
 378  
     /** Constant for the provider for system properties. */
 379  1
     private static final ConfigurationProvider SYSTEM_PROVIDER = new ConfigurationProvider(
 380  
             SystemConfiguration.class);
 381  
 
 382  
     /** Constant for the provider for ini files. */
 383  1
     private static final ConfigurationProvider INI_PROVIDER =
 384  
             new FileConfigurationProvider(HierarchicalINIConfiguration.class);
 385  
 
 386  
     /** Constant for the provider for environment properties. */
 387  1
     private static final ConfigurationProvider ENV_PROVIDER =
 388  
             new ConfigurationProvider(EnvironmentConfiguration.class);
 389  
 
 390  
     /** Constant for the provider for plist files. */
 391  1
     private static final ConfigurationProvider PLIST_PROVIDER = new FileExtensionConfigurationProvider(
 392  
             "org.apache.commons.configuration.plist.XMLPropertyListConfiguration",
 393  
             "org.apache.commons.configuration.plist.PropertyListConfiguration",
 394  
             EXT_XML);
 395  
 
 396  
     /** Constant for the provider for configuration definition files.*/
 397  1
     private static final ConfigurationProvider BUILDER_PROVIDER = new ConfigurationBuilderProvider();
 398  
 
 399  
     /** An array with the names of the default tags. */
 400  1
     private static final String[] DEFAULT_TAGS = {
 401  
             "properties", "xml", "hierarchicalXml", "jndi", "system", "plist",
 402  
             "configuration", "ini", "env"
 403  
     };
 404  
 
 405  
     /** An array with the providers for the default tags. */
 406  1
     private static final ConfigurationProvider[] DEFAULT_PROVIDERS = {
 407  
             PROPERTIES_PROVIDER, XML_PROVIDER, XML_PROVIDER, JNDI_PROVIDER,
 408  
             SYSTEM_PROVIDER, PLIST_PROVIDER, BUILDER_PROVIDER, INI_PROVIDER,
 409  
             ENV_PROVIDER
 410  
     };
 411  
 
 412  
     /**
 413  
      * The serial version UID.
 414  
      */
 415  
     private static final long serialVersionUID = -3113777854714492123L;
 416  
 
 417  
     /**
 418  
      * A specialized {@code StrLookup} object which operates on the combined
 419  
      * configuration constructed by this builder. This object is used as
 420  
      * default lookup for {@code ConfigurationInterpolator} objects assigned to
 421  
      * newly created configuration objects.
 422  
      */
 423  135
     private final StrLookup combinedConfigLookup = new StrLookup()
 424  135
     {
 425  
         @Override
 426  
         public String lookup(String key)
 427  
         {
 428  2
             if (constructedConfiguration != null)
 429  
             {
 430  2
                 Object value =
 431  
                         constructedConfiguration.resolveContainerStore(key);
 432  2
                 return (value != null) ? value.toString() : null;
 433  
             }
 434  0
             return null;
 435  
         }
 436  
     };
 437  
 
 438  
     /** Stores the configuration that is currently constructed.*/
 439  
     private CombinedConfiguration constructedConfiguration;
 440  
 
 441  
     /** Stores a map with the registered configuration providers. */
 442  
     private final Map<String, ConfigurationProvider> providers;
 443  
 
 444  
     /** Stores the base path to the configuration sources to load. */
 445  
     private String configurationBasePath;
 446  
 
 447  
     /**
 448  
      * Creates a new instance of {@code DefaultConfigurationBuilder}. A
 449  
      * configuration definition file is not yet loaded. Use the diverse setter
 450  
      * methods provided by file based configurations to specify the
 451  
      * configuration definition file.
 452  
      */
 453  
     public DefaultConfigurationBuilder()
 454  
     {
 455  135
         super();
 456  135
         providers = new HashMap<String, ConfigurationProvider>();
 457  135
         registerDefaultProviders();
 458  135
         registerBeanFactory();
 459  135
         setLogger(LogFactory.getLog(getClass()));
 460  135
         addErrorLogListener();  // log errors per default
 461  135
     }
 462  
 
 463  
     /**
 464  
      * Creates a new instance of {@code DefaultConfigurationBuilder} and
 465  
      * sets the specified configuration definition file.
 466  
      *
 467  
      * @param file the configuration definition file
 468  
      */
 469  
     public DefaultConfigurationBuilder(File file)
 470  
     {
 471  2
         this();
 472  2
         setFile(file);
 473  2
     }
 474  
 
 475  
     /**
 476  
      * Creates a new instance of {@code DefaultConfigurationBuilder} and
 477  
      * sets the specified configuration definition file.
 478  
      *
 479  
      * @param fileName the name of the configuration definition file
 480  
      * @throws ConfigurationException if an error occurs when the file is loaded
 481  
      */
 482  
     public DefaultConfigurationBuilder(String fileName)
 483  
             throws ConfigurationException
 484  
     {
 485  3
         this();
 486  3
         setFileName(fileName);
 487  3
     }
 488  
 
 489  
     /**
 490  
      * Creates a new instance of {@code DefaultConfigurationBuilder} and
 491  
      * sets the specified configuration definition file.
 492  
      *
 493  
      * @param url the URL to the configuration definition file
 494  
      * @throws ConfigurationException if an error occurs when the file is loaded
 495  
      */
 496  
     public DefaultConfigurationBuilder(URL url) throws ConfigurationException
 497  
     {
 498  2
         this();
 499  2
         setURL(url);
 500  2
     }
 501  
 
 502  
     /**
 503  
      * Returns the base path for the configuration sources to load. This path is
 504  
      * used to resolve relative paths in the configuration definition file.
 505  
      *
 506  
      * @return the base path for configuration sources
 507  
      */
 508  
     public String getConfigurationBasePath()
 509  
     {
 510  229
         return (configurationBasePath != null) ? configurationBasePath
 511  
                 : getBasePath();
 512  
     }
 513  
 
 514  
     /**
 515  
      * Sets the base path for the configuration sources to load. Normally a base
 516  
      * path need not to be set because it is determined by the location of the
 517  
      * configuration definition file to load. All relative paths in this file
 518  
      * are resolved relative to this file. Setting a base path makes sense if
 519  
      * such relative paths should be otherwise resolved, e.g. if the
 520  
      * configuration file is loaded from the class path and all sub
 521  
      * configurations it refers to are stored in a special config directory.
 522  
      *
 523  
      * @param configurationBasePath the new base path to set
 524  
      */
 525  
     public void setConfigurationBasePath(String configurationBasePath)
 526  
     {
 527  2
         this.configurationBasePath = configurationBasePath;
 528  2
     }
 529  
 
 530  
     /**
 531  
      * Adds a configuration provider for the specified tag. Whenever this tag is
 532  
      * encountered in the configuration definition file this provider will be
 533  
      * called to create the configuration object.
 534  
      *
 535  
      * @param tagName the name of the tag in the configuration definition file
 536  
      * @param provider the provider for this tag
 537  
      */
 538  
     public void addConfigurationProvider(String tagName,
 539  
             ConfigurationProvider provider)
 540  
     {
 541  1261
         if (tagName == null)
 542  
         {
 543  2
             throw new IllegalArgumentException("Tag name must not be null!");
 544  
         }
 545  1259
         if (provider == null)
 546  
         {
 547  2
             throw new IllegalArgumentException("Provider must not be null!");
 548  
         }
 549  
 
 550  1257
         providers.put(tagName, provider);
 551  1257
     }
 552  
 
 553  
     /**
 554  
      * Removes the configuration provider for the specified tag name.
 555  
      *
 556  
      * @param tagName the tag name
 557  
      * @return the removed configuration provider or <b>null</b> if none was
 558  
      * registered for that tag
 559  
      */
 560  
     public ConfigurationProvider removeConfigurationProvider(String tagName)
 561  
     {
 562  6
         return providers.remove(tagName);
 563  
     }
 564  
 
 565  
     /**
 566  
      * Returns the configuration provider for the given tag.
 567  
      *
 568  
      * @param tagName the name of the tag
 569  
      * @return the provider that was registered for this tag or <b>null</b> if
 570  
      * there is none
 571  
      */
 572  
     public ConfigurationProvider providerForTag(String tagName)
 573  
     {
 574  280
         return providers.get(tagName);
 575  
     }
 576  
 
 577  
     /**
 578  
      * Returns the configuration provided by this builder. Loads and parses the
 579  
      * configuration definition file and creates instances for the declared
 580  
      * configurations.
 581  
      *
 582  
      * @return the configuration
 583  
      * @throws ConfigurationException if an error occurs
 584  
      */
 585  
     public Configuration getConfiguration() throws ConfigurationException
 586  
     {
 587  23
         return getConfiguration(true);
 588  
     }
 589  
 
 590  
     /**
 591  
      * Returns the configuration provided by this builder. If the boolean
 592  
      * parameter is <b>true</b>, the configuration definition file will be
 593  
      * loaded. It will then be parsed, and instances for the declared
 594  
      * configurations will be created.
 595  
      *
 596  
      * @param load a flag whether the configuration definition file should be
 597  
      * loaded; a value of <b>false</b> would make sense if the file has already
 598  
      * been created or its content was manipulated using some of the property
 599  
      * accessor methods
 600  
      * @return the configuration
 601  
      * @throws ConfigurationException if an error occurs
 602  
      */
 603  
     public CombinedConfiguration getConfiguration(boolean load)
 604  
             throws ConfigurationException
 605  
     {
 606  98
         if (load)
 607  
         {
 608  83
             load();
 609  
         }
 610  
 
 611  90
         initFileSystem();
 612  90
         initSystemProperties();
 613  90
         configureEntityResolver();
 614  90
         registerConfiguredProviders();
 615  90
         registerConfiguredLookups();
 616  
 
 617  90
         CombinedConfiguration result = createResultConfiguration();
 618  90
         constructedConfiguration = result;
 619  
 
 620  90
         List<SubnodeConfiguration> overrides = fetchTopLevelOverrideConfigs();
 621  90
         overrides.addAll(fetchChildConfigs(KEY_OVERRIDE));
 622  90
         initCombinedConfiguration(result, overrides, KEY_OVERRIDE_LIST);
 623  
 
 624  88
         List<SubnodeConfiguration> additionals = fetchChildConfigs(KEY_UNION);
 625  88
         if (!additionals.isEmpty())
 626  
         {
 627  24
             CombinedConfiguration addConfig = createAdditionalsConfiguration(result);
 628  24
             result.addConfiguration(addConfig, ADDITIONAL_NAME);
 629  24
             initCombinedConfiguration(addConfig, additionals,
 630  
                     KEY_ADDITIONAL_LIST);
 631  
         }
 632  
 
 633  88
         return result;
 634  
     }
 635  
 
 636  
     /**
 637  
      * Creates the resulting combined configuration. This method is called by
 638  
      * {@code getConfiguration()}. It checks whether the
 639  
      * {@code header} section of the configuration definition file
 640  
      * contains a {@code result} element. If this is the case, it will be
 641  
      * used to initialize the properties of the newly created configuration
 642  
      * object.
 643  
      *
 644  
      * @return the resulting configuration object
 645  
      * @throws ConfigurationException if an error occurs
 646  
      */
 647  
     protected CombinedConfiguration createResultConfiguration()
 648  
             throws ConfigurationException
 649  
     {
 650  90
         XMLBeanDeclaration decl = new XMLBeanDeclaration(this, KEY_RESULT, true);
 651  90
         CombinedConfiguration result = (CombinedConfiguration) BeanHelper
 652  
                 .createBean(decl, CombinedConfiguration.class);
 653  
 
 654  90
         if (getMaxIndex(KEY_COMBINER) < 0)
 655  
         {
 656  
             // No combiner defined => set default
 657  40
             result.setNodeCombiner(new OverrideCombiner());
 658  
         }
 659  
 
 660  90
         return result;
 661  
     }
 662  
 
 663  
     /**
 664  
      * Creates the {@code CombinedConfiguration} for the configuration
 665  
      * sources in the <code>&lt;additional&gt;</code> section. This method is
 666  
      * called when the builder constructs the final configuration. It creates a
 667  
      * new {@code CombinedConfiguration} and initializes some properties
 668  
      * from the result configuration.
 669  
      *
 670  
      * @param resultConfig the result configuration (this is the configuration
 671  
      *        that will be returned by the builder)
 672  
      * @return the {@code CombinedConfiguration} for the additional
 673  
      *         configuration sources
 674  
      * @since 1.7
 675  
      */
 676  
     protected CombinedConfiguration createAdditionalsConfiguration(
 677  
             CombinedConfiguration resultConfig)
 678  
     {
 679  24
         CombinedConfiguration addConfig =
 680  
                 new CombinedConfiguration(new UnionCombiner());
 681  24
         addConfig.setDelimiterParsingDisabled(resultConfig
 682  
                 .isDelimiterParsingDisabled());
 683  24
         addConfig.setForceReloadCheck(resultConfig.isForceReloadCheck());
 684  24
         addConfig.setIgnoreReloadExceptions(resultConfig
 685  
                 .isIgnoreReloadExceptions());
 686  24
         return addConfig;
 687  
     }
 688  
 
 689  
     /**
 690  
      * Initializes a combined configuration for the configurations of a specific
 691  
      * section. This method is called for the override and for the additional
 692  
      * section (if it exists).
 693  
      *
 694  
      * @param config the configuration to be initialized
 695  
      * @param containedConfigs the list with the declarations of the contained
 696  
      * configurations
 697  
      * @param keyListNodes a list with the declaration of list nodes
 698  
      * @throws ConfigurationException if an error occurs
 699  
      */
 700  
     protected void initCombinedConfiguration(CombinedConfiguration config,
 701  
             List<? extends HierarchicalConfiguration> containedConfigs,
 702  
             String keyListNodes) throws ConfigurationException
 703  
     {
 704  114
         List<Object> listNodes = getList(keyListNodes);
 705  114
         for (Object listNode : listNodes)
 706  
         {
 707  34
             config.getNodeCombiner().addListNode((String) listNode);
 708  34
         }
 709  
 
 710  114
         for (HierarchicalConfiguration conf : containedConfigs)
 711  
         {
 712  266
             ConfigurationDeclaration decl = new ConfigurationDeclaration(this,
 713  
                     conf);
 714  266
             if (getLogger().isDebugEnabled())
 715  
             {
 716  9
                 getLogger().debug("Creating configuration " + decl.getBeanClassName() + " with name "
 717  
                     + decl.getConfiguration().getString(ATTR_NAME));
 718  
             }
 719  266
             AbstractConfiguration newConf = createConfigurationAt(decl);
 720  264
             if (newConf != null)
 721  
             {
 722  236
                 config.addConfiguration(newConf, decl.getConfiguration()
 723  
                         .getString(ATTR_NAME), decl.getAt());
 724  
             }
 725  264
         }
 726  112
     }
 727  
 
 728  
     /**
 729  
      * Registers the default configuration providers supported by this class.
 730  
      * This method will be called during initialization. It registers
 731  
      * configuration providers for the tags that are supported by default.
 732  
      */
 733  
     protected void registerDefaultProviders()
 734  
     {
 735  1350
         for (int i = 0; i < DEFAULT_TAGS.length; i++)
 736  
         {
 737  1215
             addConfigurationProvider(DEFAULT_TAGS[i], DEFAULT_PROVIDERS[i]);
 738  
         }
 739  135
     }
 740  
 
 741  
     /**
 742  
      * Registers providers defined in the configuration.
 743  
      *
 744  
      * @throws ConfigurationException if an error occurs
 745  
      */
 746  
     protected void registerConfiguredProviders() throws ConfigurationException
 747  
     {
 748  90
         List<HierarchicalConfiguration> nodes = configurationsAt(KEY_CONFIGURATION_PROVIDERS);
 749  90
         for (HierarchicalConfiguration config : nodes)
 750  
         {
 751  34
             XMLBeanDeclaration decl = new XMLBeanDeclaration(config);
 752  34
             String key = config.getString(KEY_PROVIDER_KEY);
 753  34
             addConfigurationProvider(key, (ConfigurationProvider) BeanHelper
 754  
                     .createBean(decl));
 755  34
         }
 756  90
     }
 757  
 
 758  
     /**
 759  
      * Registers StrLookups defined in the configuration.
 760  
      *
 761  
      * @throws ConfigurationException if an error occurs
 762  
      */
 763  
     protected void registerConfiguredLookups() throws ConfigurationException
 764  
     {
 765  90
         List<HierarchicalConfiguration> nodes = configurationsAt(KEY_CONFIGURATION_LOOKUPS);
 766  90
         for (HierarchicalConfiguration config : nodes)
 767  
         {
 768  7
             XMLBeanDeclaration decl = new XMLBeanDeclaration(config);
 769  7
             String key = config.getString(KEY_LOOKUP_KEY);
 770  7
             StrLookup lookup = (StrLookup) BeanHelper.createBean(decl);
 771  7
             BeanHelper.setProperty(lookup, "configuration", this);
 772  7
             ConfigurationInterpolator.registerGlobalLookup(key, lookup);
 773  7
             this.getInterpolator().registerLookup(key, lookup);
 774  7
         }
 775  90
     }
 776  
 
 777  
     protected void initFileSystem() throws ConfigurationException
 778  
     {
 779  90
         if (getMaxIndex(FILE_SYSTEM) == 0)
 780  
         {
 781  6
             HierarchicalConfiguration config = configurationAt(FILE_SYSTEM);
 782  6
             XMLBeanDeclaration decl = new XMLBeanDeclaration(config);
 783  6
             setFileSystem((FileSystem) BeanHelper.createBean(decl));
 784  
         }
 785  90
     }
 786  
 
 787  
     /**
 788  
      * If a property file is configured add the properties to the System properties.
 789  
      * @throws ConfigurationException if an error occurs.
 790  
      */
 791  
     protected void initSystemProperties() throws ConfigurationException
 792  
     {
 793  90
         String fileName = getString(KEY_SYSTEM_PROPS);
 794  90
         if (fileName != null)
 795  
         {
 796  
             try
 797  
             {
 798  2
                SystemConfiguration.setSystemProperties(getConfigurationBasePath(), fileName);
 799  
             }
 800  0
             catch (Exception ex)
 801  
             {
 802  0
                 throw new ConfigurationException("Error setting system properties from " + fileName, ex);
 803  2
             }
 804  
 
 805  
         }
 806  90
     }
 807  
 
 808  
     protected void configureEntityResolver() throws ConfigurationException
 809  
     {
 810  90
         if (getMaxIndex(KEY_ENTITY_RESOLVER) == 0)
 811  
         {
 812  18
             XMLBeanDeclaration decl = new XMLBeanDeclaration(this, KEY_ENTITY_RESOLVER, true);
 813  18
             EntityResolver resolver = (EntityResolver) BeanHelper.createBean(decl, CatalogResolver.class);
 814  18
             BeanHelper.setProperty(resolver, "fileSystem", getFileSystem());
 815  18
             BeanHelper.setProperty(resolver, "baseDir", getBasePath());
 816  18
             BeanHelper.setProperty(resolver, "substitutor", getSubstitutor());
 817  18
             setEntityResolver(resolver);
 818  
         }
 819  90
     }
 820  
 
 821  
     /**
 822  
      * Performs interpolation. This method will not only take this configuration
 823  
      * instance into account (which is the one that loaded the configuration
 824  
      * definition file), but also the so far constructed combined configuration.
 825  
      * So variables can be used that point to properties that are defined in
 826  
      * configuration sources loaded by this builder.
 827  
      *
 828  
      * @param value the value to be interpolated
 829  
      * @return the interpolated value
 830  
      */
 831  
     @Override
 832  
     protected Object interpolate(Object value)
 833  
     {
 834  497
         Object result = super.interpolate(value);
 835  497
         if (constructedConfiguration != null)
 836  
         {
 837  401
             result = constructedConfiguration.interpolate(result);
 838  
         }
 839  497
         return result;
 840  
     }
 841  
 
 842  
     /**
 843  
      * Creates a configuration object from the specified configuration
 844  
      * declaration.
 845  
      *
 846  
      * @param decl the configuration declaration
 847  
      * @return the new configuration object
 848  
      * @throws ConfigurationException if an error occurs
 849  
      */
 850  
     private AbstractConfiguration createConfigurationAt(
 851  
             ConfigurationDeclaration decl) throws ConfigurationException
 852  
     {
 853  
         try
 854  
         {
 855  266
             return (AbstractConfiguration) BeanHelper.createBean(decl);
 856  
         }
 857  2
         catch (Exception ex)
 858  
         {
 859  
             // redirect to configuration exceptions
 860  2
             throw new ConfigurationException(ex);
 861  
         }
 862  
     }
 863  
 
 864  
     /**
 865  
      * Returns a list with {@code SubnodeConfiguration} objects for the
 866  
      * child nodes of the specified configuration node.
 867  
      *
 868  
      * @param node the start node
 869  
      * @return a list with subnode configurations for the node's children
 870  
      */
 871  
     private List<SubnodeConfiguration> fetchChildConfigs(ConfigurationNode node)
 872  
     {
 873  156
         List<ConfigurationNode> children = node.getChildren();
 874  156
         List<SubnodeConfiguration> result = new ArrayList<SubnodeConfiguration>(children.size());
 875  156
         for (ConfigurationNode child : children)
 876  
         {
 877  382
             result.add(createSubnodeConfiguration(child));
 878  382
         }
 879  156
         return result;
 880  
     }
 881  
 
 882  
     /**
 883  
      * Returns a list with {@code SubnodeConfiguration} objects for the
 884  
      * child nodes of the node specified by the given key.
 885  
      *
 886  
      * @param key the key (must define exactly one node)
 887  
      * @return a list with subnode configurations for the node's children
 888  
      */
 889  
     private List<SubnodeConfiguration> fetchChildConfigs(String key)
 890  
     {
 891  178
         List<ConfigurationNode> nodes = fetchNodeList(key);
 892  178
         if (nodes.size() > 0)
 893  
         {
 894  66
             return fetchChildConfigs(nodes.get(0));
 895  
         }
 896  
         else
 897  
         {
 898  112
             return Collections.emptyList();
 899  
         }
 900  
     }
 901  
 
 902  
     /**
 903  
      * Finds the override configurations that are defined as top level elements
 904  
      * in the configuration definition file. This method will fetch the child
 905  
      * elements of the root node and remove the nodes that represent other
 906  
      * configuration sections. The remaining nodes are treated as definitions
 907  
      * for override configurations.
 908  
      *
 909  
      * @return a list with subnode configurations for the top level override
 910  
      * configurations
 911  
      */
 912  
     private List<SubnodeConfiguration> fetchTopLevelOverrideConfigs()
 913  
     {
 914  90
         List<SubnodeConfiguration> configs = fetchChildConfigs(getRootNode());
 915  90
         for (Iterator<SubnodeConfiguration> it = configs.iterator(); it.hasNext();)
 916  
         {
 917  250
             String nodeName = it.next().getRootNode().getName();
 918  794
             for (int i = 0; i < CONFIG_SECTIONS.length; i++)
 919  
             {
 920  660
                 if (CONFIG_SECTIONS[i].equals(nodeName))
 921  
                 {
 922  116
                     it.remove();
 923  116
                     break;
 924  
                 }
 925  
             }
 926  250
         }
 927  90
         return configs;
 928  
     }
 929  
 
 930  
     /**
 931  
      * Registers the bean factory used by this class if necessary. This method
 932  
      * is called by the constructor to ensure that the required bean factory is
 933  
      * available.
 934  
      */
 935  
     private void registerBeanFactory()
 936  
     {
 937  135
         synchronized (DefaultConfigurationBuilder.class)
 938  
         {
 939  135
             if (!BeanHelper.registeredFactoryNames().contains(
 940  
                     CONFIG_BEAN_FACTORY_NAME))
 941  
             {
 942  1
                 BeanHelper.registerBeanFactory(CONFIG_BEAN_FACTORY_NAME,
 943  
                         new ConfigurationBeanFactory());
 944  
             }
 945  135
         }
 946  135
     }
 947  
 
 948  
     /**
 949  
      * <p>
 950  
      * A base class for creating and initializing configuration sources.
 951  
      * </p>
 952  
      * <p>
 953  
      * Concrete sub classes of this base class are responsible for creating
 954  
      * specific {@code Configuration} objects for the tags in the
 955  
      * configuration definition file. The configuration factory will parse the
 956  
      * definition file and try to find a matching
 957  
      * {@code ConfigurationProvider} for each encountered tag. This
 958  
      * provider is then asked to create a corresponding
 959  
      * {@code Configuration} object. It is up to a concrete
 960  
      * implementation how this object is created and initialized.
 961  
      * </p>
 962  
      * <p>
 963  
      * Note that at the moment only configuration classes derived from
 964  
      * {@link AbstractConfiguration} are supported.
 965  
      * </p>
 966  
      */
 967  
     public static class ConfigurationProvider extends DefaultBeanFactory
 968  
     {
 969  
         /** Stores the class of the configuration to be created. */
 970  
         private Class<?> configurationClass;
 971  
 
 972  
         /** Stores the name of the configuration class to be created.*/
 973  
         private String configurationClassName;
 974  
 
 975  
         /**
 976  
          * Creates a new uninitialized instance of {@code ConfigurationProvider}.
 977  
          */
 978  
         public ConfigurationProvider()
 979  
         {
 980  40
             this((Class<?>) null);
 981  40
         }
 982  
 
 983  
         /**
 984  
          * Creates a new instance of {@code ConfigurationProvider} and
 985  
          * sets the class of the configuration created by this provider.
 986  
          *
 987  
          * @param configClass the configuration class
 988  
          */
 989  
         public ConfigurationProvider(Class<?> configClass)
 990  54
         {
 991  54
             setConfigurationClass(configClass);
 992  54
         }
 993  
 
 994  
         /**
 995  
          * Creates a new instance of {@code ConfigurationProvider} and
 996  
          * sets the name of the class of the configuration created by this
 997  
          * provider.
 998  
          *
 999  
          * @param configClassName the name of the configuration class
 1000  
          * @since 1.4
 1001  
          */
 1002  
         public ConfigurationProvider(String configClassName)
 1003  0
         {
 1004  0
             setConfigurationClassName(configClassName);
 1005  0
         }
 1006  
 
 1007  
         /**
 1008  
          * Returns the class of the configuration returned by this provider.
 1009  
          *
 1010  
          * @return the class of the provided configuration
 1011  
          */
 1012  
         public Class<?> getConfigurationClass()
 1013  
         {
 1014  544
             return configurationClass;
 1015  
         }
 1016  
 
 1017  
         /**
 1018  
          * Sets the class of the configuration returned by this provider.
 1019  
          *
 1020  
          * @param configurationClass the configuration class
 1021  
          */
 1022  
         public void setConfigurationClass(Class<?> configurationClass)
 1023  
         {
 1024  155
             this.configurationClass = configurationClass;
 1025  155
         }
 1026  
 
 1027  
         /**
 1028  
          * Returns the name of the configuration class returned by this
 1029  
          * provider.
 1030  
          *
 1031  
          * @return the configuration class name
 1032  
          * @since 1.4
 1033  
          */
 1034  
         public String getConfigurationClassName()
 1035  
         {
 1036  71
             return configurationClassName;
 1037  
         }
 1038  
 
 1039  
         /**
 1040  
          * Sets the name of the configuration class returned by this provider.
 1041  
          *
 1042  
          * @param configurationClassName the name of the configuration class
 1043  
          * @since 1.4
 1044  
          */
 1045  
         public void setConfigurationClassName(String configurationClassName)
 1046  
         {
 1047  0
             this.configurationClassName = configurationClassName;
 1048  0
         }
 1049  
 
 1050  
         /**
 1051  
          * Returns the configuration. This method is called to fetch the
 1052  
          * configuration from the provider. This implementation will call the
 1053  
          * inherited {@link
 1054  
          * org.apache.commons.configuration.beanutils.DefaultBeanFactory#createBean(Class, BeanDeclaration, Object)
 1055  
          * createBean()} method to create a new instance of the
 1056  
          * configuration class.
 1057  
          *
 1058  
          * @param decl the bean declaration with initialization parameters for
 1059  
          * the configuration
 1060  
          * @return the new configuration object
 1061  
          * @throws Exception if an error occurs
 1062  
          */
 1063  
         public AbstractConfiguration getConfiguration(
 1064  
                 ConfigurationDeclaration decl) throws Exception
 1065  
         {
 1066  270
             return (AbstractConfiguration) createBean(fetchConfigurationClass(),
 1067  
                     decl, null);
 1068  
         }
 1069  
 
 1070  
         /**
 1071  
          * Returns an uninitialized configuration of the represented type. This
 1072  
          * method will be called for optional configurations when the
 1073  
          * {@code getConfiguration()} method caused an error and the
 1074  
          * {@code forceCreate} attribute is set. A concrete sub class can
 1075  
          * here try to create an uninitialized, empty configuration, which may
 1076  
          * be possible if the error was created during initialization. This base
 1077  
          * implementation just returns <b>null</b>.
 1078  
          *
 1079  
          * @param decl the bean declaration with initialization parameters for
 1080  
          * the configuration
 1081  
          * @return the new configuration object
 1082  
          * @throws Exception if an error occurs
 1083  
          * @since 1.4
 1084  
          */
 1085  
         public AbstractConfiguration getEmptyConfiguration(
 1086  
                 ConfigurationDeclaration decl) throws Exception
 1087  
         {
 1088  0
             return null;
 1089  
         }
 1090  
 
 1091  
         /**
 1092  
          * Returns the configuration class supported by this provider. If a
 1093  
          * class object was set, it is returned. Otherwise the method tries to
 1094  
          * resolve the class name.
 1095  
          *
 1096  
          * @return the class of the configuration to be created
 1097  
          * @since 1.4
 1098  
          */
 1099  
         protected synchronized Class<?> fetchConfigurationClass() throws Exception
 1100  
         {
 1101  272
             if (getConfigurationClass() == null)
 1102  
             {
 1103  71
                 setConfigurationClass(loadClass(getConfigurationClassName()));
 1104  
             }
 1105  272
             return getConfigurationClass();
 1106  
         }
 1107  
 
 1108  
         /**
 1109  
          * Loads the class with the specified name dynamically. If the class's
 1110  
          * name is <b>null</b>, <b>null</b> will also be returned.
 1111  
          *
 1112  
          * @param className the name of the class to be loaded
 1113  
          * @return the class object
 1114  
          * @throws ClassNotFoundException if class loading fails
 1115  
          * @since 1.4
 1116  
          */
 1117  
         protected Class<?> loadClass(String className)
 1118  
                 throws ClassNotFoundException
 1119  
         {
 1120  71
             return (className != null) ? Class.forName(className, true,
 1121  
                     getClass().getClassLoader()) : null;
 1122  
         }
 1123  
     }
 1124  
 
 1125  
     /**
 1126  
      * <p>
 1127  
      * A specialized {@code BeanDeclaration} implementation that
 1128  
      * represents the declaration of a configuration source.
 1129  
      * </p>
 1130  
      * <p>
 1131  
      * Instances of this class are able to extract all information about a
 1132  
      * configuration source from the configuration definition file. The
 1133  
      * declaration of a configuration source is very similar to a bean
 1134  
      * declaration processed by {@code XMLBeanDeclaration}. There are
 1135  
      * very few differences, e.g. some reserved attributes like
 1136  
      * {@code optional} and {@code at} and the fact that a bean
 1137  
      * factory is never needed.
 1138  
      * </p>
 1139  
      */
 1140  
     public static class ConfigurationDeclaration extends XMLBeanDeclaration
 1141  
     {
 1142  
         /** Stores a reference to the associated configuration builder. */
 1143  
         private DefaultConfigurationBuilder configurationBuilder;
 1144  
 
 1145  
         /**
 1146  
          * Creates a new instance of {@code ConfigurationDeclaration} and
 1147  
          * initializes it.
 1148  
          *
 1149  
          * @param builder the associated configuration builder
 1150  
          * @param config the configuration this declaration is based onto
 1151  
          */
 1152  
         public ConfigurationDeclaration(DefaultConfigurationBuilder builder,
 1153  
                 HierarchicalConfiguration config)
 1154  
         {
 1155  281
             super(config);
 1156  281
             configurationBuilder = builder;
 1157  281
         }
 1158  
 
 1159  
         /**
 1160  
          * Returns the associated configuration builder.
 1161  
          *
 1162  
          * @return the configuration builder
 1163  
          */
 1164  
         public DefaultConfigurationBuilder getConfigurationBuilder()
 1165  
         {
 1166  1528
             return configurationBuilder;
 1167  
         }
 1168  
 
 1169  
         /**
 1170  
          * Returns the value of the {@code at} attribute.
 1171  
          *
 1172  
          * @return the value of the {@code at} attribute (can be <b>null</b>)
 1173  
          */
 1174  
         public String getAt()
 1175  
         {
 1176  240
             String result = this.getConfiguration().getString(ATTR_AT_RES);
 1177  240
             return (result == null) ? this.getConfiguration().getString(ATTR_AT)
 1178  
                     : result;
 1179  
         }
 1180  
 
 1181  
         /**
 1182  
          * Returns a flag whether this is an optional configuration.
 1183  
          *
 1184  
          * @return a flag if this declaration points to an optional
 1185  
          * configuration
 1186  
          */
 1187  
         public boolean isOptional()
 1188  
         {
 1189  40
             Boolean value = this.getConfiguration().getBoolean(ATTR_OPTIONAL_RES,
 1190  
                     null);
 1191  40
             if (value == null)
 1192  
             {
 1193  26
                 value = this.getConfiguration().getBoolean(ATTR_OPTIONAL,
 1194  
                         Boolean.FALSE);
 1195  
             }
 1196  38
             return value.booleanValue();
 1197  
         }
 1198  
 
 1199  
         /**
 1200  
          * Returns a flag whether this configuration should always be created
 1201  
          * and added to the resulting combined configuration. This flag is
 1202  
          * evaluated only for optional configurations whose normal creation has
 1203  
          * caused an error. If for such a configuration the
 1204  
          * {@code forceCreate} attribute is set and the corresponding
 1205  
          * configuration provider supports this mode, an empty configuration
 1206  
          * will be created and added to the resulting combined configuration.
 1207  
          *
 1208  
          * @return the value of the {@code forceCreate} attribute
 1209  
          * @since 1.4
 1210  
          */
 1211  
         public boolean isForceCreate()
 1212  
         {
 1213  32
             return this.getConfiguration().getBoolean(ATTR_FORCECREATE, false);
 1214  
         }
 1215  
 
 1216  
         /**
 1217  
          * Returns the name of the bean factory. For configuration source
 1218  
          * declarations always a reserved factory is used. This factory's name
 1219  
          * is returned by this implementation.
 1220  
          *
 1221  
          * @return the name of the bean factory
 1222  
          */
 1223  
         @Override
 1224  
         public String getBeanFactoryName()
 1225  
         {
 1226  270
             return CONFIG_BEAN_FACTORY_NAME;
 1227  
         }
 1228  
 
 1229  
         /**
 1230  
          * Returns the bean's class name. This implementation will always return
 1231  
          * <b>null</b>.
 1232  
          *
 1233  
          * @return the name of the bean's class
 1234  
          */
 1235  
         @Override
 1236  
         public String getBeanClassName()
 1237  
         {
 1238  279
             return null;
 1239  
         }
 1240  
 
 1241  
         /**
 1242  
          * Checks whether the given node is reserved. This method will take
 1243  
          * further reserved attributes into account
 1244  
          *
 1245  
          * @param nd the node
 1246  
          * @return a flag whether this node is reserved
 1247  
          */
 1248  
         @Override
 1249  
         protected boolean isReservedNode(ConfigurationNode nd)
 1250  
         {
 1251  723
             if (super.isReservedNode(nd))
 1252  
             {
 1253  180
                 return true;
 1254  
             }
 1255  
 
 1256  543
             return nd.isAttribute()
 1257  
                     && ((ATTR_ATNAME.equals(nd.getName()) && nd.getParentNode()
 1258  
                             .getAttributeCount(RESERVED_PREFIX + ATTR_ATNAME) == 0) || (ATTR_OPTIONALNAME
 1259  
                             .equals(nd.getName()) && nd.getParentNode()
 1260  
                             .getAttributeCount(RESERVED_PREFIX + ATTR_OPTIONALNAME) == 0));
 1261  
         }
 1262  
 
 1263  
         /**
 1264  
          * Performs interpolation. This implementation will delegate
 1265  
          * interpolation to the configuration builder, which takes care that the
 1266  
          * currently constructed configuration is taken into account, too.
 1267  
          *
 1268  
          * @param value the value to be interpolated
 1269  
          * @return the interpolated value
 1270  
          */
 1271  
         @Override
 1272  
         protected Object interpolate(Object value)
 1273  
         {
 1274  373
             return getConfigurationBuilder().interpolate(value);
 1275  
         }
 1276  
     }
 1277  
 
 1278  
     /**
 1279  
      * A specialized {@code BeanFactory} implementation that handles
 1280  
      * configuration declarations. This class will retrieve the correct
 1281  
      * configuration provider and delegate the task of creating the
 1282  
      * configuration to this object.
 1283  
      */
 1284  1
     static class ConfigurationBeanFactory implements BeanFactory
 1285  
     {
 1286  
         /** The logger. */
 1287  1
         private Log logger = LogFactory.getLog(DefaultConfigurationBuilder.class);
 1288  
 
 1289  
         /**
 1290  
          * Creates an instance of a bean class. This implementation expects that
 1291  
          * the passed in bean declaration is a declaration for a configuration.
 1292  
          * It will determine the responsible configuration provider and delegate
 1293  
          * the call to this instance. If creation of the configuration fails
 1294  
          * and the {@code optional} attribute is set, the exception will
 1295  
          * be ignored. If the {@code forceCreate} attribute is set, too,
 1296  
          * the provider is asked to create an empty configuration. A return
 1297  
          * value of <b>null</b> means that no configuration could be created.
 1298  
          *
 1299  
          * @param beanClass the bean class (will be ignored)
 1300  
          * @param data the declaration
 1301  
          * @param param an additional parameter (will be ignored)
 1302  
          * @return the newly created configuration
 1303  
          * @throws Exception if an error occurs
 1304  
          */
 1305  
         public Object createBean(Class<?> beanClass, BeanDeclaration data,
 1306  
                 Object param) throws Exception
 1307  
         {
 1308  270
             ConfigurationDeclaration decl = (ConfigurationDeclaration) data;
 1309  270
             String tagName = decl.getNode().getName();
 1310  270
             ConfigurationProvider provider = decl.getConfigurationBuilder()
 1311  
                     .providerForTag(tagName);
 1312  270
             if (provider == null)
 1313  
             {
 1314  2
                 throw new ConfigurationRuntimeException(
 1315  
                         "No ConfigurationProvider registered for tag "
 1316  
                                 + tagName);
 1317  
             }
 1318  
 
 1319  
             try
 1320  
             {
 1321  268
                 AbstractConfiguration config = provider.getConfiguration(decl);
 1322  234
                 installInterpolator(decl, config);
 1323  234
                 return config;
 1324  
             }
 1325  34
             catch (Exception ex)
 1326  
             {
 1327  
                 // If this is an optional configuration, ignore the exception
 1328  34
                 if (!decl.isOptional())
 1329  
                 {
 1330  2
                     throw ex;
 1331  
                 }
 1332  
                 else
 1333  
                 {
 1334  32
                     if (logger.isDebugEnabled())
 1335  
                     {
 1336  0
                         logger.debug("Load failed for optional configuration " + tagName + ": "
 1337  
                             + ex.getMessage());
 1338  
                     }
 1339  
                     // Notify registered error listeners
 1340  32
                     decl.getConfigurationBuilder().fireError(
 1341  
                             EVENT_ERR_LOAD_OPTIONAL,
 1342  
                             decl.getConfiguration().getString(ATTR_NAME), null,
 1343  
                             ex);
 1344  
 
 1345  32
                     if (decl.isForceCreate())
 1346  
                     {
 1347  
                         try
 1348  
                         {
 1349  6
                             return provider.getEmptyConfiguration(decl);
 1350  
                         }
 1351  2
                         catch (Exception ex2)
 1352  
                         {
 1353  
                             // Ignore exception, return null in this case
 1354  2
                             logger.warn("Could not create instance of optional configuration "
 1355  
                                     + tagName, ex2);
 1356  
                         }
 1357  
                     }
 1358  28
                     return null;
 1359  
                 }
 1360  
             }
 1361  
         }
 1362  
 
 1363  
         /**
 1364  
          * Returns the default class for this bean factory.
 1365  
          *
 1366  
          * @return the default class
 1367  
          */
 1368  
         public Class<?> getDefaultBeanClass()
 1369  
         {
 1370  
             // Here some valid class must be returned, otherwise BeanHelper
 1371  
             // will complain that the bean's class cannot be determined
 1372  270
             return Configuration.class;
 1373  
         }
 1374  
 
 1375  
         /**
 1376  
          * Installs a specialized {@code ConfigurationInterpolator} on a newly
 1377  
          * created configuration which also takes the combined configuration
 1378  
          * created by the builder into account. With this
 1379  
          * {@code ConfigurationInterpolator} the interpolation facilities of
 1380  
          * this child configuration are extended to include all other
 1381  
          * configurations created by this builder.
 1382  
          *
 1383  
          * @param decl the {@code ConfigurationDeclaration}
 1384  
          * @param config the newly created configuration instance
 1385  
          */
 1386  
         private void installInterpolator(ConfigurationDeclaration decl,
 1387  
                 AbstractConfiguration config)
 1388  
         {
 1389  234
             ConfigurationInterpolator parent = new ConfigurationInterpolator();
 1390  234
             parent.setDefaultLookup(decl.getConfigurationBuilder().combinedConfigLookup);
 1391  234
             config.getInterpolator().setParentInterpolator(parent);
 1392  234
         }
 1393  
     }
 1394  
 
 1395  
     /**
 1396  
      * A specialized provider implementation that deals with file based
 1397  
      * configurations. Ensures that the base path is correctly set and that the
 1398  
      * load() method gets called.
 1399  
      */
 1400  
     public static class FileConfigurationProvider extends ConfigurationProvider
 1401  
     {
 1402  
         /**
 1403  
          * Creates a new instance of {@code FileConfigurationProvider}.
 1404  
          */
 1405  
         public FileConfigurationProvider()
 1406  
         {
 1407  34
             super();
 1408  34
         }
 1409  
 
 1410  
         /**
 1411  
          * Creates a new instance of {@code FileConfigurationProvider}
 1412  
          * and sets the configuration class.
 1413  
          *
 1414  
          * @param configClass the class for the configurations to be created
 1415  
          */
 1416  
         public FileConfigurationProvider(Class<?> configClass)
 1417  
         {
 1418  4
             super(configClass);
 1419  4
         }
 1420  
 
 1421  
         /**
 1422  
          * Creates a new instance of {@code FileConfigurationProvider}
 1423  
          * and sets the configuration class name.
 1424  
          *
 1425  
          * @param configClassName the name of the configuration to be created
 1426  
          * @since 1.4
 1427  
          */
 1428  
         public FileConfigurationProvider(String configClassName)
 1429  
         {
 1430  0
             super(configClassName);
 1431  0
         }
 1432  
 
 1433  
         /**
 1434  
          * Creates the configuration. After that {@code load()} will be
 1435  
          * called. If this configuration is marked as optional, exceptions will
 1436  
          * be ignored.
 1437  
          *
 1438  
          * @param decl the declaration
 1439  
          * @return the new configuration
 1440  
          * @throws Exception if an error occurs
 1441  
          */
 1442  
         @Override
 1443  
         public AbstractConfiguration getConfiguration(
 1444  
                 ConfigurationDeclaration decl) throws Exception
 1445  
         {
 1446  225
             AbstractConfiguration result = getEmptyConfiguration(decl);
 1447  225
             if (result instanceof FileSystemBased)
 1448  
             {
 1449  225
                 DefaultConfigurationBuilder builder = decl.getConfigurationBuilder();
 1450  225
                 if (builder.getFileSystem() != null)
 1451  
                 {
 1452  225
                     ((FileSystemBased) result).setFileSystem(builder.getFileSystem());
 1453  
                 }
 1454  
             }
 1455  225
             ((FileConfiguration) result).load();
 1456  199
             return result;
 1457  
         }
 1458  
 
 1459  
         /**
 1460  
          * Returns an uninitialized file configuration. This method will be
 1461  
          * called for optional configurations when the
 1462  
          * {@code getConfiguration()} method caused an error and the
 1463  
          * {@code forceCreate} attribute is set. It will create the
 1464  
          * configuration of the represented type, but the {@code load()}
 1465  
          * method won't be called. This way non-existing configuration files can
 1466  
          * be handled gracefully: If loading a the file fails, an empty
 1467  
          * configuration will be created that is already configured with the
 1468  
          * correct file name.
 1469  
          *
 1470  
          * @param decl the bean declaration with initialization parameters for
 1471  
          * the configuration
 1472  
          * @return the new configuration object
 1473  
          * @throws Exception if an error occurs
 1474  
          * @since 1.4
 1475  
          */
 1476  
         @Override
 1477  
         public AbstractConfiguration getEmptyConfiguration(
 1478  
                 ConfigurationDeclaration decl) throws Exception
 1479  
         {
 1480  227
             AbstractConfiguration config = super.getConfiguration(decl);
 1481  
 
 1482  
             /**
 1483  
              * Some wrapper classes may need to pass the EntityResolver to XMLConfigurations
 1484  
              * they construct buy may not be an XMLConfiguration.
 1485  
              */
 1486  227
             if (config instanceof EntityResolverSupport)
 1487  
             {
 1488  28
                 DefaultConfigurationBuilder builder = decl.getConfigurationBuilder();
 1489  28
                 EntityResolver resolver = builder.getEntityResolver();
 1490  28
                 ((EntityResolverSupport) config).setEntityResolver(resolver);
 1491  
             }
 1492  
 
 1493  227
             return config;
 1494  
         }
 1495  
 
 1496  
         /**
 1497  
          * Initializes the bean instance. Ensures that the file configuration's
 1498  
          * base path will be initialized with the base path of the factory so
 1499  
          * that relative path names can be correctly resolved.
 1500  
          *
 1501  
          * @param bean the bean to be initialized
 1502  
          * @param data the declaration
 1503  
          * @throws Exception if an error occurs
 1504  
          */
 1505  
         @Override
 1506  
         protected void initBeanInstance(Object bean, BeanDeclaration data)
 1507  
                 throws Exception
 1508  
         {
 1509  227
             FileConfiguration config = (FileConfiguration) bean;
 1510  227
             config.setBasePath(((ConfigurationDeclaration) data)
 1511  
                     .getConfigurationBuilder().getConfigurationBasePath());
 1512  227
             super.initBeanInstance(bean, data);
 1513  227
         }
 1514  
     }
 1515  
 
 1516  
     /**
 1517  
      * A specialized configuration provider for XML configurations. This
 1518  
      * implementation acts like a {@code FileConfigurationProvider}, but
 1519  
      * it will copy all entity IDs that have been registered for the
 1520  
      * configuration builder to the new XML configuration before it is loaded.
 1521  
      *
 1522  
      * @since 1.6
 1523  
      */
 1524  
     public static class XMLConfigurationProvider extends FileConfigurationProvider
 1525  
     {
 1526  
         /**
 1527  
          * Creates a new instance of {@code XMLConfigurationProvider}.
 1528  
          */
 1529  
         public XMLConfigurationProvider()
 1530  
         {
 1531  3
             super(XMLConfiguration.class);
 1532  3
         }
 1533  
 
 1534  
         /**
 1535  
          * Returns a new empty configuration instance. This implementation
 1536  
          * performs some additional initialization specific to XML
 1537  
          * configurations.
 1538  
          *
 1539  
          * @param decl the configuration declaration
 1540  
          * @return the new configuration
 1541  
          * @throws Exception if an error occurs
 1542  
          */
 1543  
         @Override
 1544  
         public AbstractConfiguration getEmptyConfiguration(
 1545  
                 ConfigurationDeclaration decl) throws Exception
 1546  
         {
 1547  126
             XMLConfiguration config = (XMLConfiguration) super
 1548  
                     .getEmptyConfiguration(decl);
 1549  
 
 1550  126
             DefaultConfigurationBuilder builder = decl
 1551  
                     .getConfigurationBuilder();
 1552  126
             EntityResolver resolver = builder.getEntityResolver();
 1553  126
             if (resolver instanceof EntityRegistry)
 1554  
             {
 1555  
                 // copy the registered entities
 1556  108
                 config.getRegisteredEntities().putAll(
 1557  
                     builder.getRegisteredEntities());
 1558  
             }
 1559  
             else
 1560  
             {
 1561  18
                 config.setEntityResolver(resolver);
 1562  
             }
 1563  126
             return config;
 1564  
         }
 1565  
     }
 1566  
 
 1567  
     /**
 1568  
      * A specialized configuration provider for file based configurations that
 1569  
      * can handle configuration sources whose concrete type depends on the
 1570  
      * extension of the file to be loaded. One example is the
 1571  
      * {@code properties} tag: if the file ends with ".xml" a
 1572  
      * XMLPropertiesConfiguration object must be created, otherwise a
 1573  
      * PropertiesConfiguration object.
 1574  
      */
 1575  
     static class FileExtensionConfigurationProvider extends
 1576  
             FileConfigurationProvider
 1577  
     {
 1578  
         /**
 1579  
          * Stores the class to be created when the file extension matches.
 1580  
          */
 1581  
         private Class<?> matchingClass;
 1582  
 
 1583  
         /**
 1584  
          * Stores the name of the class to be created when the file extension
 1585  
          * matches.
 1586  
          */
 1587  
         private String matchingClassName;
 1588  
 
 1589  
         /**
 1590  
          * Stores the class to be created when the file extension does not
 1591  
          * match.
 1592  
          */
 1593  
         private Class<?> defaultClass;
 1594  
 
 1595  
         /**
 1596  
          * Stores the name of the class to be created when the file extension
 1597  
          * does not match.
 1598  
          */
 1599  
         private String defaultClassName;
 1600  
 
 1601  
         /** Stores the file extension to be checked against. */
 1602  
         private String fileExtension;
 1603  
 
 1604  
         /**
 1605  
          * Creates a new instance of
 1606  
          * {@code FileExtensionConfigurationProvider} and initializes it.
 1607  
          *
 1608  
          * @param matchingClass the class to be created when the file extension
 1609  
          * matches
 1610  
          * @param defaultClass the class to be created when the file extension
 1611  
          * does not match
 1612  
          * @param extension the file extension to be checked against
 1613  
          */
 1614  
         public FileExtensionConfigurationProvider(Class<?> matchingClass,
 1615  
                 Class<?> defaultClass, String extension)
 1616  1
         {
 1617  1
             this.matchingClass = matchingClass;
 1618  1
             this.defaultClass = defaultClass;
 1619  1
             fileExtension = extension;
 1620  1
         }
 1621  
 
 1622  
         /**
 1623  
          * Creates a new instance of
 1624  
          * {@code FileExtensionConfigurationProvider} and initializes it
 1625  
          * with the names of the classes to be created.
 1626  
          *
 1627  
          * @param matchingClassName the name of the class to be created when the
 1628  
          * file extension matches
 1629  
          * @param defaultClassName the name of the class to be created when the
 1630  
          * file extension does not match
 1631  
          * @param extension the file extension to be checked against
 1632  
          * @since 1.4
 1633  
          */
 1634  
         public FileExtensionConfigurationProvider(String matchingClassName,
 1635  
                 String defaultClassName, String extension)
 1636  1
         {
 1637  1
             this.matchingClassName = matchingClassName;
 1638  1
             this.defaultClassName = defaultClassName;
 1639  1
             fileExtension = extension;
 1640  1
         }
 1641  
 
 1642  
         /**
 1643  
          * Returns the matching class object, no matter whether it was defined
 1644  
          * as a class or as a class name.
 1645  
          *
 1646  
          * @return the matching class object
 1647  
          * @throws Exception if an error occurs
 1648  
          * @since 1.4
 1649  
          */
 1650  
         protected synchronized Class<?> fetchMatchingClass() throws Exception
 1651  
         {
 1652  16
             if (matchingClass == null)
 1653  
             {
 1654  0
                 matchingClass = loadClass(matchingClassName);
 1655  
             }
 1656  16
             return matchingClass;
 1657  
         }
 1658  
 
 1659  
         /**
 1660  
          * Returns the default class object, no matter whether it was defined as
 1661  
          * a class or as a class name.
 1662  
          *
 1663  
          * @return the default class object
 1664  
          * @throws Exception if an error occurs
 1665  
          * @since 1.4
 1666  
          */
 1667  
         protected synchronized Class<?> fetchDefaultClass() throws Exception
 1668  
         {
 1669  55
             if (defaultClass == null)
 1670  
             {
 1671  0
                 defaultClass = loadClass(defaultClassName);
 1672  
             }
 1673  55
             return defaultClass;
 1674  
         }
 1675  
 
 1676  
         /**
 1677  
          * Creates the configuration object. The class is determined by the file
 1678  
          * name's extension.
 1679  
          *
 1680  
          * @param beanClass the class
 1681  
          * @param data the bean declaration
 1682  
          * @return the new bean
 1683  
          * @throws Exception if an error occurs
 1684  
          */
 1685  
         @Override
 1686  
         protected Object createBeanInstance(Class<?> beanClass,
 1687  
                 BeanDeclaration data) throws Exception
 1688  
         {
 1689  71
             String fileName = ((ConfigurationDeclaration) data)
 1690  
                     .getConfiguration().getString(ATTR_FILENAME);
 1691  71
             if (fileName != null
 1692  
                     && fileName.toLowerCase().trim().endsWith(fileExtension))
 1693  
             {
 1694  16
                 return super.createBeanInstance(fetchMatchingClass(), data);
 1695  
             }
 1696  
             else
 1697  
             {
 1698  55
                 return super.createBeanInstance(fetchDefaultClass(), data);
 1699  
             }
 1700  
         }
 1701  
     }
 1702  
 
 1703  
     /**
 1704  
      * A specialized configuration provider class that allows to include other
 1705  
      * configuration definition files.
 1706  
      */
 1707  
     static class ConfigurationBuilderProvider extends ConfigurationProvider
 1708  
     {
 1709  
         /**
 1710  
          * Creates a new instance of {@code ConfigurationBuilderProvider}.
 1711  
          */
 1712  
         public ConfigurationBuilderProvider()
 1713  
         {
 1714  5
             super(DefaultConfigurationBuilder.class);
 1715  5
         }
 1716  
 
 1717  
         /**
 1718  
          * Creates the configuration. First creates a configuration builder
 1719  
          * object. Then returns the configuration created by this builder.
 1720  
          *
 1721  
          * @param decl the configuration declaration
 1722  
          * @return the configuration
 1723  
          * @exception Exception if an error occurs
 1724  
          */
 1725  
         @Override
 1726  
         public AbstractConfiguration getConfiguration(
 1727  
                 ConfigurationDeclaration decl) throws Exception
 1728  
         {
 1729  11
             DefaultConfigurationBuilder builder = (DefaultConfigurationBuilder) super
 1730  
                     .getConfiguration(decl);
 1731  11
             return builder.getConfiguration(true);
 1732  
         }
 1733  
 
 1734  
         /**
 1735  
          * Returns an empty configuration in case of an optional configuration
 1736  
          * could not be created. This implementation returns an empty combined
 1737  
          * configuration.
 1738  
          *
 1739  
          * @param decl the configuration declaration
 1740  
          * @return the configuration
 1741  
          * @exception Exception if an error occurs
 1742  
          * @since 1.4
 1743  
          */
 1744  
         @Override
 1745  
         public AbstractConfiguration getEmptyConfiguration(
 1746  
                 ConfigurationDeclaration decl) throws Exception
 1747  
         {
 1748  2
             return new CombinedConfiguration();
 1749  
         }
 1750  
 
 1751  
         /**
 1752  
          * {@inheritDoc} This implementation ensures that the configuration
 1753  
          * builder created by this provider inherits the properties from the
 1754  
          * current configuration builder.
 1755  
          */
 1756  
         @Override
 1757  
         protected void initBeanInstance(Object bean, BeanDeclaration data)
 1758  
                 throws Exception
 1759  
         {
 1760  13
             ConfigurationDeclaration decl = (ConfigurationDeclaration) data;
 1761  13
             initChildBuilder(decl.getConfigurationBuilder(),
 1762  
                     (DefaultConfigurationBuilder) bean);
 1763  13
             super.initBeanInstance(bean, data);
 1764  13
         }
 1765  
 
 1766  
         /**
 1767  
          * Initializes the given child configuration builder from its parent
 1768  
          * builder. This method copies the values of some properties from the
 1769  
          * parent builder to the child builder so that the child inherits
 1770  
          * properties from its parent.
 1771  
          *
 1772  
          * @param parent the parent builder
 1773  
          * @param child the child builder
 1774  
          */
 1775  
         private static void initChildBuilder(
 1776  
                 DefaultConfigurationBuilder parent,
 1777  
                 DefaultConfigurationBuilder child)
 1778  
         {
 1779  13
             child.setAttributeSplittingDisabled(parent
 1780  
                     .isAttributeSplittingDisabled());
 1781  13
             child.setBasePath(parent.getBasePath());
 1782  13
             child.setDelimiterParsingDisabled(parent
 1783  
                     .isDelimiterParsingDisabled());
 1784  13
             child.setListDelimiter(parent.getListDelimiter());
 1785  13
             child.setThrowExceptionOnMissing(parent.isThrowExceptionOnMissing());
 1786  13
             child.setLogger(parent.getLogger());
 1787  
 
 1788  13
             child.clearConfigurationListeners();
 1789  13
             for (ConfigurationListener l : parent.getConfigurationListeners())
 1790  
             {
 1791  1
                 child.addConfigurationListener(l);
 1792  1
             }
 1793  13
             child.clearErrorListeners();
 1794  13
             for (ConfigurationErrorListener l : parent.getErrorListeners())
 1795  
             {
 1796  2
                 child.addErrorListener(l);
 1797  2
             }
 1798  13
         }
 1799  
     }
 1800  
 }