Coverage Report - org.apache.commons.configuration.DynamicCombinedConfiguration
 
Classes in this File Line Coverage Branch Coverage Complexity
DynamicCombinedConfiguration
24%
45/185
38%
9/24
1,333
DynamicCombinedConfiguration$1
50%
1/2
N/A
1,333
DynamicCombinedConfiguration$ConfigData
100%
8/8
N/A
1,333
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.configuration;
 18  
 
 19  
 import java.math.BigDecimal;
 20  
 import java.math.BigInteger;
 21  
 import java.util.ArrayList;
 22  
 import java.util.Collection;
 23  
 import java.util.HashMap;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 import java.util.Properties;
 28  
 import java.util.Set;
 29  
 
 30  
 import org.apache.commons.configuration.event.ConfigurationErrorListener;
 31  
 import org.apache.commons.configuration.event.ConfigurationListener;
 32  
 import org.apache.commons.configuration.tree.ConfigurationNode;
 33  
 import org.apache.commons.configuration.tree.ExpressionEngine;
 34  
 import org.apache.commons.configuration.tree.NodeCombiner;
 35  
 
 36  
 /**
 37  
  * DynamicCombinedConfiguration allows a set of CombinedConfigurations to be used. Each CombinedConfiguration
 38  
  * is referenced by a key that is dynamically constructed from a key pattern on each call. The key pattern
 39  
  * will be resolved using the configured ConfigurationInterpolator.
 40  
  * @since 1.6
 41  
  * @author <a
 42  
  * href="http://commons.apache.org/configuration/team-list.html">Commons
 43  
  * Configuration team</a>
 44  
  * @version $Id: DynamicCombinedConfiguration.java 727955 2008-12-19 07:06:16Z oheger $
 45  
  */
 46  
 public class DynamicCombinedConfiguration extends CombinedConfiguration
 47  
 {
 48  
     /**
 49  
      * Prevent recursion while resolving unprefixed properties.
 50  
      */
 51  1
     private static ThreadLocal recursive = new ThreadLocal()
 52  
     {
 53  1
         protected synchronized Object initialValue()
 54  
         {
 55  0
             return Boolean.FALSE;
 56  
         }
 57  
     };
 58  
 
 59  
     /** The CombinedConfigurations */
 60  1
     private Map configs = new HashMap();
 61  
 
 62  
     /** Stores a list with the contained configurations. */
 63  1
     private List configurations = new ArrayList();
 64  
 
 65  
     /** Stores a map with the named configurations. */
 66  1
     private Map namedConfigurations = new HashMap();
 67  
 
 68  
     /** The key pattern for the CombinedConfiguration map */
 69  
     private String keyPattern;
 70  
 
 71  
     /** Stores the combiner. */
 72  
     private NodeCombiner nodeCombiner;
 73  
 
 74  
     /**
 75  
      * Creates a new instance of <code>CombinedConfiguration</code> and
 76  
      * initializes the combiner to be used.
 77  
      *
 78  
      * @param comb the node combiner (can be <b>null</b>, then a union combiner
 79  
      * is used as default)
 80  
      */
 81  
     public DynamicCombinedConfiguration(NodeCombiner comb)
 82  
     {
 83  0
         super();
 84  0
         setNodeCombiner(comb);
 85  0
     }
 86  
 
 87  
     /**
 88  
      * Creates a new instance of <code>CombinedConfiguration</code> that uses
 89  
      * a union combiner.
 90  
      *
 91  
      * @see org.apache.commons.configuration.tree.UnionCombiner
 92  
      */
 93  
     public DynamicCombinedConfiguration()
 94  
     {
 95  1
         super();
 96  1
     }
 97  
 
 98  
     public void setKeyPattern(String pattern)
 99  
     {
 100  1
         this.keyPattern = pattern;
 101  1
     }
 102  
 
 103  
     public String getKeyPattern()
 104  
     {
 105  0
         return this.keyPattern;
 106  
     }
 107  
 
 108  
     /**
 109  
      * Returns the node combiner that is used for creating the combined node
 110  
      * structure.
 111  
      *
 112  
      * @return the node combiner
 113  
      */
 114  
     public NodeCombiner getNodeCombiner()
 115  
     {
 116  8
         return nodeCombiner;
 117  
     }
 118  
 
 119  
     /**
 120  
      * Sets the node combiner. This object will be used when the combined node
 121  
      * structure is to be constructed. It must not be <b>null</b>, otherwise an
 122  
      * <code>IllegalArgumentException</code> exception is thrown. Changing the
 123  
      * node combiner causes an invalidation of this combined configuration, so
 124  
      * that the new combiner immediately takes effect.
 125  
      *
 126  
      * @param nodeCombiner the node combiner
 127  
      */
 128  
     public void setNodeCombiner(NodeCombiner nodeCombiner)
 129  
     {
 130  1
         if (nodeCombiner == null)
 131  
         {
 132  0
             throw new IllegalArgumentException(
 133  
                     "Node combiner must not be null!");
 134  
         }
 135  1
         this.nodeCombiner = nodeCombiner;
 136  1
         invalidateAll();
 137  1
     }
 138  
     /**
 139  
      * Adds a new configuration to this combined configuration. It is possible
 140  
      * (but not mandatory) to give the new configuration a name. This name must
 141  
      * be unique, otherwise a <code>ConfigurationRuntimeException</code> will
 142  
      * be thrown. With the optional <code>at</code> argument you can specify
 143  
      * where in the resulting node structure the content of the added
 144  
      * configuration should appear. This is a string that uses dots as property
 145  
      * delimiters (independent on the current expression engine). For instance
 146  
      * if you pass in the string <code>&quot;database.tables&quot;</code>,
 147  
      * all properties of the added configuration will occur in this branch.
 148  
      *
 149  
      * @param config the configuration to add (must not be <b>null</b>)
 150  
      * @param name the name of this configuration (can be <b>null</b>)
 151  
      * @param at the position of this configuration in the combined tree (can be
 152  
      * <b>null</b>)
 153  
      */
 154  
     public void addConfiguration(AbstractConfiguration config, String name,
 155  
             String at)
 156  
     {
 157  2
         ConfigData cd = new ConfigData(config, name, at);
 158  2
         configurations.add(cd);
 159  2
         if (name != null)
 160  
         {
 161  2
             namedConfigurations.put(name, config);
 162  
         }
 163  2
     }
 164  
        /**
 165  
      * Returns the number of configurations that are contained in this combined
 166  
      * configuration.
 167  
      *
 168  
      * @return the number of contained configurations
 169  
      */
 170  
     public int getNumberOfConfigurations()
 171  
     {
 172  0
         return configurations.size();
 173  
     }
 174  
 
 175  
     /**
 176  
      * Returns the configuration at the specified index. The contained
 177  
      * configurations are numbered in the order they were added to this combined
 178  
      * configuration. The index of the first configuration is 0.
 179  
      *
 180  
      * @param index the index
 181  
      * @return the configuration at this index
 182  
      */
 183  
     public Configuration getConfiguration(int index)
 184  
     {
 185  0
         ConfigData cd = (ConfigData) configurations.get(index);
 186  0
         return cd.getConfiguration();
 187  
     }
 188  
 
 189  
     /**
 190  
      * Returns the configuration with the given name. This can be <b>null</b>
 191  
      * if no such configuration exists.
 192  
      *
 193  
      * @param name the name of the configuration
 194  
      * @return the configuration with this name
 195  
      */
 196  
     public Configuration getConfiguration(String name)
 197  
     {
 198  0
         return (Configuration) namedConfigurations.get(name);
 199  
     }
 200  
 
 201  
     /**
 202  
      * Returns a set with the names of all configurations contained in this
 203  
      * combined configuration. Of course here are only these configurations
 204  
      * listed, for which a name was specified when they were added.
 205  
      *
 206  
      * @return a set with the names of the contained configurations (never
 207  
      * <b>null</b>)
 208  
      */
 209  
     public Set getConfigurationNames()
 210  
     {
 211  0
         return namedConfigurations.keySet();
 212  
     }
 213  
 
 214  
     /**
 215  
      * Removes the configuration with the specified name.
 216  
      *
 217  
      * @param name the name of the configuration to be removed
 218  
      * @return the removed configuration (<b>null</b> if this configuration
 219  
      * was not found)
 220  
      */
 221  
     public Configuration removeConfiguration(String name)
 222  
     {
 223  0
         Configuration conf = getConfiguration(name);
 224  0
         if (conf != null)
 225  
         {
 226  0
             removeConfiguration(conf);
 227  
         }
 228  0
         return conf;
 229  
     }
 230  
 
 231  
     /**
 232  
      * Removes the specified configuration from this combined configuration.
 233  
      *
 234  
      * @param config the configuration to be removed
 235  
      * @return a flag whether this configuration was found and could be removed
 236  
      */
 237  
     public boolean removeConfiguration(Configuration config)
 238  
     {
 239  0
         for (int index = 0; index < getNumberOfConfigurations(); index++)
 240  
         {
 241  0
             if (((ConfigData) configurations.get(index)).getConfiguration() == config)
 242  
             {
 243  0
                 removeConfigurationAt(index);
 244  
 
 245  
             }
 246  
         }
 247  
 
 248  0
         return super.removeConfiguration(config);
 249  
     }
 250  
 
 251  
     /**
 252  
      * Removes the configuration at the specified index.
 253  
      *
 254  
      * @param index the index
 255  
      * @return the removed configuration
 256  
      */
 257  
     public Configuration removeConfigurationAt(int index)
 258  
     {
 259  0
         ConfigData cd = (ConfigData) configurations.remove(index);
 260  0
         if (cd.getName() != null)
 261  
         {
 262  0
             namedConfigurations.remove(cd.getName());
 263  
         }
 264  0
         return super.removeConfigurationAt(index);
 265  
     }
 266  
     /**
 267  
      * Returns the configuration root node of this combined configuration. This
 268  
      * method will construct a combined node structure using the current node
 269  
      * combiner if necessary.
 270  
      *
 271  
      * @return the combined root node
 272  
      */
 273  
     public ConfigurationNode getRootNode()
 274  
     {
 275  0
         return getCurrentConfig().getRootNode();
 276  
     }
 277  
 
 278  
     public void setRootNode(ConfigurationNode rootNode)
 279  
     {
 280  1
         if (configs != null)
 281  
         {
 282  0
             this.getCurrentConfig().setRootNode(rootNode);
 283  
         }
 284  
         else
 285  
         {
 286  1
             super.setRootNode(rootNode);
 287  
         }
 288  1
     }
 289  
 
 290  
     public void addProperty(String key, Object value)
 291  
     {
 292  0
         this.getCurrentConfig().addProperty(key, value);
 293  0
     }
 294  
 
 295  
     public void clear()
 296  
     {
 297  1
         if (configs != null)
 298  
         {
 299  0
             this.getCurrentConfig().clear();
 300  
         }
 301  1
     }
 302  
 
 303  
     public void clearProperty(String key)
 304  
     {
 305  0
         this.getCurrentConfig().clearProperty(key);
 306  0
     }
 307  
 
 308  
     public boolean containsKey(String key)
 309  
     {
 310  0
         return this.getCurrentConfig().containsKey(key);
 311  
     }
 312  
 
 313  
     public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
 314  
     {
 315  0
         return this.getCurrentConfig().getBigDecimal(key, defaultValue);
 316  
     }
 317  
 
 318  
     public BigDecimal getBigDecimal(String key)
 319  
     {
 320  0
         return this.getCurrentConfig().getBigDecimal(key);
 321  
     }
 322  
 
 323  
     public BigInteger getBigInteger(String key, BigInteger defaultValue)
 324  
     {
 325  0
         return this.getCurrentConfig().getBigInteger(key, defaultValue);
 326  
     }
 327  
 
 328  
     public BigInteger getBigInteger(String key)
 329  
     {
 330  0
         return this.getCurrentConfig().getBigInteger(key);
 331  
     }
 332  
 
 333  
     public boolean getBoolean(String key, boolean defaultValue)
 334  
     {
 335  0
         return this.getCurrentConfig().getBoolean(key, defaultValue);
 336  
     }
 337  
 
 338  
     public Boolean getBoolean(String key, Boolean defaultValue)
 339  
     {
 340  0
         return this.getCurrentConfig().getBoolean(key, defaultValue);
 341  
     }
 342  
 
 343  
     public boolean getBoolean(String key)
 344  
     {
 345  0
         return this.getCurrentConfig().getBoolean(key);
 346  
     }
 347  
 
 348  
     public byte getByte(String key, byte defaultValue)
 349  
     {
 350  0
         return this.getCurrentConfig().getByte(key, defaultValue);
 351  
     }
 352  
 
 353  
     public Byte getByte(String key, Byte defaultValue)
 354  
     {
 355  0
         return this.getCurrentConfig().getByte(key, defaultValue);
 356  
     }
 357  
 
 358  
     public byte getByte(String key)
 359  
     {
 360  0
         return this.getCurrentConfig().getByte(key);
 361  
     }
 362  
 
 363  
     public double getDouble(String key, double defaultValue)
 364  
     {
 365  0
         return this.getCurrentConfig().getDouble(key, defaultValue);
 366  
     }
 367  
 
 368  
     public Double getDouble(String key, Double defaultValue)
 369  
     {
 370  0
         return this.getCurrentConfig().getDouble(key, defaultValue);
 371  
     }
 372  
 
 373  
     public double getDouble(String key)
 374  
     {
 375  0
         return this.getCurrentConfig().getDouble(key);
 376  
     }
 377  
 
 378  
     public float getFloat(String key, float defaultValue)
 379  
     {
 380  0
         return this.getCurrentConfig().getFloat(key, defaultValue);
 381  
     }
 382  
 
 383  
     public Float getFloat(String key, Float defaultValue)
 384  
     {
 385  0
         return this.getCurrentConfig().getFloat(key, defaultValue);
 386  
     }
 387  
 
 388  
     public float getFloat(String key)
 389  
     {
 390  0
         return this.getCurrentConfig().getFloat(key);
 391  
     }
 392  
 
 393  
     public int getInt(String key, int defaultValue)
 394  
     {
 395  0
         return this.getCurrentConfig().getInt(key, defaultValue);
 396  
     }
 397  
 
 398  
     public int getInt(String key)
 399  
     {
 400  4
         return this.getCurrentConfig().getInt(key);
 401  
     }
 402  
 
 403  
     public Integer getInteger(String key, Integer defaultValue)
 404  
     {
 405  0
         return this.getCurrentConfig().getInteger(key, defaultValue);
 406  
     }
 407  
 
 408  
     public Iterator getKeys()
 409  
     {
 410  0
         return this.getCurrentConfig().getKeys();
 411  
     }
 412  
 
 413  
     public Iterator getKeys(String prefix)
 414  
     {
 415  0
         return this.getCurrentConfig().getKeys(prefix);
 416  
     }
 417  
 
 418  
     public List getList(String key, List defaultValue)
 419  
     {
 420  0
         return this.getCurrentConfig().getList(key, defaultValue);
 421  
     }
 422  
 
 423  
     public List getList(String key)
 424  
     {
 425  0
         return this.getCurrentConfig().getList(key);
 426  
     }
 427  
 
 428  
     public long getLong(String key, long defaultValue)
 429  
     {
 430  0
         return this.getCurrentConfig().getLong(key, defaultValue);
 431  
     }
 432  
 
 433  
     public Long getLong(String key, Long defaultValue)
 434  
     {
 435  0
         return this.getCurrentConfig().getLong(key, defaultValue);
 436  
     }
 437  
 
 438  
     public long getLong(String key)
 439  
     {
 440  0
         return this.getCurrentConfig().getLong(key);
 441  
     }
 442  
 
 443  
     public Properties getProperties(String key)
 444  
     {
 445  0
         return this.getCurrentConfig().getProperties(key);
 446  
     }
 447  
 
 448  
     public Object getProperty(String key)
 449  
     {
 450  0
         return this.getCurrentConfig().getProperty(key);
 451  
     }
 452  
 
 453  
     public short getShort(String key, short defaultValue)
 454  
     {
 455  0
         return this.getCurrentConfig().getShort(key, defaultValue);
 456  
     }
 457  
 
 458  
     public Short getShort(String key, Short defaultValue)
 459  
     {
 460  0
         return this.getCurrentConfig().getShort(key, defaultValue);
 461  
     }
 462  
 
 463  
     public short getShort(String key)
 464  
     {
 465  0
         return this.getCurrentConfig().getShort(key);
 466  
     }
 467  
 
 468  
     public String getString(String key, String defaultValue)
 469  
     {
 470  0
         return this.getCurrentConfig().getString(key, defaultValue);
 471  
     }
 472  
 
 473  
     public String getString(String key)
 474  
     {
 475  0
         return this.getCurrentConfig().getString(key);
 476  
     }
 477  
 
 478  
     public String[] getStringArray(String key)
 479  
     {
 480  0
         return this.getCurrentConfig().getStringArray(key);
 481  
     }
 482  
 
 483  
     public boolean isEmpty()
 484  
     {
 485  0
         return this.getCurrentConfig().isEmpty();
 486  
     }
 487  
 
 488  
     public void setProperty(String key, Object value)
 489  
     {
 490  0
         if (configs != null)
 491  
         {
 492  0
             this.getCurrentConfig().setProperty(key, value);
 493  
         }
 494  0
     }
 495  
 
 496  
     public Configuration subset(String prefix)
 497  
     {
 498  0
         return this.getCurrentConfig().subset(prefix);
 499  
     }
 500  
 
 501  
     public Node getRoot()
 502  
     {
 503  0
         return this.getCurrentConfig().getRoot();
 504  
     }
 505  
 
 506  
     public void setRoot(Node node)
 507  
     {
 508  0
         if (configs != null)
 509  
         {
 510  0
             this.getCurrentConfig().setRoot(node);
 511  
         }
 512  
         else
 513  
         {
 514  0
             super.setRoot(node);
 515  
         }
 516  0
     }
 517  
 
 518  
     public ExpressionEngine getExpressionEngine()
 519  
     {
 520  4
         return super.getExpressionEngine();
 521  
     }
 522  
 
 523  
     public void setExpressionEngine(ExpressionEngine expressionEngine)
 524  
     {
 525  0
         super.setExpressionEngine(expressionEngine);
 526  0
     }
 527  
 
 528  
     public void addNodes(String key, Collection nodes)
 529  
     {
 530  0
         this.getCurrentConfig().addNodes(key, nodes);
 531  0
     }
 532  
 
 533  
     public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
 534  
     {
 535  0
         return this.getCurrentConfig().configurationAt(key, supportUpdates);
 536  
     }
 537  
 
 538  
     public SubnodeConfiguration configurationAt(String key)
 539  
     {
 540  0
         return this.getCurrentConfig().configurationAt(key);
 541  
     }
 542  
 
 543  
     public List configurationsAt(String key)
 544  
     {
 545  0
         return this.getCurrentConfig().configurationsAt(key);
 546  
     }
 547  
 
 548  
     public void clearTree(String key)
 549  
     {
 550  0
         this.getCurrentConfig().clearTree(key);
 551  0
     }
 552  
 
 553  
     public int getMaxIndex(String key)
 554  
     {
 555  0
         return this.getCurrentConfig().getMaxIndex(key);
 556  
     }
 557  
 
 558  
     public Configuration interpolatedConfiguration()
 559  
     {
 560  0
         return this.getCurrentConfig().interpolatedConfiguration();
 561  
     }
 562  
 
 563  
 
 564  
     /**
 565  
      * Returns the configuration source, in which the specified key is defined.
 566  
      * This method will determine the configuration node that is identified by
 567  
      * the given key. The following constellations are possible:
 568  
      * <ul>
 569  
      * <li>If no node object is found for this key, <b>null</b> is returned.</li>
 570  
      * <li>If the key maps to multiple nodes belonging to different
 571  
      * configuration sources, a <code>IllegalArgumentException</code> is
 572  
      * thrown (in this case no unique source can be determined).</li>
 573  
      * <li>If exactly one node is found for the key, the (child) configuration
 574  
      * object, to which the node belongs is determined and returned.</li>
 575  
      * <li>For keys that have been added directly to this combined
 576  
      * configuration and that do not belong to the namespaces defined by
 577  
      * existing child configurations this configuration will be returned.</li>
 578  
      * </ul>
 579  
      *
 580  
      * @param key the key of a configuration property
 581  
      * @return the configuration, to which this property belongs or <b>null</b>
 582  
      * if the key cannot be resolved
 583  
      * @throws IllegalArgumentException if the key maps to multiple properties
 584  
      * and the source cannot be determined, or if the key is <b>null</b>
 585  
      */
 586  
     public Configuration getSource(String key)
 587  
     {
 588  0
         if (key == null)
 589  
         {
 590  0
             throw new IllegalArgumentException("Key must not be null!");
 591  
         }
 592  0
         return getCurrentConfig().getSource(key);
 593  
     }
 594  
 
 595  
     public void addConfigurationListener(ConfigurationListener l)
 596  
     {
 597  0
         super.addConfigurationListener(l);
 598  
 
 599  0
         Iterator iter = configs.values().iterator();
 600  0
         while (iter.hasNext())
 601  
         {
 602  0
             CombinedConfiguration config = (CombinedConfiguration) iter.next();
 603  0
             config.addConfigurationListener(l);
 604  
         }
 605  0
     }
 606  
 
 607  
     public boolean removeConfigurationListener(ConfigurationListener l)
 608  
     {
 609  0
         Iterator iter = configs.values().iterator();
 610  0
         while (iter.hasNext())
 611  
         {
 612  0
             CombinedConfiguration config = (CombinedConfiguration) iter.next();
 613  0
             config.removeConfigurationListener(l);
 614  
         }
 615  0
         return super.removeConfigurationListener(l);
 616  
     }
 617  
 
 618  
     public Collection getConfigurationListeners()
 619  
     {
 620  0
         return super.getConfigurationListeners();
 621  
     }
 622  
 
 623  
     public void clearConfigurationListeners()
 624  
     {
 625  0
         Iterator iter = configs.values().iterator();
 626  0
         while (iter.hasNext())
 627  
         {
 628  0
             CombinedConfiguration config = (CombinedConfiguration) iter.next();
 629  0
             config.clearConfigurationListeners();
 630  
         }
 631  0
         super.clearConfigurationListeners();
 632  0
     }
 633  
 
 634  
     public void addErrorListener(ConfigurationErrorListener l)
 635  
     {
 636  0
         Iterator iter = configs.values().iterator();
 637  0
         while (iter.hasNext())
 638  
         {
 639  0
             CombinedConfiguration config = (CombinedConfiguration) iter.next();
 640  0
             config.addErrorListener(l);
 641  
         }
 642  0
         super.addErrorListener(l);
 643  0
     }
 644  
 
 645  
     public boolean removeErrorListener(ConfigurationErrorListener l)
 646  
     {
 647  0
         Iterator iter = configs.values().iterator();
 648  0
         while (iter.hasNext())
 649  
         {
 650  0
             CombinedConfiguration config = (CombinedConfiguration) iter.next();
 651  0
             config.removeErrorListener(l);
 652  
         }
 653  0
         return super.removeErrorListener(l);
 654  
     }
 655  
 
 656  
     public void clearErrorListeners()
 657  
     {
 658  0
         Iterator iter = configs.values().iterator();
 659  0
         while (iter.hasNext())
 660  
         {
 661  0
             CombinedConfiguration config = (CombinedConfiguration) iter.next();
 662  0
             config.clearErrorListeners();
 663  
         }
 664  0
         super.clearErrorListeners();
 665  0
     }
 666  
 
 667  
     public Collection getErrorListeners()
 668  
     {
 669  0
         return super.getErrorListeners();
 670  
     }
 671  
 
 672  
 
 673  
 
 674  
     /**
 675  
      * Returns a copy of this object. This implementation performs a deep clone,
 676  
      * i.e. all contained configurations will be cloned, too. For this to work,
 677  
      * all contained configurations must be cloneable. Registered event
 678  
      * listeners won't be cloned. The clone will use the same node combiner than
 679  
      * the original.
 680  
      *
 681  
      * @return the copied object
 682  
      */
 683  
     public Object clone()
 684  
     {
 685  0
         return super.clone();
 686  
     }
 687  
 
 688  
 
 689  
 
 690  
     /**
 691  
      * Invalidates the current combined configuration. This means that the next time a
 692  
      * property is accessed the combined node structure must be re-constructed.
 693  
      * Invalidation of a combined configuration also means that an event of type
 694  
      * <code>EVENT_COMBINED_INVALIDATE</code> is fired. Note that while other
 695  
      * events most times appear twice (once before and once after an update),
 696  
      * this event is only fired once (after update).
 697  
      */
 698  
     public void invalidate()
 699  
     {
 700  0
         getCurrentConfig().invalidate();
 701  0
     }
 702  
 
 703  
     public void invalidateAll()
 704  
     {
 705  1
         if (configs == null)
 706  
         {
 707  1
             return;
 708  
         }
 709  0
         Iterator iter = configs.values().iterator();
 710  0
         while (iter.hasNext())
 711  
         {
 712  0
            CombinedConfiguration config = (CombinedConfiguration) iter.next();
 713  0
            config.invalidate();
 714  
         }
 715  0
     }
 716  
 
 717  
     /*
 718  
      * Don't allow resolveContainerStore to be called recursively.
 719  
      * @param key The key to resolve.
 720  
      * @return The value of the key.
 721  
      */
 722  
     protected Object resolveContainerStore(String key)
 723  
     {
 724  0
         if (((Boolean) recursive.get()).booleanValue())
 725  
         {
 726  0
             return null;
 727  
         }
 728  0
         recursive.set(Boolean.TRUE);
 729  
         try
 730  
         {
 731  0
             return super.resolveContainerStore(key);
 732  
         }
 733  
         finally
 734  
         {
 735  0
             recursive.set(Boolean.FALSE);
 736  
         }
 737  
     }
 738  
 
 739  
     private CombinedConfiguration getCurrentConfig()
 740  
     {
 741  4
         String key = getSubstitutor().replace(keyPattern);
 742  
         CombinedConfiguration config;
 743  4
         synchronized (getNodeCombiner())
 744  
         {
 745  4
             config = (CombinedConfiguration) configs.get(key);
 746  4
             if (config == null)
 747  
             {
 748  4
                 config = new CombinedConfiguration(getNodeCombiner());
 749  4
                 config.setExpressionEngine(this.getExpressionEngine());
 750  4
                 Iterator iter = config.getErrorListeners().iterator();
 751  4
                 while (iter.hasNext())
 752  
                 {
 753  0
                     ConfigurationErrorListener listener = (ConfigurationErrorListener) iter.next();
 754  0
                     config.addErrorListener(listener);
 755  
                 }
 756  4
                 iter = config.getConfigurationListeners().iterator();
 757  4
                 while (iter.hasNext())
 758  
                 {
 759  0
                     ConfigurationListener listener = (ConfigurationListener) iter.next();
 760  0
                     config.addConfigurationListener(listener);
 761  
                 }
 762  4
                 config.setForceReloadCheck(isForceReloadCheck());
 763  4
                 iter = configurations.iterator();
 764  12
                 while (iter.hasNext())
 765  
                 {
 766  8
                     ConfigData data = (ConfigData) iter.next();
 767  8
                     config.addConfiguration(data.getConfiguration(), data.getName(),
 768  
                             data.getAt());
 769  
                 }
 770  4
                 configs.put(key, config);
 771  
             }
 772  4
         }
 773  4
         return config;
 774  
     }
 775  
 
 776  
     /**
 777  
      * Internal class that identifies each Configuration.
 778  
      */
 779  
     static class ConfigData
 780  
     {
 781  
         /** Stores a reference to the configuration. */
 782  
         private AbstractConfiguration configuration;
 783  
 
 784  
         /** Stores the name under which the configuration is stored. */
 785  
         private String name;
 786  
 
 787  
         /** Stores the at string.*/
 788  
         private String at;
 789  
 
 790  
                 /**
 791  
          * Creates a new instance of <code>ConfigData</code> and initializes
 792  
          * it.
 793  
          *
 794  
          * @param config the configuration
 795  
          * @param n the name
 796  
          * @param at the at position
 797  
          */
 798  
         public ConfigData(AbstractConfiguration config, String n, String at)
 799  2
         {
 800  2
             configuration = config;
 801  2
             name = n;
 802  2
             this.at = at;
 803  2
         }
 804  
 
 805  
                 /**
 806  
          * Returns the stored configuration.
 807  
          *
 808  
          * @return the configuration
 809  
          */
 810  
         public AbstractConfiguration getConfiguration()
 811  
         {
 812  8
             return configuration;
 813  
         }
 814  
 
 815  
         /**
 816  
          * Returns the configuration's name.
 817  
          *
 818  
          * @return the name
 819  
          */
 820  
         public String getName()
 821  
         {
 822  8
             return name;
 823  
         }
 824  
 
 825  
         /**
 826  
          * Returns the at position of this configuration.
 827  
          *
 828  
          * @return the at position
 829  
          */
 830  
         public String getAt()
 831  
         {
 832  8
             return at;
 833  
         }
 834  
 
 835  
     }
 836  
 }