View Javadoc

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  package org.apache.commons.configuration;
18  
19  import java.io.Reader;
20  import java.io.Writer;
21  import java.math.BigDecimal;
22  import java.math.BigInteger;
23  import java.util.Collection;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Properties;
27  
28  import org.apache.commons.configuration.event.ConfigurationErrorListener;
29  import org.apache.commons.configuration.event.ConfigurationListener;
30  import org.apache.commons.configuration.tree.ConfigurationNode;
31  import org.apache.commons.configuration.tree.ExpressionEngine;
32  
33  /**
34   * Wraps a HierarchicalConfiguration and allows subtrees to be access via a configured path with
35   * replaceable tokens derived from the ConfigurationInterpolator. When used with injection frameworks
36   * such as Spring it allows components to be injected with subtrees of the configuration.
37   * @since 1.6
38   * @author <a
39   * href="http://commons.apache.org/configuration/team-list.html">Commons
40   * Configuration team</a>
41   * @version $Id: PatternSubtreeConfigurationWrapper.java 1210175 2011-12-04 18:49:51Z oheger $
42   */
43  public class PatternSubtreeConfigurationWrapper extends AbstractHierarchicalFileConfiguration
44  {
45      /**
46       * Prevent recursion while resolving unprefixed properties.
47       */
48      private static ThreadLocal<Boolean> recursive = new ThreadLocal<Boolean>()
49      {
50          @Override
51          protected synchronized Boolean initialValue()
52          {
53              return Boolean.FALSE;
54          }
55      };
56  
57      /** The wrapped configuration */
58      private final AbstractHierarchicalFileConfiguration config;
59  
60      /** The path to the subtree */
61      private final String path;
62  
63      /** True if the path ends with '/', false otherwise */
64      private final boolean trailing;
65  
66      /** True if the constructor has finished */
67      private boolean init;
68  
69      /**
70       * Constructor
71       * @param config The Configuration to be wrapped.
72       * @param path The base path pattern.
73       */
74      public PatternSubtreeConfigurationWrapper(AbstractHierarchicalFileConfiguration config, String path)
75      {
76          this.config = config;
77          this.path = path;
78          this.trailing = path.endsWith("/");
79          this.init = true;
80      }
81  
82      @Override
83      public Object getReloadLock()
84      {
85          return config.getReloadLock();
86      }
87  
88      @Override
89      public void addProperty(String key, Object value)
90      {
91          config.addProperty(makePath(key), value);
92      }
93  
94      @Override
95      public void clear()
96      {
97          getConfig().clear();
98      }
99  
100     @Override
101     public void clearProperty(String key)
102     {
103         config.clearProperty(makePath(key));
104     }
105 
106     @Override
107     public boolean containsKey(String key)
108     {
109         return config.containsKey(makePath(key));
110     }
111 
112     @Override
113     public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
114     {
115         return config.getBigDecimal(makePath(key), defaultValue);
116     }
117 
118     @Override
119     public BigDecimal getBigDecimal(String key)
120     {
121         return config.getBigDecimal(makePath(key));
122     }
123 
124     @Override
125     public BigInteger getBigInteger(String key, BigInteger defaultValue)
126     {
127         return config.getBigInteger(makePath(key), defaultValue);
128     }
129 
130     @Override
131     public BigInteger getBigInteger(String key)
132     {
133         return config.getBigInteger(makePath(key));
134     }
135 
136     @Override
137     public boolean getBoolean(String key, boolean defaultValue)
138     {
139         return config.getBoolean(makePath(key), defaultValue);
140     }
141 
142     @Override
143     public Boolean getBoolean(String key, Boolean defaultValue)
144     {
145         return config.getBoolean(makePath(key), defaultValue);
146     }
147 
148     @Override
149     public boolean getBoolean(String key)
150     {
151         return config.getBoolean(makePath(key));
152     }
153 
154     @Override
155     public byte getByte(String key, byte defaultValue)
156     {
157         return config.getByte(makePath(key), defaultValue);
158     }
159 
160     @Override
161     public Byte getByte(String key, Byte defaultValue)
162     {
163         return config.getByte(makePath(key), defaultValue);
164     }
165 
166     @Override
167     public byte getByte(String key)
168     {
169         return config.getByte(makePath(key));
170     }
171 
172     @Override
173     public double getDouble(String key, double defaultValue)
174     {
175         return config.getDouble(makePath(key), defaultValue);
176     }
177 
178     @Override
179     public Double getDouble(String key, Double defaultValue)
180     {
181         return config.getDouble(makePath(key), defaultValue);
182     }
183 
184     @Override
185     public double getDouble(String key)
186     {
187         return config.getDouble(makePath(key));
188     }
189 
190     @Override
191     public float getFloat(String key, float defaultValue)
192     {
193         return config.getFloat(makePath(key), defaultValue);
194     }
195 
196     @Override
197     public Float getFloat(String key, Float defaultValue)
198     {
199         return config.getFloat(makePath(key), defaultValue);
200     }
201 
202     @Override
203     public float getFloat(String key)
204     {
205         return config.getFloat(makePath(key));
206     }
207 
208     @Override
209     public int getInt(String key, int defaultValue)
210     {
211         return config.getInt(makePath(key), defaultValue);
212     }
213 
214     @Override
215     public int getInt(String key)
216     {
217         return config.getInt(makePath(key));
218     }
219 
220     @Override
221     public Integer getInteger(String key, Integer defaultValue)
222     {
223         return config.getInteger(makePath(key), defaultValue);
224     }
225 
226     @Override
227     public Iterator<String> getKeys()
228     {
229         return config.getKeys(makePath());
230     }
231 
232     @Override
233     public Iterator<String> getKeys(String prefix)
234     {
235         return config.getKeys(makePath(prefix));
236     }
237 
238     @Override
239     public List<Object> getList(String key, List<Object> defaultValue)
240     {
241         return config.getList(makePath(key), defaultValue);
242     }
243 
244     @Override
245     public List<Object> getList(String key)
246     {
247         return config.getList(makePath(key));
248     }
249 
250     @Override
251     public long getLong(String key, long defaultValue)
252     {
253         return config.getLong(makePath(key), defaultValue);
254     }
255 
256     @Override
257     public Long getLong(String key, Long defaultValue)
258     {
259         return config.getLong(makePath(key), defaultValue);
260     }
261 
262     @Override
263     public long getLong(String key)
264     {
265         return config.getLong(makePath(key));
266     }
267 
268     @Override
269     public Properties getProperties(String key)
270     {
271         return config.getProperties(makePath(key));
272     }
273 
274     @Override
275     public Object getProperty(String key)
276     {
277         return config.getProperty(makePath(key));
278     }
279 
280     @Override
281     public short getShort(String key, short defaultValue)
282     {
283         return config.getShort(makePath(key), defaultValue);
284     }
285 
286     @Override
287     public Short getShort(String key, Short defaultValue)
288     {
289         return config.getShort(makePath(key), defaultValue);
290     }
291 
292     @Override
293     public short getShort(String key)
294     {
295         return config.getShort(makePath(key));
296     }
297 
298     @Override
299     public String getString(String key, String defaultValue)
300     {
301         return config.getString(makePath(key), defaultValue);
302     }
303 
304     @Override
305     public String getString(String key)
306     {
307         return config.getString(makePath(key));
308     }
309 
310     @Override
311     public String[] getStringArray(String key)
312     {
313         return config.getStringArray(makePath(key));
314     }
315 
316     @Override
317     public boolean isEmpty()
318     {
319         return getConfig().isEmpty();
320     }
321 
322     @Override
323     public void setProperty(String key, Object value)
324     {
325         getConfig().setProperty(key, value);
326     }
327 
328     @Override
329     public Configuration subset(String prefix)
330     {
331         return getConfig().subset(prefix);
332     }
333 
334     @Override
335     public Node getRoot()
336     {
337         return getConfig().getRoot();
338     }
339 
340     @Override
341     public void setRoot(Node node)
342     {
343         if (init)
344         {
345             getConfig().setRoot(node);
346         }
347         else
348         {
349             super.setRoot(node);
350         }
351     }
352 
353     @Override
354     public ConfigurationNode getRootNode()
355     {
356         return getConfig().getRootNode();
357     }
358 
359     @Override
360     public void setRootNode(ConfigurationNode rootNode)
361     {
362         if (init)
363         {
364             getConfig().setRootNode(rootNode);
365         }
366         else
367         {
368             super.setRootNode(rootNode);
369         }
370     }
371 
372     @Override
373     public ExpressionEngine getExpressionEngine()
374     {
375         return config.getExpressionEngine();
376     }
377 
378     @Override
379     public void setExpressionEngine(ExpressionEngine expressionEngine)
380     {
381         if (init)
382         {
383             config.setExpressionEngine(expressionEngine);
384         }
385         else
386         {
387             super.setExpressionEngine(expressionEngine);
388         }
389     }
390 
391     @Override
392     public void addNodes(String key, Collection<? extends ConfigurationNode> nodes)
393     {
394         getConfig().addNodes(key, nodes);
395     }
396 
397     @Override
398     public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
399     {
400         return config.configurationAt(makePath(key), supportUpdates);
401     }
402 
403     @Override
404     public SubnodeConfiguration configurationAt(String key)
405     {
406         return config.configurationAt(makePath(key));
407     }
408 
409     @Override
410     public List<HierarchicalConfiguration> configurationsAt(String key)
411     {
412         return config.configurationsAt(makePath(key));
413     }
414 
415     @Override
416     public void clearTree(String key)
417     {
418         config.clearTree(makePath(key));
419     }
420 
421     @Override
422     public int getMaxIndex(String key)
423     {
424         return config.getMaxIndex(makePath(key));
425     }
426 
427     @Override
428     public Configuration interpolatedConfiguration()
429     {
430         return getConfig().interpolatedConfiguration();
431     }
432 
433     @Override
434     public void addConfigurationListener(ConfigurationListener l)
435     {
436         getConfig().addConfigurationListener(l);
437     }
438 
439     @Override
440     public boolean removeConfigurationListener(ConfigurationListener l)
441     {
442         return getConfig().removeConfigurationListener(l);
443     }
444 
445     @Override
446     public Collection<ConfigurationListener> getConfigurationListeners()
447     {
448         return getConfig().getConfigurationListeners();
449     }
450 
451     @Override
452     public void clearConfigurationListeners()
453     {
454         getConfig().clearConfigurationListeners();
455     }
456 
457     @Override
458     public void addErrorListener(ConfigurationErrorListener l)
459     {
460         getConfig().addErrorListener(l);
461     }
462 
463     @Override
464     public boolean removeErrorListener(ConfigurationErrorListener l)
465     {
466         return getConfig().removeErrorListener(l);
467     }
468 
469     @Override
470     public void clearErrorListeners()
471     {
472         getConfig().clearErrorListeners();
473     }
474 
475     public void save(Writer writer) throws ConfigurationException
476     {
477         config.save(writer);
478     }
479 
480     public void load(Reader reader) throws ConfigurationException
481     {
482         config.load(reader);
483     }
484 
485     @Override
486     public Collection<ConfigurationErrorListener> getErrorListeners()
487     {
488         return getConfig().getErrorListeners();
489     }
490 
491     @Override
492     protected Object resolveContainerStore(String key)
493     {
494         if (recursive.get().booleanValue())
495         {
496             return null;
497         }
498         recursive.set(Boolean.TRUE);
499         try
500         {
501             return super.resolveContainerStore(key);
502         }
503         finally
504         {
505             recursive.set(Boolean.FALSE);
506         }
507     }
508 
509     private HierarchicalConfiguration getConfig()
510     {
511         return config.configurationAt(makePath());
512     }
513 
514     private String makePath()
515     {
516         String pathPattern = trailing ? path.substring(0, path.length() - 1) : path;
517         return getSubstitutor().replace(pathPattern);
518     }
519 
520     /*
521      * Resolve the root expression and then add the item being retrieved. Insert a
522      * separator character as required.
523      */
524     private String makePath(String item)
525     {
526         String pathPattern;
527         if ((item.length() == 0 || item.startsWith("/")) && trailing)
528         {
529             pathPattern = path.substring(0, path.length() - 1);
530         }
531         else  if (!item.startsWith("/") || !trailing)
532         {
533             pathPattern = path + "/";
534         }
535         else
536         {
537             pathPattern = path;
538         }
539         return getSubstitutor().replace(pathPattern) + item;
540     }
541 }