1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration;
18
19 import java.io.File;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.io.Reader;
23 import java.io.Writer;
24 import java.math.BigDecimal;
25 import java.math.BigInteger;
26 import java.net.URL;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Properties;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.ConcurrentMap;
33
34 import org.apache.commons.beanutils.BeanUtils;
35 import org.apache.commons.configuration.event.ConfigurationErrorEvent;
36 import org.apache.commons.configuration.event.ConfigurationErrorListener;
37 import org.apache.commons.configuration.event.ConfigurationEvent;
38 import org.apache.commons.configuration.event.ConfigurationListener;
39 import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
40 import org.apache.commons.configuration.reloading.ReloadingStrategy;
41 import org.apache.commons.configuration.resolver.EntityResolverSupport;
42 import org.apache.commons.configuration.tree.ConfigurationNode;
43 import org.apache.commons.configuration.tree.ExpressionEngine;
44 import org.apache.commons.lang.text.StrSubstitutor;
45 import org.apache.commons.logging.Log;
46 import org.apache.commons.logging.LogFactory;
47 import org.xml.sax.EntityResolver;
48 import org.xml.sax.SAXParseException;
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class MultiFileHierarchicalConfiguration extends AbstractHierarchicalFileConfiguration
63 implements ConfigurationListener, ConfigurationErrorListener, EntityResolverSupport
64 {
65
66
67
68 private static ThreadLocal<Boolean> recursive = new ThreadLocal<Boolean>()
69 {
70 @Override
71 protected synchronized Boolean initialValue()
72 {
73 return Boolean.FALSE;
74 }
75 };
76
77
78 private final ConcurrentMap<String, XMLConfiguration> configurationsMap =
79 new ConcurrentHashMap<String, XMLConfiguration>();
80
81
82 private String pattern;
83
84
85 private boolean init;
86
87
88 private boolean ignoreException = true;
89
90
91 private boolean schemaValidation;
92
93
94 private boolean validating;
95
96
97 private boolean attributeSplittingDisabled;
98
99
100 private String loggerName = MultiFileHierarchicalConfiguration.class.getName();
101
102
103 private ReloadingStrategy fileStrategy;
104
105
106 private EntityResolver entityResolver;
107
108
109 private StrSubstitutor localSubst = new StrSubstitutor(new ConfigurationInterpolator());
110
111
112
113
114 public MultiFileHierarchicalConfiguration()
115 {
116 super();
117 this.init = true;
118 setLogger(LogFactory.getLog(loggerName));
119 }
120
121
122
123
124
125 public MultiFileHierarchicalConfiguration(String pathPattern)
126 {
127 super();
128 this.pattern = pathPattern;
129 this.init = true;
130 setLogger(LogFactory.getLog(loggerName));
131 }
132
133 public void setLoggerName(String name)
134 {
135 this.loggerName = name;
136 }
137
138
139
140
141
142 public void setFilePattern(String pathPattern)
143 {
144 this.pattern = pathPattern;
145 }
146
147 public boolean isSchemaValidation()
148 {
149 return schemaValidation;
150 }
151
152 public void setSchemaValidation(boolean schemaValidation)
153 {
154 this.schemaValidation = schemaValidation;
155 }
156
157 public boolean isValidating()
158 {
159 return validating;
160 }
161
162 public void setValidating(boolean validating)
163 {
164 this.validating = validating;
165 }
166
167 public boolean isAttributeSplittingDisabled()
168 {
169 return attributeSplittingDisabled;
170 }
171
172 public void setAttributeSplittingDisabled(boolean attributeSplittingDisabled)
173 {
174 this.attributeSplittingDisabled = attributeSplittingDisabled;
175 }
176
177 @Override
178 public ReloadingStrategy getReloadingStrategy()
179 {
180 return fileStrategy;
181 }
182
183 @Override
184 public void setReloadingStrategy(ReloadingStrategy strategy)
185 {
186 this.fileStrategy = strategy;
187 }
188
189 public void setEntityResolver(EntityResolver entityResolver)
190 {
191 this.entityResolver = entityResolver;
192 }
193
194 public EntityResolver getEntityResolver()
195 {
196 return this.entityResolver;
197 }
198
199
200
201
202
203
204 public void setIgnoreException(boolean ignoreException)
205 {
206 this.ignoreException = ignoreException;
207 }
208
209 @Override
210 public void addProperty(String key, Object value)
211 {
212 this.getConfiguration().addProperty(key, value);
213 }
214
215 @Override
216 public void clear()
217 {
218 this.getConfiguration().clear();
219 }
220
221 @Override
222 public void clearProperty(String key)
223 {
224 this.getConfiguration().clearProperty(key);
225 }
226
227 @Override
228 public boolean containsKey(String key)
229 {
230 return this.getConfiguration().containsKey(key);
231 }
232
233 @Override
234 public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
235 {
236 return this.getConfiguration().getBigDecimal(key, defaultValue);
237 }
238
239 @Override
240 public BigDecimal getBigDecimal(String key)
241 {
242 return this.getConfiguration().getBigDecimal(key);
243 }
244
245 @Override
246 public BigInteger getBigInteger(String key, BigInteger defaultValue)
247 {
248 return this.getConfiguration().getBigInteger(key, defaultValue);
249 }
250
251 @Override
252 public BigInteger getBigInteger(String key)
253 {
254 return this.getConfiguration().getBigInteger(key);
255 }
256
257 @Override
258 public boolean getBoolean(String key, boolean defaultValue)
259 {
260 return this.getConfiguration().getBoolean(key, defaultValue);
261 }
262
263 @Override
264 public Boolean getBoolean(String key, Boolean defaultValue)
265 {
266 return this.getConfiguration().getBoolean(key, defaultValue);
267 }
268
269 @Override
270 public boolean getBoolean(String key)
271 {
272 return this.getConfiguration().getBoolean(key);
273 }
274
275 @Override
276 public byte getByte(String key, byte defaultValue)
277 {
278 return this.getConfiguration().getByte(key, defaultValue);
279 }
280
281 @Override
282 public Byte getByte(String key, Byte defaultValue)
283 {
284 return this.getConfiguration().getByte(key, defaultValue);
285 }
286
287 @Override
288 public byte getByte(String key)
289 {
290 return this.getConfiguration().getByte(key);
291 }
292
293 @Override
294 public double getDouble(String key, double defaultValue)
295 {
296 return this.getConfiguration().getDouble(key, defaultValue);
297 }
298
299 @Override
300 public Double getDouble(String key, Double defaultValue)
301 {
302 return this.getConfiguration().getDouble(key, defaultValue);
303 }
304
305 @Override
306 public double getDouble(String key)
307 {
308 return this.getConfiguration().getDouble(key);
309 }
310
311 @Override
312 public float getFloat(String key, float defaultValue)
313 {
314 return this.getConfiguration().getFloat(key, defaultValue);
315 }
316
317 @Override
318 public Float getFloat(String key, Float defaultValue)
319 {
320 return this.getConfiguration().getFloat(key, defaultValue);
321 }
322
323 @Override
324 public float getFloat(String key)
325 {
326 return this.getConfiguration().getFloat(key);
327 }
328
329 @Override
330 public int getInt(String key, int defaultValue)
331 {
332 return this.getConfiguration().getInt(key, defaultValue);
333 }
334
335 @Override
336 public int getInt(String key)
337 {
338 return this.getConfiguration().getInt(key);
339 }
340
341 @Override
342 public Integer getInteger(String key, Integer defaultValue)
343 {
344 return this.getConfiguration().getInteger(key, defaultValue);
345 }
346
347 @Override
348 public Iterator<String> getKeys()
349 {
350 return this.getConfiguration().getKeys();
351 }
352
353 @Override
354 public Iterator<String> getKeys(String prefix)
355 {
356 return this.getConfiguration().getKeys(prefix);
357 }
358
359 @Override
360 public List<Object> getList(String key, List<Object> defaultValue)
361 {
362 return this.getConfiguration().getList(key, defaultValue);
363 }
364
365 @Override
366 public List<Object> getList(String key)
367 {
368 return this.getConfiguration().getList(key);
369 }
370
371 @Override
372 public long getLong(String key, long defaultValue)
373 {
374 return this.getConfiguration().getLong(key, defaultValue);
375 }
376
377 @Override
378 public Long getLong(String key, Long defaultValue)
379 {
380 return this.getConfiguration().getLong(key, defaultValue);
381 }
382
383 @Override
384 public long getLong(String key)
385 {
386 return this.getConfiguration().getLong(key);
387 }
388
389 @Override
390 public Properties getProperties(String key)
391 {
392 return this.getConfiguration().getProperties(key);
393 }
394
395 @Override
396 public Object getProperty(String key)
397 {
398 return this.getConfiguration().getProperty(key);
399 }
400
401 @Override
402 public short getShort(String key, short defaultValue)
403 {
404 return this.getConfiguration().getShort(key, defaultValue);
405 }
406
407 @Override
408 public Short getShort(String key, Short defaultValue)
409 {
410 return this.getConfiguration().getShort(key, defaultValue);
411 }
412
413 @Override
414 public short getShort(String key)
415 {
416 return this.getConfiguration().getShort(key);
417 }
418
419 @Override
420 public String getString(String key, String defaultValue)
421 {
422 return this.getConfiguration().getString(key, defaultValue);
423 }
424
425 @Override
426 public String getString(String key)
427 {
428 return this.getConfiguration().getString(key);
429 }
430
431 @Override
432 public String[] getStringArray(String key)
433 {
434 return this.getConfiguration().getStringArray(key);
435 }
436
437 @Override
438 public boolean isEmpty()
439 {
440 return this.getConfiguration().isEmpty();
441 }
442
443 @Override
444 public void setProperty(String key, Object value)
445 {
446 if (init)
447 {
448 this.getConfiguration().setProperty(key, value);
449 }
450 }
451
452 @Override
453 public Configuration subset(String prefix)
454 {
455 return this.getConfiguration().subset(prefix);
456 }
457
458 @Override
459 public Object getReloadLock()
460 {
461 return this.getConfiguration().getReloadLock();
462 }
463
464 @Override
465 public Node getRoot()
466 {
467 return this.getConfiguration().getRoot();
468 }
469
470 @Override
471 public void setRoot(Node node)
472 {
473 if (init)
474 {
475 this.getConfiguration().setRoot(node);
476 }
477 else
478 {
479 super.setRoot(node);
480 }
481 }
482
483 @Override
484 public ConfigurationNode getRootNode()
485 {
486 return this.getConfiguration().getRootNode();
487 }
488
489 @Override
490 public void setRootNode(ConfigurationNode rootNode)
491 {
492 if (init)
493 {
494 this.getConfiguration().setRootNode(rootNode);
495 }
496 else
497 {
498 super.setRootNode(rootNode);
499 }
500 }
501
502 @Override
503 public ExpressionEngine getExpressionEngine()
504 {
505 return super.getExpressionEngine();
506 }
507
508 @Override
509 public void setExpressionEngine(ExpressionEngine expressionEngine)
510 {
511 super.setExpressionEngine(expressionEngine);
512 }
513
514 @Override
515 public void addNodes(String key, Collection<? extends ConfigurationNode> nodes)
516 {
517 this.getConfiguration().addNodes(key, nodes);
518 }
519
520 @Override
521 public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
522 {
523 return this.getConfiguration().configurationAt(key, supportUpdates);
524 }
525
526 @Override
527 public SubnodeConfiguration configurationAt(String key)
528 {
529 return this.getConfiguration().configurationAt(key);
530 }
531
532 @Override
533 public List<HierarchicalConfiguration> configurationsAt(String key)
534 {
535 return this.getConfiguration().configurationsAt(key);
536 }
537
538 @Override
539 public void clearTree(String key)
540 {
541 this.getConfiguration().clearTree(key);
542 }
543
544 @Override
545 public int getMaxIndex(String key)
546 {
547 return this.getConfiguration().getMaxIndex(key);
548 }
549
550 @Override
551 public Configuration interpolatedConfiguration()
552 {
553 return this.getConfiguration().interpolatedConfiguration();
554 }
555
556 @Override
557 public void addConfigurationListener(ConfigurationListener l)
558 {
559 super.addConfigurationListener(l);
560 }
561
562 @Override
563 public boolean removeConfigurationListener(ConfigurationListener l)
564 {
565 return super.removeConfigurationListener(l);
566 }
567
568 @Override
569 public Collection<ConfigurationListener> getConfigurationListeners()
570 {
571 return super.getConfigurationListeners();
572 }
573
574 @Override
575 public void clearConfigurationListeners()
576 {
577 super.clearConfigurationListeners();
578 }
579
580 @Override
581 public void addErrorListener(ConfigurationErrorListener l)
582 {
583 super.addErrorListener(l);
584 }
585
586 @Override
587 public boolean removeErrorListener(ConfigurationErrorListener l)
588 {
589 return super.removeErrorListener(l);
590 }
591
592 @Override
593 public void clearErrorListeners()
594 {
595 super.clearErrorListeners();
596 }
597
598 @Override
599 public Collection<ConfigurationErrorListener> getErrorListeners()
600 {
601 return super.getErrorListeners();
602 }
603
604 public void save(Writer writer) throws ConfigurationException
605 {
606 if (init)
607 {
608 this.getConfiguration().save(writer);
609 }
610 }
611
612 public void load(Reader reader) throws ConfigurationException
613 {
614 if (init)
615 {
616 this.getConfiguration().load(reader);
617 }
618 }
619
620 @Override
621 public void load() throws ConfigurationException
622 {
623 this.getConfiguration();
624 }
625
626 @Override
627 public void load(String fileName) throws ConfigurationException
628 {
629 this.getConfiguration().load(fileName);
630 }
631
632 @Override
633 public void load(File file) throws ConfigurationException
634 {
635 this.getConfiguration().load(file);
636 }
637
638 @Override
639 public void load(URL url) throws ConfigurationException
640 {
641 this.getConfiguration().load(url);
642 }
643
644 @Override
645 public void load(InputStream in) throws ConfigurationException
646 {
647 this.getConfiguration().load(in);
648 }
649
650 @Override
651 public void load(InputStream in, String encoding) throws ConfigurationException
652 {
653 this.getConfiguration().load(in, encoding);
654 }
655
656 @Override
657 public void save() throws ConfigurationException
658 {
659 this.getConfiguration().save();
660 }
661
662 @Override
663 public void save(String fileName) throws ConfigurationException
664 {
665 this.getConfiguration().save(fileName);
666 }
667
668 @Override
669 public void save(File file) throws ConfigurationException
670 {
671 this.getConfiguration().save(file);
672 }
673
674 @Override
675 public void save(URL url) throws ConfigurationException
676 {
677 this.getConfiguration().save(url);
678 }
679
680 @Override
681 public void save(OutputStream out) throws ConfigurationException
682 {
683 this.getConfiguration().save(out);
684 }
685
686 @Override
687 public void save(OutputStream out, String encoding) throws ConfigurationException
688 {
689 this.getConfiguration().save(out, encoding);
690 }
691
692 @Override
693 public void configurationChanged(ConfigurationEvent event)
694 {
695 if (event.getSource() instanceof XMLConfiguration)
696 {
697 for (ConfigurationListener listener : getConfigurationListeners())
698 {
699 listener.configurationChanged(event);
700 }
701 }
702 }
703
704 @Override
705 public void configurationError(ConfigurationErrorEvent event)
706 {
707 if (event.getSource() instanceof XMLConfiguration)
708 {
709 for (ConfigurationErrorListener listener : getErrorListeners())
710 {
711 listener.configurationError(event);
712 }
713 }
714
715 if (event.getType() == AbstractFileConfiguration.EVENT_RELOAD)
716 {
717 if (isThrowable(event.getCause()))
718 {
719 throw new ConfigurationRuntimeException(event.getCause());
720 }
721 }
722 }
723
724
725
726
727
728
729 @Override
730 protected Object resolveContainerStore(String key)
731 {
732 if (recursive.get().booleanValue())
733 {
734 return null;
735 }
736 recursive.set(Boolean.TRUE);
737 try
738 {
739 return super.resolveContainerStore(key);
740 }
741 finally
742 {
743 recursive.set(Boolean.FALSE);
744 }
745 }
746
747
748
749
750 public void removeConfiguration()
751 {
752 String path = getSubstitutor().replace(pattern);
753 configurationsMap.remove(path);
754 }
755
756
757
758
759
760
761
762 private AbstractHierarchicalFileConfiguration getConfiguration()
763 {
764 if (pattern == null)
765 {
766 throw new ConfigurationRuntimeException("File pattern must be defined");
767 }
768 String path = localSubst.replace(pattern);
769
770 if (configurationsMap.containsKey(path))
771 {
772 return configurationsMap.get(path);
773 }
774
775 if (path.equals(pattern))
776 {
777 XMLConfiguration configuration = new XMLConfiguration()
778 {
779 @Override
780 public void load() throws ConfigurationException
781 {
782 }
783 @Override
784 public void save() throws ConfigurationException
785 {
786 }
787 };
788
789 configurationsMap.putIfAbsent(pattern, configuration);
790
791 return configuration;
792 }
793
794 XMLConfiguration configuration = new XMLConfiguration();
795 if (loggerName != null)
796 {
797 Log log = LogFactory.getLog(loggerName);
798 if (log != null)
799 {
800 configuration.setLogger(log);
801 }
802 }
803 configuration.setBasePath(getBasePath());
804 configuration.setFileName(path);
805 configuration.setFileSystem(getFileSystem());
806 configuration.setExpressionEngine(getExpressionEngine());
807 ReloadingStrategy strategy = createReloadingStrategy();
808 if (strategy != null)
809 {
810 configuration.setReloadingStrategy(strategy);
811 }
812 configuration.setDelimiterParsingDisabled(isDelimiterParsingDisabled());
813 configuration.setAttributeSplittingDisabled(isAttributeSplittingDisabled());
814 configuration.setValidating(validating);
815 configuration.setSchemaValidation(schemaValidation);
816 configuration.setEntityResolver(entityResolver);
817 configuration.setListDelimiter(getListDelimiter());
818 configuration.addConfigurationListener(this);
819 configuration.addErrorListener(this);
820 try
821 {
822 configuration.load();
823 }
824 catch (ConfigurationException ce)
825 {
826 if (isThrowable(ce))
827 {
828 throw new ConfigurationRuntimeException(ce);
829 }
830 }
831 configurationsMap.putIfAbsent(path, configuration);
832 return configurationsMap.get(path);
833 }
834
835 private boolean isThrowable(Throwable throwable)
836 {
837 if (!ignoreException)
838 {
839 return true;
840 }
841 Throwable cause = throwable.getCause();
842 while (cause != null && !(cause instanceof SAXParseException))
843 {
844 cause = cause.getCause();
845 }
846 return cause != null;
847 }
848
849
850
851
852
853 private ReloadingStrategy createReloadingStrategy()
854 {
855 if (fileStrategy == null)
856 {
857 return null;
858 }
859 try
860 {
861 ReloadingStrategy strategy = (ReloadingStrategy) BeanUtils.cloneBean(fileStrategy);
862 strategy.setConfiguration(null);
863 return strategy;
864 }
865 catch (Exception ex)
866 {
867 return null;
868 }
869 }
870
871 }