    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.math.BigDecimal;
    020    import java.math.BigInteger;
    021    import java.util.ArrayList;
    022    import java.util.Collection;
    023    import java.util.HashMap;
    024    import java.util.Iterator;
    025    import java.util.List;
    026    import java.util.Map;
    027    import java.util.Properties;
    028    import java.util.Set;
    029
    030    import org.apache.commons.configuration.event.ConfigurationErrorListener;
    031    import org.apache.commons.configuration.event.ConfigurationListener;
    032    import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
    033    import org.apache.commons.configuration.tree.ConfigurationNode;
    034    import org.apache.commons.configuration.tree.ExpressionEngine;
    035    import org.apache.commons.configuration.tree.NodeCombiner;
    036    import org.apache.commons.lang.text.StrSubstitutor;
    037    import org.apache.commons.logging.Log;
    038    import org.apache.commons.logging.LogFactory;
    039
    040    /**
    041     * DynamicCombinedConfiguration allows a set of CombinedConfigurations to be used. Each CombinedConfiguration
    042     * is referenced by a key that is dynamically constructed from a key pattern on each call. The key pattern
    043     * will be resolved using the configured ConfigurationInterpolator.
    044     * @since 1.6
    045     * @author <a
    046     * href="http://commons.apache.org/configuration/team-list.html">Commons
    047     * Configuration team</a>
    048     * @version $Id: DynamicCombinedConfiguration.java 1158121 2011-08-16 06:21:42Z oheger $
    049     */
    050    public class DynamicCombinedConfiguration extends CombinedConfiguration
    051    {
    052        /**
    053         * Prevent recursion while resolving unprefixed properties.
    054         */
    055        private static ThreadLocal recursive = new ThreadLocal()
    056        {
    057            protected synchronized Object initialValue()
    058            {
    059                return Boolean.FALSE;
    060            }
    061        };
    062
    063        /** The CombinedConfigurations */
    064        private Map configs = new HashMap();
    065
    066        /** Stores a list with the contained configurations. */
    067        private List configurations = new ArrayList();
    068
    069        /** Stores a map with the named configurations. */
    070        private Map namedConfigurations = new HashMap();
    071
    072        /** The key pattern for the CombinedConfiguration map */
    073        private String keyPattern;
    074
    075        /** Stores the combiner. */
    076        private NodeCombiner nodeCombiner;
    077
    078        /** The name of the logger to use for each CombinedConfiguration */
    079        private String loggerName = DynamicCombinedConfiguration.class.getName();
    080
    081        /** The object for handling variable substitution in key patterns. */
    082        private StrSubstitutor localSubst = new StrSubstitutor(new ConfigurationInterpolator());
    083
    084        /**
    085         * Creates a new instance of <code>CombinedConfiguration</code> and
    086         * initializes the combiner to be used.
    087         *
    088         * @param comb the node combiner (can be <b>null</b>, then a union combiner
    089         * is used as default)
    090         */
    091        public DynamicCombinedConfiguration(NodeCombiner comb)
    092        {
    093            super();
    094            setNodeCombiner(comb);
    095            setIgnoreReloadExceptions(false);
    096            setLogger(LogFactory.getLog(DynamicCombinedConfiguration.class));
    097        }
    098
    099        /**
    100         * Creates a new instance of <code>CombinedConfiguration</code> that uses
    101         * a union combiner.
    102         *
    103         * @see org.apache.commons.configuration.tree.UnionCombiner
    104         */
    105        public DynamicCombinedConfiguration()
    106        {
    107            super();
    108            setIgnoreReloadExceptions(false);
    109            setLogger(LogFactory.getLog(DynamicCombinedConfiguration.class));
    110        }
    111
    112        public void setKeyPattern(String pattern)
    113        {
    114            this.keyPattern = pattern;
    115        }
    116
    117        public String getKeyPattern()
    118        {
    119            return this.keyPattern;
    120        }
    121
    122        /**
    123         * Set the name of the Logger to use on each CombinedConfiguration.
    124         * @param name The Logger name.
    125         */
    126        public void setLoggerName(String name)
    127        {
    128            this.loggerName = name;
    129        }
    130
    131        /**
    132         * Returns the node combiner that is used for creating the combined node
    133         * structure.
    134         *
    135         * @return the node combiner
    136         */
    137        public NodeCombiner getNodeCombiner()
    138        {
    139            return nodeCombiner;
    140        }
    141
    142        /**
    143         * Sets the node combiner. This object will be used when the combined node
    144         * structure is to be constructed. It must not be <b>null</b>, otherwise an
    145         * <code>IllegalArgumentException</code> exception is thrown. Changing the
    146         * node combiner causes an invalidation of this combined configuration, so
    147         * that the new combiner immediately takes effect.
    148         *
    149         * @param nodeCombiner the node combiner
    150         */
    151        public void setNodeCombiner(NodeCombiner nodeCombiner)
    152        {
    153            if (nodeCombiner == null)
    154            {
    155                throw new IllegalArgumentException(
    156                        "Node combiner must not be null!");
    157            }
    158            this.nodeCombiner = nodeCombiner;
    159            invalidateAll();
    160        }
    161        /**
    162         * Adds a new configuration to this combined configuration. It is possible
    163         * (but not mandatory) to give the new configuration a name. This name must
    164         * be unique, otherwise a <code>ConfigurationRuntimeException</code> will
    165         * be thrown. With the optional <code>at</code> argument you can specify
    166         * where in the resulting node structure the content of the added
    167         * configuration should appear. This is a string that uses dots as property
    168         * delimiters (independent on the current expression engine). For instance
    169         * if you pass in the string <code>&quot;database.tables&quot;</code>,
    170         * all properties of the added configuration will occur in this branch.
    171         *
    172         * @param config the configuration to add (must not be <b>null</b>)
    173         * @param name the name of this configuration (can be <b>null</b>)
    174         * @param at the position of this configuration in the combined tree (can be
    175         * <b>null</b>)
    176         */
    177        public void addConfiguration(AbstractConfiguration config, String name,
    178                String at)
    179        {
    180            ConfigData cd = new ConfigData(config, name, at);
    181            configurations.add(cd);
    182            if (name != null)
    183            {
    184                namedConfigurations.put(name, config);
    185            }
    186        }
    187           /**
    188         * Returns the number of configurations that are contained in this combined
    189         * configuration.
    190         *
    191         * @return the number of contained configurations
    192         */
    193        public int getNumberOfConfigurations()
    194        {
    195            return configurations.size();
    196        }
    197
    198        /**
    199         * Returns the configuration at the specified index. The contained
    200         * configurations are numbered in the order they were added to this combined
    201         * configuration. The index of the first configuration is 0.
    202         *
    203         * @param index the index
    204         * @return the configuration at this index
    205         */
    206        public Configuration getConfiguration(int index)
    207        {
    208            ConfigData cd = (ConfigData) configurations.get(index);
    209            return cd.getConfiguration();
    210        }
    211
    212        /**
    213         * Returns the configuration with the given name. This can be <b>null</b>
    214         * if no such configuration exists.
    215         *
    216         * @param name the name of the configuration
    217         * @return the configuration with this name
    218         */
    219        public Configuration getConfiguration(String name)
    220        {
    221            return (Configuration) namedConfigurations.get(name);
    222        }
    223
    224        /**
    225         * Returns a set with the names of all configurations contained in this
    226         * combined configuration. Of course here are only these configurations
    227         * listed, for which a name was specified when they were added.
    228         *
    229         * @return a set with the names of the contained configurations (never
    230         * <b>null</b>)
    231         */
    232        public Set getConfigurationNames()
    233        {
    234            return namedConfigurations.keySet();
    235        }
    236
    237        /**
    238         * Removes the configuration with the specified name.
    239         *
    240         * @param name the name of the configuration to be removed
    241         * @return the removed configuration (<b>null</b> if this configuration
    242         * was not found)
    243         */
    244        public Configuration removeConfiguration(String name)
    245        {
    246            Configuration conf = getConfiguration(name);
    247            if (conf != null)
    248            {
    249                removeConfiguration(conf);
    250            }
    251            return conf;
    252        }
    253
    254        /**
    255         * Removes the specified configuration from this combined configuration.
    256         *
    257         * @param config the configuration to be removed
    258         * @return a flag whether this configuration was found and could be removed
    259         */
    260        public boolean removeConfiguration(Configuration config)
    261        {
    262            for (int index = 0; index < getNumberOfConfigurations(); index++)
    263            {
    264                if (((ConfigData) configurations.get(index)).getConfiguration() == config)
    265                {
    266                    removeConfigurationAt(index);
    267
    268                }
    269            }
    270
    271            return super.removeConfiguration(config);
    272        }
    273
    274        /**
    275         * Removes the configuration at the specified index.
    276         *
    277         * @param index the index
    278         * @return the removed configuration
    279         */
    280        public Configuration removeConfigurationAt(int index)
    281        {
    282            ConfigData cd = (ConfigData) configurations.remove(index);
    283            if (cd.getName() != null)
    284            {
    285                namedConfigurations.remove(cd.getName());
    286            }
    287            return super.removeConfigurationAt(index);
    288        }
    289        /**
    290         * Returns the configuration root node of this combined configuration. This
    291         * method will construct a combined node structure using the current node
    292         * combiner if necessary.
    293         *
    294         * @return the combined root node
    295         */
    296        public ConfigurationNode getRootNode()
    297        {
    298            return getCurrentConfig().getRootNode();
    299        }
    300
    301        public void setRootNode(ConfigurationNode rootNode)
    302        {
    303            if (configs != null)
    304            {
    305                this.getCurrentConfig().setRootNode(rootNode);
    306            }
    307            else
    308            {
    309                super.setRootNode(rootNode);
    310            }
    311        }
    312
    313        public void addProperty(String key, Object value)
    314        {
    315            this.getCurrentConfig().addProperty(key, value);
    316        }
    317
    318        public void clear()
    319        {
    320            if (configs != null)
    321            {
    322                this.getCurrentConfig().clear();
    323            }
    324        }
    325
    326        public void clearProperty(String key)
    327        {
    328            this.getCurrentConfig().clearProperty(key);
    329        }
    330
    331        public boolean containsKey(String key)
    332        {
    333            return this.getCurrentConfig().containsKey(key);
    334        }
    335
    336        public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
    337        {
    338            return this.getCurrentConfig().getBigDecimal(key, defaultValue);
    339        }
    340
    341        public BigDecimal getBigDecimal(String key)
    342        {
    343            return this.getCurrentConfig().getBigDecimal(key);
    344        }
    345
    346        public BigInteger getBigInteger(String key, BigInteger defaultValue)
    347        {
    348            return this.getCurrentConfig().getBigInteger(key, defaultValue);
    349        }
    350
    351        public BigInteger getBigInteger(String key)
    352        {
    353            return this.getCurrentConfig().getBigInteger(key);
    354        }
    355
    356        public boolean getBoolean(String key, boolean defaultValue)
    357        {
    358            return this.getCurrentConfig().getBoolean(key, defaultValue);
    359        }
    360
    361        public Boolean getBoolean(String key, Boolean defaultValue)
    362        {
    363            return this.getCurrentConfig().getBoolean(key, defaultValue);
    364        }
    365
    366        public boolean getBoolean(String key)
    367        {
    368            return this.getCurrentConfig().getBoolean(key);
    369        }
    370
    371        public byte getByte(String key, byte defaultValue)
    372        {
    373            return this.getCurrentConfig().getByte(key, defaultValue);
    374        }
    375
    376        public Byte getByte(String key, Byte defaultValue)
    377        {
    378            return this.getCurrentConfig().getByte(key, defaultValue);
    379        }
    380
    381        public byte getByte(String key)
    382        {
    383            return this.getCurrentConfig().getByte(key);
    384        }
    385
    386        public double getDouble(String key, double defaultValue)
    387        {
    388            return this.getCurrentConfig().getDouble(key, defaultValue);
    389        }
    390
    391        public Double getDouble(String key, Double defaultValue)
    392        {
    393            return this.getCurrentConfig().getDouble(key, defaultValue);
    394        }
    395
    396        public double getDouble(String key)
    397        {
    398            return this.getCurrentConfig().getDouble(key);
    399        }
    400
    401        public float getFloat(String key, float defaultValue)
    402        {
    403            return this.getCurrentConfig().getFloat(key, defaultValue);
    404        }
    405
    406        public Float getFloat(String key, Float defaultValue)
    407        {
    408            return this.getCurrentConfig().getFloat(key, defaultValue);
    409        }
    410
    411        public float getFloat(String key)
    412        {
    413            return this.getCurrentConfig().getFloat(key);
    414        }
    415
    416        public int getInt(String key, int defaultValue)
    417        {
    418            return this.getCurrentConfig().getInt(key, defaultValue);
    419        }
    420
    421        public int getInt(String key)
    422        {
    423            return this.getCurrentConfig().getInt(key);
    424        }
    425
    426        public Integer getInteger(String key, Integer defaultValue)
    427        {
    428            return this.getCurrentConfig().getInteger(key, defaultValue);
    429        }
    430
    431        public Iterator getKeys()
    432        {
    433            return this.getCurrentConfig().getKeys();
    434        }
    435
    436        public Iterator getKeys(String prefix)
    437        {
    438            return this.getCurrentConfig().getKeys(prefix);
    439        }
    440
    441        public List getList(String key, List defaultValue)
    442        {
    443            return this.getCurrentConfig().getList(key, defaultValue);
    444        }
    445
    446        public List getList(String key)
    447        {
    448            return this.getCurrentConfig().getList(key);
    449        }
    450
    451        public long getLong(String key, long defaultValue)
    452        {
    453            return this.getCurrentConfig().getLong(key, defaultValue);
    454        }
    455
    456        public Long getLong(String key, Long defaultValue)
    457        {
    458            return this.getCurrentConfig().getLong(key, defaultValue);
    459        }
    460
    461        public long getLong(String key)
    462        {
    463            return this.getCurrentConfig().getLong(key);
    464        }
    465
    466        public Properties getProperties(String key)
    467        {
    468            return this.getCurrentConfig().getProperties(key);
    469        }
    470
    471        public Object getProperty(String key)
    472        {
    473            return this.getCurrentConfig().getProperty(key);
    474        }
    475
    476        public short getShort(String key, short defaultValue)
    477        {
    478            return this.getCurrentConfig().getShort(key, defaultValue);
    479        }
    480
    481        public Short getShort(String key, Short defaultValue)
    482        {
    483            return this.getCurrentConfig().getShort(key, defaultValue);
    484        }
    485
    486        public short getShort(String key)
    487        {
    488            return this.getCurrentConfig().getShort(key);
    489        }
    490
    491        public String getString(String key, String defaultValue)
    492        {
    493            return this.getCurrentConfig().getString(key, defaultValue);
    494        }
    495
    496        public String getString(String key)
    497        {
    498            return this.getCurrentConfig().getString(key);
    499        }
    500
    501        public String[] getStringArray(String key)
    502        {
    503            return this.getCurrentConfig().getStringArray(key);
    504        }
    505
    506        public boolean isEmpty()
    507        {
    508            return this.getCurrentConfig().isEmpty();
    509        }
    510
    511        public void setProperty(String key, Object value)
    512        {
    513            if (configs != null)
    514            {
    515                this.getCurrentConfig().setProperty(key, value);
    516            }
    517        }
    518
    519        public Configuration subset(String prefix)
    520        {
    521            return this.getCurrentConfig().subset(prefix);
    522        }
    523
    524        public Node getRoot()
    525        {
    526            return this.getCurrentConfig().getRoot();
    527        }
    528
    529        public void setRoot(Node node)
    530        {
    531            if (configs != null)
    532            {
    533                this.getCurrentConfig().setRoot(node);
    534            }
    535            else
    536            {
    537                super.setRoot(node);
    538            }
    539        }
    540
    541        public ExpressionEngine getExpressionEngine()
    542        {
    543            return super.getExpressionEngine();
    544        }
    545
    546        public void setExpressionEngine(ExpressionEngine expressionEngine)
    547        {
    548            super.setExpressionEngine(expressionEngine);
    549        }
    550
    551        public void addNodes(String key, Collection nodes)
    552        {
    553            this.getCurrentConfig().addNodes(key, nodes);
    554        }
    555
    556        public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
    557        {
    558            return this.getCurrentConfig().configurationAt(key, supportUpdates);
    559        }
    560
    561        public SubnodeConfiguration configurationAt(String key)
    562        {
    563            return this.getCurrentConfig().configurationAt(key);
    564        }
    565
    566        public List configurationsAt(String key)
    567        {
    568            return this.getCurrentConfig().configurationsAt(key);
    569        }
    570
    571        public void clearTree(String key)
    572        {
    573            this.getCurrentConfig().clearTree(key);
    574        }
    575
    576        public int getMaxIndex(String key)
    577        {
    578            return this.getCurrentConfig().getMaxIndex(key);
    579        }
    580
    581        public Configuration interpolatedConfiguration()
    582        {
    583            return this.getCurrentConfig().interpolatedConfiguration();
    584        }
    585
    586
    587        /**
    588         * Returns the configuration source, in which the specified key is defined.
    589         * This method will determine the configuration node that is identified by
    590         * the given key. The following constellations are possible:
    591         * <ul>
    592         * <li>If no node object is found for this key, <b>null</b> is returned.</li>
    593         * <li>If the key maps to multiple nodes belonging to different
    594         * configuration sources, a <code>IllegalArgumentException</code> is
    595         * thrown (in this case no unique source can be determined).</li>
    596         * <li>If exactly one node is found for the key, the (child) configuration
    597         * object, to which the node belongs is determined and returned.</li>
    598         * <li>For keys that have been added directly to this combined
    599         * configuration and that do not belong to the namespaces defined by
    600         * existing child configurations this configuration will be returned.</li>
    601         * </ul>
    602         *
    603         * @param key the key of a configuration property
    604         * @return the configuration, to which this property belongs or <b>null</b>
    605         * if the key cannot be resolved
    606         * @throws IllegalArgumentException if the key maps to multiple properties
    607         * and the source cannot be determined, or if the key is <b>null</b>
    608         */
    609        public Configuration getSource(String key)
    610        {
    611            if (key == null)
    612            {
    613                throw new IllegalArgumentException("Key must not be null!");
    614            }
    615            return getCurrentConfig().getSource(key);
    616        }
    617
    618        public void addConfigurationListener(ConfigurationListener l)
    619        {
    620            super.addConfigurationListener(l);
    621
    622            Iterator iter = configs.values().iterator();
    623            while (iter.hasNext())
    624            {
    625                CombinedConfiguration config = (CombinedConfiguration) iter.next();
    626                config.addConfigurationListener(l);
    627            }
    628        }
    629
    630        public boolean removeConfigurationListener(ConfigurationListener l)
    631        {
    632            Iterator iter = configs.values().iterator();
    633            while (iter.hasNext())
    634            {
    635                CombinedConfiguration config = (CombinedConfiguration) iter.next();
    636                config.removeConfigurationListener(l);
    637            }
    638            return super.removeConfigurationListener(l);
    639        }
    640
    641        public Collection getConfigurationListeners()
    642        {
    643            return super.getConfigurationListeners();
    644        }
    645
    646        public void clearConfigurationListeners()
    647        {
    648            Iterator iter = configs.values().iterator();
    649            while (iter.hasNext())
    650            {
    651                CombinedConfiguration config = (CombinedConfiguration) iter.next();
    652                config.clearConfigurationListeners();
    653            }
    654            super.clearConfigurationListeners();
    655        }
    656
    657        public void addErrorListener(ConfigurationErrorListener l)
    658        {
    659            Iterator iter = configs.values().iterator();
    660            while (iter.hasNext())
    661            {
    662                CombinedConfiguration config = (CombinedConfiguration) iter.next();
    663                config.addErrorListener(l);
    664            }
    665            super.addErrorListener(l);
    666        }
    667
    668        public boolean removeErrorListener(ConfigurationErrorListener l)
    669        {
    670            Iterator iter = configs.values().iterator();
    671            while (iter.hasNext())
    672            {
    673                CombinedConfiguration config = (CombinedConfiguration) iter.next();
    674                config.removeErrorListener(l);
    675            }
    676            return super.removeErrorListener(l);
    677        }
    678
    679        public void clearErrorListeners()
    680        {
    681            Iterator iter = configs.values().iterator();
    682            while (iter.hasNext())
    683            {
    684                CombinedConfiguration config = (CombinedConfiguration) iter.next();
    685                config.clearErrorListeners();
    686            }
    687            super.clearErrorListeners();
    688        }
    689
    690        public Collection getErrorListeners()
    691        {
    692            return super.getErrorListeners();
    693        }
    694
    695
    696
    697        /**
    698         * Returns a copy of this object. This implementation performs a deep clone,
    699         * i.e. all contained configurations will be cloned, too. For this to work,
    700         * all contained configurations must be cloneable. Registered event
    701         * listeners won't be cloned. The clone will use the same node combiner than
    702         * the original.
    703         *
    704         * @return the copied object
    705         */
    706        public Object clone()
    707        {
    708            return super.clone();
    709        }
    710
    711
    712
    713        /**
    714         * Invalidates the current combined configuration. This means that the next time a
    715         * property is accessed the combined node structure must be re-constructed.
    716         * Invalidation of a combined configuration also means that an event of type
    717         * <code>EVENT_COMBINED_INVALIDATE</code> is fired. Note that while other
    718         * events most times appear twice (once before and once after an update),
    719         * this event is only fired once (after update).
    720         */
    721        public void invalidate()
    722        {
    723            getCurrentConfig().invalidate();
    724        }
    725
    726        public void invalidateAll()
    727        {
    728            if (configs == null)
    729            {
    730                return;
    731            }
    732            Iterator iter = configs.values().iterator();
    733            while (iter.hasNext())
    734            {
    735               CombinedConfiguration config = (CombinedConfiguration) iter.next();
    736               config.invalidate();
    737            }
    738        }
    739
    740        /*
    741         * Don't allow resolveContainerStore to be called recursively.
    742         * @param key The key to resolve.
    743         * @return The value of the key.
    744         */
    745        protected Object resolveContainerStore(String key)
    746        {
    747            if (((Boolean) recursive.get()).booleanValue())
    748            {
    749                return null;
    750            }
    751            recursive.set(Boolean.TRUE);
    752            try
    753            {
    754                return super.resolveContainerStore(key);
    755            }
    756            finally
    757            {
    758                recursive.set(Boolean.FALSE);
    759            }
    760        }
    761
    762        private CombinedConfiguration getCurrentConfig()
    763        {
    764            String key = localSubst.replace(keyPattern);
    765            CombinedConfiguration config;
    766            synchronized (getNodeCombiner())
    767            {
    768                config = (CombinedConfiguration) configs.get(key);
    769                if (config == null)
    770                {
    771                    config = new CombinedConfiguration(getNodeCombiner());
    772                    if (loggerName != null)
    773                    {
    774                        Log log = LogFactory.getLog(loggerName);
    775                        if (log != null)
    776                        {
    777                            config.setLogger(log);
    778                        }
    779                    }
    780                    config.setIgnoreReloadExceptions(isIgnoreReloadExceptions());
    781                    config.setExpressionEngine(this.getExpressionEngine());
    782                    config.setDelimiterParsingDisabled(isDelimiterParsingDisabled());
    783                    config.setConversionExpressionEngine(getConversionExpressionEngine());
    784                    config.setListDelimiter(getListDelimiter());
    785                    Iterator iter = getErrorListeners().iterator();
    786                    while (iter.hasNext())
    787                    {
    788                        ConfigurationErrorListener listener = (ConfigurationErrorListener) iter.next();
    789                        config.addErrorListener(listener);
    790                    }
    791                    iter = getConfigurationListeners().iterator();
    792                    while (iter.hasNext())
    793                    {
    794                        ConfigurationListener listener = (ConfigurationListener) iter.next();
    795                        config.addConfigurationListener(listener);
    796                    }
    797                    config.setForceReloadCheck(isForceReloadCheck());
    798                    iter = configurations.iterator();
    799                    while (iter.hasNext())
    800                    {
    801                        ConfigData data = (ConfigData) iter.next();
    802                        config.addConfiguration(data.getConfiguration(), data.getName(),
    803                                data.getAt());
    804                    }
    805                    configs.put(key, config);
    806                }
    807            }
    808            if (getLogger().isDebugEnabled())
    809            {
    810                getLogger().debug("Returning config for " + key + ": " + config);
    811            }
    812            return config;
    813        }
    814
    815        /**
    816         * Internal class that identifies each Configuration.
    817         */
    818        static class ConfigData
    819        {
    820            /** Stores a reference to the configuration. */
    821            private AbstractConfiguration configuration;
    822
    823            /** Stores the name under which the configuration is stored. */
    824            private String name;
    825
    826            /** Stores the at string.*/
    827            private String at;
    828
    829                    /**
    830             * Creates a new instance of <code>ConfigData</code> and initializes
    831             * it.
    832             *
    833             * @param config the configuration
    834             * @param n the name
    835             * @param at the at position
    836             */
    837            public ConfigData(AbstractConfiguration config, String n, String at)
    838            {
    839                configuration = config;
    840                name = n;
    841                this.at = at;
    842            }
    843
    844                    /**
    845             * Returns the stored configuration.
    846             *
    847             * @return the configuration
    848             */
    849            public AbstractConfiguration getConfiguration()
    850            {
    851                return configuration;
    852            }
    853
    854            /**
    855             * Returns the configuration's name.
    856             *
    857             * @return the name
    858             */
    859            public String getName()
    860            {
    861                return name;
    862            }
    863
    864            /**
    865             * Returns the at position of this configuration.
    866             *
    867             * @return the at position
    868             */
    869            public String getAt()
    870            {
    871                return at;
    872            }
    873
    874        }
    875    }