##### Coverage Report - org.apache.commons.configuration.DefaultConfigurationBuilder

Classes in this File | Line Coverage | Branch Coverage | Complexity
DefaultConfigurationBuilder |
98% | 123/125
100% | 22/22
| 1.7096774193548387;1,71
DefaultConfigurationBuilder$ConfigurationBeanFactory |
100% | 16/16
100% | 4/4
| 1.7096774193548387;1,71
DefaultConfigurationBuilder$ConfigurationBuilderProvider |
100% | 5/5
100% | 1/1
| 1.7096774193548387;1,71
DefaultConfigurationBuilder$ConfigurationDeclaration |
100% | 17/17
100% | 4/4
| 1.7096774193548387;1,71
DefaultConfigurationBuilder$ConfigurationProvider |
70% | 14/20
100% | 2/2
| 1.7096774193548387;1,71
DefaultConfigurationBuilder$FileConfigurationProvider |
86% | 12/14
N/A | N/A
| 1.7096774193548387;1,71
DefaultConfigurationBuilder$FileExtensionConfigurationProvider |
90% | 18/20
100% | 3/3
| 1.7096774193548387;1,71
DefaultConfigurationBuilder$XMLConfigurationProvider |
100% | 6/6
100% | 1/1
| 1.7096774193548387;1,71

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