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