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

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

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