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 727958 2008-12-19 07:19:24Z oheger $
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 void addProperty(String key, Object value)
082 {
083 config.addProperty(makePath(key), value);
084 }
085
086 public void clear()
087 {
088 getConfig().clear();
089 }
090
091 public void clearProperty(String key)
092 {
093 config.clearProperty(makePath(key));
094 }
095
096 public boolean containsKey(String key)
097 {
098 return config.containsKey(makePath(key));
099 }
100
101 public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
102 {
103 return config.getBigDecimal(makePath(key), defaultValue);
104 }
105
106 public BigDecimal getBigDecimal(String key)
107 {
108 return config.getBigDecimal(makePath(key));
109 }
110
111 public BigInteger getBigInteger(String key, BigInteger defaultValue)
112 {
113 return config.getBigInteger(makePath(key), defaultValue);
114 }
115
116 public BigInteger getBigInteger(String key)
117 {
118 return config.getBigInteger(makePath(key));
119 }
120
121 public boolean getBoolean(String key, boolean defaultValue)
122 {
123 return config.getBoolean(makePath(key), defaultValue);
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)
132 {
133 return config.getBoolean(makePath(key));
134 }
135
136 public byte getByte(String key, byte defaultValue)
137 {
138 return config.getByte(makePath(key), defaultValue);
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)
147 {
148 return config.getByte(makePath(key));
149 }
150
151 public double getDouble(String key, double defaultValue)
152 {
153 return config.getDouble(makePath(key), defaultValue);
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)
162 {
163 return config.getDouble(makePath(key));
164 }
165
166 public float getFloat(String key, float defaultValue)
167 {
168 return config.getFloat(makePath(key), defaultValue);
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)
177 {
178 return config.getFloat(makePath(key));
179 }
180
181 public int getInt(String key, int defaultValue)
182 {
183 return config.getInt(makePath(key), defaultValue);
184 }
185
186 public int getInt(String key)
187 {
188 return config.getInt(makePath(key));
189 }
190
191 public Integer getInteger(String key, Integer defaultValue)
192 {
193 return config.getInteger(makePath(key), defaultValue);
194 }
195
196 public Iterator getKeys()
197 {
198 return config.getKeys(makePath());
199 }
200
201 public Iterator getKeys(String prefix)
202 {
203 return config.getKeys(makePath(prefix));
204 }
205
206 public List getList(String key, List defaultValue)
207 {
208 return config.getList(makePath(key), defaultValue);
209 }
210
211 public List getList(String key)
212 {
213 return config.getList(makePath(key));
214 }
215
216 public long getLong(String key, long defaultValue)
217 {
218 return config.getLong(makePath(key), defaultValue);
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)
227 {
228 return config.getLong(makePath(key));
229 }
230
231 public Properties getProperties(String key)
232 {
233 return config.getProperties(makePath(key));
234 }
235
236 public Object getProperty(String key)
237 {
238 return config.getProperty(makePath(key));
239 }
240
241 public short getShort(String key, short defaultValue)
242 {
243 return config.getShort(makePath(key), defaultValue);
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)
252 {
253 return config.getShort(makePath(key));
254 }
255
256 public String getString(String key, String defaultValue)
257 {
258 return config.getString(makePath(key), defaultValue);
259 }
260
261 public String getString(String key)
262 {
263 return config.getString(makePath(key));
264 }
265
266 public String[] getStringArray(String key)
267 {
268 return config.getStringArray(makePath(key));
269 }
270
271 public boolean isEmpty()
272 {
273 return getConfig().isEmpty();
274 }
275
276 public void setProperty(String key, Object value)
277 {
278 getConfig().setProperty(key, value);
279 }
280
281 public Configuration subset(String prefix)
282 {
283 return getConfig().subset(prefix);
284 }
285
286 public Node getRoot()
287 {
288 return getConfig().getRoot();
289 }
290
291 public void setRoot(Node node)
292 {
293 if (init)
294 {
295 getConfig().setRoot(node);
296 }
297 else
298 {
299 super.setRoot(node);
300 }
301 }
302
303 public ConfigurationNode getRootNode()
304 {
305 return getConfig().getRootNode();
306 }
307
308 public void setRootNode(ConfigurationNode rootNode)
309 {
310 if (init)
311 {
312 getConfig().setRootNode(rootNode);
313 }
314 else
315 {
316 super.setRootNode(rootNode);
317 }
318 }
319
320 public ExpressionEngine getExpressionEngine()
321 {
322 return config.getExpressionEngine();
323 }
324
325 public void setExpressionEngine(ExpressionEngine expressionEngine)
326 {
327 if (init)
328 {
329 config.setExpressionEngine(expressionEngine);
330 }
331 else
332 {
333 super.setExpressionEngine(expressionEngine);
334 }
335 }
336
337 public void addNodes(String key, Collection nodes)
338 {
339 getConfig().addNodes(key, nodes);
340 }
341
342 public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
343 {
344 return config.configurationAt(makePath(key), supportUpdates);
345 }
346
347 public SubnodeConfiguration configurationAt(String key)
348 {
349 return config.configurationAt(makePath(key));
350 }
351
352 public List configurationsAt(String key)
353 {
354 return config.configurationsAt(makePath(key));
355 }
356
357 public void clearTree(String key)
358 {
359 config.clearTree(makePath(key));
360 }
361
362 public int getMaxIndex(String key)
363 {
364 return config.getMaxIndex(makePath(key));
365 }
366
367 public Configuration interpolatedConfiguration()
368 {
369 return getConfig().interpolatedConfiguration();
370 }
371
372 public void addConfigurationListener(ConfigurationListener l)
373 {
374 getConfig().addConfigurationListener(l);
375 }
376
377 public boolean removeConfigurationListener(ConfigurationListener l)
378 {
379 return getConfig().removeConfigurationListener(l);
380 }
381
382 public Collection getConfigurationListeners()
383 {
384 return getConfig().getConfigurationListeners();
385 }
386
387 public void clearConfigurationListeners()
388 {
389 getConfig().clearConfigurationListeners();
390 }
391
392 public void addErrorListener(ConfigurationErrorListener l)
393 {
394 getConfig().addErrorListener(l);
395 }
396
397 public boolean removeErrorListener(ConfigurationErrorListener l)
398 {
399 return getConfig().removeErrorListener(l);
400 }
401
402 public void clearErrorListeners()
403 {
404 getConfig().clearErrorListeners();
405 }
406
407 public void save(Writer writer) throws ConfigurationException
408 {
409 config.save(writer);
410 }
411
412 public void load(Reader reader) throws ConfigurationException
413 {
414 config.load(reader);
415 }
416
417 public Collection getErrorListeners()
418 {
419 return getConfig().getErrorListeners();
420 }
421
422 protected Object resolveContainerStore(String key)
423 {
424 if (((Boolean) recursive.get()).booleanValue())
425 {
426 return null;
427 }
428 recursive.set(Boolean.TRUE);
429 try
430 {
431 return super.resolveContainerStore(key);
432 }
433 finally
434 {
435 recursive.set(Boolean.FALSE);
436 }
437 }
438
439 private HierarchicalConfiguration getConfig()
440 {
441 return config.configurationAt(makePath());
442 }
443
444 private String makePath()
445 {
446 String pathPattern = trailing ? path.substring(0, path.length() - 1) : path;
447 return getSubstitutor().replace(pathPattern);
448 }
449
450 /*
451 * Resolve the root expression and then add the item being retrieved. Insert a
452 * separator character as required.
453 */
454 private String makePath(String item)
455 {
456 String pathPattern;
457 if ((item.length() == 0 || item.startsWith("/")) && trailing)
458 {
459 pathPattern = path.substring(0, path.length() - 1);
460 }
461 else if (!item.startsWith("/") || !trailing)
462 {
463 pathPattern = path + "/";
464 }
465 else
466 {
467 pathPattern = path;
468 }
469 return getSubstitutor().replace(pathPattern) + item;
470 }
471 }