1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.springframework.extensions.config.xml;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Properties;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.dom4j.Document;
33 import org.dom4j.Element;
34 import org.dom4j.io.SAXReader;
35 import org.springframework.beans.BeansException;
36 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
37 import org.springframework.core.Constants;
38 import org.springframework.core.io.Resource;
39 import org.springframework.extensions.config.BaseConfigService;
40 import org.springframework.extensions.config.ConfigDeployer;
41 import org.springframework.extensions.config.ConfigDeployment;
42 import org.springframework.extensions.config.ConfigElement;
43 import org.springframework.extensions.config.ConfigException;
44 import org.springframework.extensions.config.ConfigSection;
45 import org.springframework.extensions.config.ConfigSectionImpl;
46 import org.springframework.extensions.config.ConfigSource;
47 import org.springframework.extensions.config.evaluator.Evaluator;
48 import org.springframework.extensions.config.xml.elementreader.ConfigElementReader;
49 import org.springframework.extensions.config.xml.elementreader.GenericElementReader;
50 import org.springframework.util.PropertyPlaceholderHelper;
51 import org.springframework.util.StringValueResolver;
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class XMLConfigService extends BaseConfigService implements XMLConfigConstants
66 {
67 private static final Log logger = LogFactory.getLog(XMLConfigService.class);
68
69 private static final Constants constants = new Constants(PropertyPlaceholderConfigurer.class);
70
71 private Resource[] propertyLocations;
72 private int systemPropertiesMode = PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE;
73 private PropertyConfigurer propertyConfigurer;
74 private Map<String, ConfigElementReader> elementReaders;
75
76
77
78
79
80
81
82 public XMLConfigService(ConfigSource configSource)
83 {
84 super(configSource);
85 }
86
87
88
89
90
91
92 public void setProperties(Resource[] locations)
93 {
94 this.propertyLocations = locations;
95 }
96
97
98
99
100
101
102
103
104 public void setSystemPropertiesModeName(String constantName) throws IllegalArgumentException
105 {
106 this.systemPropertiesMode = constants.asNumber(constantName).intValue();
107 }
108
109 public List<ConfigDeployment> initConfig()
110 {
111 if (logger.isDebugEnabled())
112 logger.debug("Commencing initialisation");
113
114 List<ConfigDeployment> configDeployments = super.initConfig();
115
116
117 propertyConfigurer = null;
118 if (propertyLocations != null)
119 {
120 PropertyConfigurer configurer = new PropertyConfigurer();
121 configurer.setLocations(propertyLocations);
122 configurer.setIgnoreUnresolvablePlaceholders(true);
123 configurer.setSystemPropertiesMode(systemPropertiesMode);
124 configurer.init();
125 propertyConfigurer = configurer;
126 }
127
128
129 putElementReaders(new HashMap<String, ConfigElementReader>());
130
131 List<ConfigDeployment> deployments = parse();
132 configDeployments.addAll(deployments);
133
134
135 for (ConfigDeployer configDeployer : configDeployers)
136 {
137 deployments = configDeployer.initConfig();
138 configDeployments.addAll(deployments);
139 }
140
141 if (logger.isDebugEnabled())
142 logger.debug("Completed initialisation");
143
144 return configDeployments;
145 }
146
147 public void destroy()
148 {
149 removeElementReaders();
150 super.destroy();
151 }
152
153 protected void parse(InputStream stream)
154 {
155 Map<String, ConfigElementReader> parsedElementReaders = null;
156 Map<String, Evaluator> parsedEvaluators = null;
157 List<ConfigSection> parsedConfigSections = new ArrayList<ConfigSection>();
158
159 String currentArea = null;
160 try
161 {
162
163 SAXReader reader = new SAXReader();
164 Document document = reader.read(stream);
165 Element rootElement = document.getRootElement();
166
167
168 currentArea = rootElement.attributeValue("area");
169
170
171 Element pluginsElement = rootElement.element(ELEMENT_PLUG_INS);
172 if (pluginsElement != null)
173 {
174
175 parsedEvaluators = parseEvaluatorsElement(pluginsElement.element(ELEMENT_EVALUATORS));
176
177
178 parsedElementReaders = parseElementReadersElement(pluginsElement.element(ELEMENT_ELEMENT_READERS));
179 }
180
181
182 @SuppressWarnings("unchecked")
183 Iterator<Element> configElements = rootElement.elementIterator(ELEMENT_CONFIG);
184 while (configElements.hasNext())
185 {
186 Element configElement = configElements.next();
187 parsedConfigSections.add(parseConfigElement(parsedElementReaders, configElement, currentArea));
188 }
189 }
190 catch (Throwable e)
191 {
192 if (e instanceof ConfigException)
193 {
194 throw (ConfigException)e;
195 }
196 else
197 {
198 throw new ConfigException("Failed to parse config stream", e);
199 }
200 }
201
202 try
203 {
204
205
206 if (parsedEvaluators != null)
207 {
208 for (Map.Entry<String, Evaluator> entry : parsedEvaluators.entrySet())
209 {
210
211 addEvaluator(entry.getKey(), entry.getValue());
212 }
213 }
214
215 if (parsedElementReaders != null)
216 {
217 for (Map.Entry<String, ConfigElementReader> entry : parsedElementReaders.entrySet())
218 {
219
220 addConfigElementReader(entry.getKey(), entry.getValue());
221 }
222 }
223
224 if (parsedConfigSections != null)
225 {
226 for (ConfigSection section : parsedConfigSections)
227 {
228
229 addConfigSection(section, currentArea);
230 }
231 }
232 }
233 catch (Throwable e)
234 {
235 throw new ConfigException("Failed to add config to config service", e);
236 }
237 }
238
239
240
241
242
243
244
245 private Map<String, Evaluator> parseEvaluatorsElement(Element evaluatorsElement)
246 {
247 if (evaluatorsElement != null)
248 {
249 Map<String, Evaluator> parsedEvaluators = new HashMap<String, Evaluator>();
250 @SuppressWarnings("unchecked")
251 Iterator<Element> evaluators = evaluatorsElement.elementIterator();
252 while (evaluators.hasNext())
253 {
254 Element evaluatorElement = evaluators.next();
255 String evaluatorName = evaluatorElement.attributeValue(ATTR_ID);
256 String evaluatorClass = evaluatorElement.attributeValue(ATTR_CLASS);
257
258
259
260 if (evaluatorName == null || evaluatorName.length() == 0)
261 {
262 throw new ConfigException("All evaluator elements must define an id attribute");
263 }
264
265 if (evaluatorClass == null || evaluatorClass.length() == 0)
266 {
267 throw new ConfigException("Evaluator '" + evaluatorName + "' must define a class attribute");
268 }
269
270
271 parsedEvaluators.put(evaluatorName, createEvaluator(evaluatorName, evaluatorClass));
272 }
273
274 return parsedEvaluators;
275 }
276
277 return null;
278 }
279
280
281
282
283
284
285 private Map<String, ConfigElementReader> parseElementReadersElement(Element readersElement)
286 {
287 if (readersElement != null)
288 {
289 Map<String, ConfigElementReader> parsedElementReaders = new HashMap<String, ConfigElementReader>();
290 @SuppressWarnings("unchecked")
291 Iterator<Element> readers = readersElement.elementIterator();
292 while (readers.hasNext())
293 {
294 Element readerElement = readers.next();
295 String readerElementName = readerElement.attributeValue(ATTR_ELEMENT_NAME);
296 String readerElementClass = readerElement.attributeValue(ATTR_CLASS);
297
298 if (readerElementName == null || readerElementName.length() == 0)
299 {
300 throw new ConfigException("All element-reader elements must define an element-name attribute");
301 }
302
303 if (readerElementClass == null || readerElementClass.length() == 0)
304 {
305 throw new ConfigException("Element-reader '" + readerElementName
306 + "' must define a class attribute");
307 }
308
309
310 parsedElementReaders.put(readerElementName, createConfigElementReader(readerElementName, readerElementClass));
311 }
312
313 return parsedElementReaders;
314 }
315
316 return null;
317 }
318
319
320
321
322
323
324
325 private ConfigSection parseConfigElement(Map<String, ConfigElementReader> parsedElementReaders, Element configElement, String currentArea)
326 {
327 if (configElement != null)
328 {
329 boolean replace = false;
330 String evaluatorName = configElement.attributeValue(ATTR_EVALUATOR);
331 String condition = configElement.attributeValue(ATTR_CONDITION);
332 String replaceValue = configElement.attributeValue(ATTR_REPLACE);
333 if (replaceValue != null && replaceValue.equalsIgnoreCase("true"))
334 {
335 replace = true;
336 }
337
338
339 ConfigSectionImpl section = new ConfigSectionImpl(evaluatorName, condition, replace);
340
341
342 @SuppressWarnings("unchecked")
343 Iterator<Element> children = configElement.elementIterator();
344 while (children.hasNext())
345 {
346 Element child = children.next();
347 String elementName = child.getName();
348
349
350 ConfigElementReader elementReader = null;
351 if (parsedElementReaders != null)
352 {
353 elementReader = parsedElementReaders.get(elementName);
354 }
355
356 if (elementReader == null)
357 {
358 elementReader = getConfigElementReader(elementName);
359 }
360
361 if (logger.isDebugEnabled())
362 logger.debug("Retrieved element reader " + elementReader + " for element named '" + elementName
363 + "'");
364
365 if (elementReader == null)
366 {
367 elementReader = new GenericElementReader(propertyConfigurer);
368
369 if (logger.isDebugEnabled())
370 logger.debug("Defaulting to " + elementReader + " as there wasn't an element "
371 + "reader registered for element '" + elementName + "'");
372 }
373
374 ConfigElement cfgElement = elementReader.parse(child);
375 section.addConfigElement(cfgElement);
376
377 if (logger.isDebugEnabled())
378 logger.debug("Added " + cfgElement + " to " + section);
379 }
380
381 return section;
382 }
383
384 return null;
385 }
386
387
388
389
390
391
392
393
394
395 private void addConfigElementReader(String elementName, ConfigElementReader elementReader)
396 {
397 putConfigElementReader(elementName, elementReader);
398
399 if (logger.isDebugEnabled())
400 logger.debug("Added element reader '" + elementName + "': " + elementReader.getClass().getName());
401 }
402
403
404
405
406
407
408
409
410
411 private ConfigElementReader createConfigElementReader(String elementName, String className)
412 {
413 ConfigElementReader elementReader = null;
414
415 try
416 {
417 @SuppressWarnings("unchecked")
418 Class clazz = Class.forName(className);
419 elementReader = (ConfigElementReader) clazz.newInstance();
420 }
421 catch (Throwable e)
422 {
423 throw new ConfigException("Could not instantiate element reader for '" + elementName + "' with class: "
424 + className, e);
425
426 }
427
428 return elementReader;
429 }
430
431
432
433
434
435
436
437 private ConfigElementReader getConfigElementReader(String elementName)
438 {
439 return (ConfigElementReader) getElementReaders().get(elementName);
440 }
441
442
443
444
445
446
447
448 private void putConfigElementReader(String elementName, ConfigElementReader elementReader)
449 {
450 getElementReaders().put(elementName, elementReader);
451 }
452
453
454
455
456
457
458 protected Map<String, ConfigElementReader> getElementReaders()
459 {
460 return elementReaders;
461 }
462
463
464
465
466
467
468 protected void putElementReaders(Map<String, ConfigElementReader> elementReaders)
469 {
470 this.elementReaders = elementReaders;
471 }
472
473
474
475
476 protected void removeElementReaders()
477 {
478 elementReaders.clear();
479 elementReaders = null;
480 }
481
482
483
484
485 public static class PropertyConfigurer extends PropertyPlaceholderConfigurer
486 {
487 private PlaceholderResolvingStringValueResolver resolver;
488
489
490
491
492
493 {
494 try
495 {
496 Properties properties = mergeProperties();
497 this.resolver = new PlaceholderResolvingStringValueResolver(properties, DEFAULT_PLACEHOLDER_PREFIX, DEFAULT_PLACEHOLDER_SUFFIX, DEFAULT_VALUE_SEPARATOR, true);
498 }
499 catch(IOException e)
500 {
501 throw new ConfigException("Failed to retrieve properties", e);
502 }
503 }
504
505
506
507
508
509
510
511 public String resolveValue(String val)
512 {
513 return resolver.resolveStringValue(val);
514 }
515 }
516
517
518
519
520
521
522 public static class PlaceholderResolvingStringValueResolver implements StringValueResolver
523 {
524 private final PropertyPlaceholderHelper helper;
525 private final Properties props;
526
527 public PlaceholderResolvingStringValueResolver(Properties props, String placeholderPrefix, String placeholderSuffix, String valueSeparator, boolean ignoreUnresolvablePlaceholders)
528 {
529 this.helper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
530 this.props = props;
531 }
532
533 public String resolveStringValue(String strVal) throws BeansException
534 {
535 String value = this.helper.replacePlaceholders(strVal, props);
536 return value;
537 }
538 }
539 }