001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.configuration;
018
019 import java.io.Reader;
020 import java.io.Writer;
021 import java.math.BigDecimal;
022 import java.math.BigInteger;
023 import java.util.Collection;
024 import java.util.Iterator;
025 import java.util.List;
026 import java.util.Properties;
027
028 import org.apache.commons.configuration.event.ConfigurationErrorListener;
029 import org.apache.commons.configuration.event.ConfigurationListener;
030 import org.apache.commons.configuration.tree.ConfigurationNode;
031 import org.apache.commons.configuration.tree.ExpressionEngine;
032
033 /**
034 * Wraps a HierarchicalConfiguration and allows subtrees to be access via a configured path with
035 * replaceable tokens derived from the ConfigurationInterpolator. When used with injection frameworks
036 * such as Spring it allows components to be injected with subtrees of the configuration.
037 * @since 1.6
038 * @author <a
039 * href="http://commons.apache.org/configuration/team-list.html">Commons
040 * Configuration team</a>
041 * @version $Id: PatternSubtreeConfigurationWrapper.java 823891 2009-10-10 17:17:44Z rgoers $
042 */
043 public class PatternSubtreeConfigurationWrapper extends AbstractHierarchicalFileConfiguration
044 {
045 /**
046 * Prevent recursion while resolving unprefixed properties.
047 */
048 private static ThreadLocal recursive = new ThreadLocal()
049 {
050 protected synchronized Object initialValue()
051 {
052 return Boolean.FALSE;
053 }
054 };
055
056 /** The wrapped configuration */
057 private final AbstractHierarchicalFileConfiguration config;
058
059 /** The path to the subtree */
060 private final String path;
061
062 /** True if the path ends with '/', false otherwise */
063 private final boolean trailing;
064
065 /** True if the constructor has finished */
066 private boolean init;
067
068 /**
069 * Constructor
070 * @param config The Configuration to be wrapped.
071 * @param path The base path pattern.
072 */
073 public PatternSubtreeConfigurationWrapper(AbstractHierarchicalFileConfiguration config, String path)
074 {
075 this.config = config;
076 this.path = path;
077 this.trailing = path.endsWith("/");
078 this.init = true;
079 }
080
081 public Object getReloadLock()
082 {
083 return config.getReloadLock();
084 }
085
086 public void addProperty(String key, Object value)
087 {
088 config.addProperty(makePath(key), value);
089 }
090
091 public void clear()
092 {
093 getConfig().clear();
094 }
095
096 public void clearProperty(String key)
097 {
098 config.clearProperty(makePath(key));
099 }
100
101 public boolean containsKey(String key)
102 {
103 return config.containsKey(makePath(key));
104 }
105
106 public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
107 {
108 return config.getBigDecimal(makePath(key), defaultValue);
109 }
110
111 public BigDecimal getBigDecimal(String key)
112 {
113 return config.getBigDecimal(makePath(key));
114 }
115
116 public BigInteger getBigInteger(String key, BigInteger defaultValue)
117 {
118 return config.getBigInteger(makePath(key), defaultValue);
119 }
120
121 public BigInteger getBigInteger(String key)
122 {
123 return config.getBigInteger(makePath(key));
124 }
125
126 public boolean getBoolean(String key, boolean defaultValue)
127 {
128 return config.getBoolean(makePath(key), defaultValue);
129 }
130
131 public Boolean getBoolean(String key, Boolean defaultValue)
132 {
133 return config.getBoolean(makePath(key), defaultValue);
134 }
135
136 public boolean getBoolean(String key)
137 {
138 return config.getBoolean(makePath(key));
139 }
140
141 public byte getByte(String key, byte defaultValue)
142 {
143 return config.getByte(makePath(key), defaultValue);
144 }
145
146 public Byte getByte(String key, Byte defaultValue)
147 {
148 return config.getByte(makePath(key), defaultValue);
149 }
150
151 public byte getByte(String key)
152 {
153 return config.getByte(makePath(key));
154 }
155
156 public double getDouble(String key, double defaultValue)
157 {
158 return config.getDouble(makePath(key), defaultValue);
159 }
160
161 public Double getDouble(String key, Double defaultValue)
162 {
163 return config.getDouble(makePath(key), defaultValue);
164 }
165
166 public double getDouble(String key)
167 {
168 return config.getDouble(makePath(key));
169 }
170
171 public float getFloat(String key, float defaultValue)
172 {
173 return config.getFloat(makePath(key), defaultValue);
174 }
175
176 public Float getFloat(String key, Float defaultValue)
177 {
178 return config.getFloat(makePath(key), defaultValue);
179 }
180
181 public float getFloat(String key)
182 {
183 return config.getFloat(makePath(key));
184 }
185
186 public int getInt(String key, int defaultValue)
187 {
188 return config.getInt(makePath(key), defaultValue);
189 }
190
191 public int getInt(String key)
192 {
193 return config.getInt(makePath(key));
194 }
195
196 public Integer getInteger(String key, Integer defaultValue)
197 {
198 return config.getInteger(makePath(key), defaultValue);
199 }
200
201 public Iterator getKeys()
202 {
203 return config.getKeys(makePath());
204 }
205
206 public Iterator getKeys(String prefix)
207 {
208 return config.getKeys(makePath(prefix));
209 }
210
211 public List getList(String key, List defaultValue)
212 {
213 return config.getList(makePath(key), defaultValue);
214 }
215
216 public List getList(String key)
217 {
218 return config.getList(makePath(key));
219 }
220
221 public long getLong(String key, long defaultValue)
222 {
223 return config.getLong(makePath(key), defaultValue);
224 }
225
226 public Long getLong(String key, Long defaultValue)
227 {
228 return config.getLong(makePath(key), defaultValue);
229 }
230
231 public long getLong(String key)
232 {
233 return config.getLong(makePath(key));
234 }
235
236 public Properties getProperties(String key)
237 {
238 return config.getProperties(makePath(key));
239 }
240
241 public Object getProperty(String key)
242 {
243 return config.getProperty(makePath(key));
244 }
245
246 public short getShort(String key, short defaultValue)
247 {
248 return config.getShort(makePath(key), defaultValue);
249 }
250
251 public Short getShort(String key, Short defaultValue)
252 {
253 return config.getShort(makePath(key), defaultValue);
254 }
255
256 public short getShort(String key)
257 {
258 return config.getShort(makePath(key));
259 }
260
261 public String getString(String key, String defaultValue)
262 {
263 return config.getString(makePath(key), defaultValue);
264 }
265
266 public String getString(String key)
267 {
268 return config.getString(makePath(key));
269 }
270
271 public String[] getStringArray(String key)
272 {
273 return config.getStringArray(makePath(key));
274 }
275
276 public boolean isEmpty()
277 {
278 return getConfig().isEmpty();
279 }
280
281 public void setProperty(String key, Object value)
282 {
283 getConfig().setProperty(key, value);
284 }
285
286 public Configuration subset(String prefix)
287 {
288 return getConfig().subset(prefix);
289 }
290
291 public Node getRoot()
292 {
293 return getConfig().getRoot();
294 }
295
296 public void setRoot(Node node)
297 {
298 if (init)
299 {
300 getConfig().setRoot(node);
301 }
302 else
303 {
304 super.setRoot(node);
305 }
306 }
307
308 public ConfigurationNode getRootNode()
309 {
310 return getConfig().getRootNode();
311 }
312
313 public void setRootNode(ConfigurationNode rootNode)
314 {
315 if (init)
316 {
317 getConfig().setRootNode(rootNode);
318 }
319 else
320 {
321 super.setRootNode(rootNode);
322 }
323 }
324
325 public ExpressionEngine getExpressionEngine()
326 {
327 return config.getExpressionEngine();
328 }
329
330 public void setExpressionEngine(ExpressionEngine expressionEngine)
331 {
332 if (init)
333 {
334 config.setExpressionEngine(expressionEngine);
335 }
336 else
337 {
338 super.setExpressionEngine(expressionEngine);
339 }
340 }
341
342 public void addNodes(String key, Collection nodes)
343 {
344 getConfig().addNodes(key, nodes);
345 }
346
347 public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
348 {
349 return config.configurationAt(makePath(key), supportUpdates);
350 }
351
352 public SubnodeConfiguration configurationAt(String key)
353 {
354 return config.configurationAt(makePath(key));
355 }
356
357 public List configurationsAt(String key)
358 {
359 return config.configurationsAt(makePath(key));
360 }
361
362 public void clearTree(String key)
363 {
364 config.clearTree(makePath(key));
365 }
366
367 public int getMaxIndex(String key)
368 {
369 return config.getMaxIndex(makePath(key));
370 }
371
372 public Configuration interpolatedConfiguration()
373 {
374 return getConfig().interpolatedConfiguration();
375 }
376
377 public void addConfigurationListener(ConfigurationListener l)
378 {
379 getConfig().addConfigurationListener(l);
380 }
381
382 public boolean removeConfigurationListener(ConfigurationListener l)
383 {
384 return getConfig().removeConfigurationListener(l);
385 }
386
387 public Collection getConfigurationListeners()
388 {
389 return getConfig().getConfigurationListeners();
390 }
391
392 public void clearConfigurationListeners()
393 {
394 getConfig().clearConfigurationListeners();
395 }
396
397 public void addErrorListener(ConfigurationErrorListener l)
398 {
399 getConfig().addErrorListener(l);
400 }
401
402 public boolean removeErrorListener(ConfigurationErrorListener l)
403 {
404 return getConfig().removeErrorListener(l);
405 }
406
407 public void clearErrorListeners()
408 {
409 getConfig().clearErrorListeners();
410 }
411
412 public void save(Writer writer) throws ConfigurationException
413 {
414 config.save(writer);
415 }
416
417 public void load(Reader reader) throws ConfigurationException
418 {
419 config.load(reader);
420 }
421
422 public Collection getErrorListeners()
423 {
424 return getConfig().getErrorListeners();
425 }
426
427 protected Object resolveContainerStore(String key)
428 {
429 if (((Boolean) recursive.get()).booleanValue())
430 {
431 return null;
432 }
433 recursive.set(Boolean.TRUE);
434 try
435 {
436 return super.resolveContainerStore(key);
437 }
438 finally
439 {
440 recursive.set(Boolean.FALSE);
441 }
442 }
443
444 private HierarchicalConfiguration getConfig()
445 {
446 return config.configurationAt(makePath());
447 }
448
449 private String makePath()
450 {
451 String pathPattern = trailing ? path.substring(0, path.length() - 1) : path;
452 return getSubstitutor().replace(pathPattern);
453 }
454
455 /*
456 * Resolve the root expression and then add the item being retrieved. Insert a
457 * separator character as required.
458 */
459 private String makePath(String item)
460 {
461 String pathPattern;
462 if ((item.length() == 0 || item.startsWith("/")) && trailing)
463 {
464 pathPattern = path.substring(0, path.length() - 1);
465 }
466 else if (!item.startsWith("/") || !trailing)
467 {
468 pathPattern = path + "/";
469 }
470 else
471 {
472 pathPattern = path;
473 }
474 return getSubstitutor().replace(pathPattern) + item;
475 }
476 }