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 }