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 }