    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    }