Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ConfigurationFactory |
|
| 1.575;1,575 | ||||
ConfigurationFactory$AdditionalConfigurationData |
|
| 1.575;1,575 | ||||
ConfigurationFactory$ConfigurationBuilder |
|
| 1.575;1,575 | ||||
ConfigurationFactory$DigesterConfigurationFactory |
|
| 1.575;1,575 | ||||
ConfigurationFactory$FileConfigurationFactory |
|
| 1.575;1,575 | ||||
ConfigurationFactory$JNDIConfigurationFactory |
|
| 1.575;1,575 | ||||
ConfigurationFactory$PropertiesConfigurationFactory |
|
| 1.575;1,575 | ||||
ConfigurationFactory$PropertyListConfigurationFactory |
|
| 1.575;1,575 | ||||
ConfigurationFactory$SystemConfigurationFactory |
|
| 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><override></code> and <code><additional></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><additional></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><additional></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 | } |