Coverage report

| %line | %branch
--- | --- | ---
org.apache.commons.configuration.ConfigurationFactory$HierarchicalConfigurationNodeConverter |
100% |
100% |

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

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.