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

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

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