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

Classes in this File | Line Coverage | Branch Coverage | Complexity
ConfigurationFactory |
97% | 85/88
100% | 12/12
| 1.575;1,575
ConfigurationFactory$AdditionalConfigurationData |
100% | 7/7
N/A | N/A
| 1.575;1,575
ConfigurationFactory$ConfigurationBuilder |
100% | 24/24
100% | 5/5
| 1.575;1,575
ConfigurationFactory$DigesterConfigurationFactory |
100% | 4/4
N/A | N/A
| 1.575;1,575
ConfigurationFactory$FileConfigurationFactory |
100% | 14/14
100% | 1/1
| 1.575;1,575
ConfigurationFactory$JNDIConfigurationFactory |
100% | 4/4
100% | 1/1
| 1.575;1,575
ConfigurationFactory$PropertiesConfigurationFactory |
100% | 7/7
100% | 1/1
| 1.575;1,575
ConfigurationFactory$PropertyListConfigurationFactory |
43% | 3/7
0% | 0/1
| 1.575;1,575
ConfigurationFactory$SystemConfigurationFactory |
100% | 4/4
100% | 1/1
| 1.575;1,575

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