Coverage Report - org.apache.commons.configuration.CompositeConfiguration
 
Classes in this File Line Coverage Branch Coverage Complexity
CompositeConfiguration
98%
112/114
100%
26/26
2,5
 
 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  
 
 18  
 package org.apache.commons.configuration;
 19  
 
 20  
 import java.util.ArrayList;
 21  
 import java.util.Collection;
 22  
 import java.util.Iterator;
 23  
 import java.util.LinkedList;
 24  
 import java.util.List;
 25  
 import java.util.ListIterator;
 26  
 
 27  
 /**
 28  
  * This Configuration class allows you to add multiple different types of Configuration
 29  
  * to this CompositeConfiguration.  If you add Configuration1, and then Configuration2,
 30  
  * any properties shared will mean that Configuration1 will be returned.
 31  
  * You can add multiple different types or the same type of properties file.
 32  
  * If Configuration1 doesn't have the property, then Configuration2 will be checked.
 33  
  *
 34  
  * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
 35  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 36  
  * @version $Id: CompositeConfiguration.java 494581 2007-01-09 21:14:20Z oheger $
 37  
  */
 38  
 public class CompositeConfiguration extends AbstractConfiguration
 39  
 implements Cloneable
 40  
 {
 41  
     /** List holding all the configuration */
 42  120
     private List configList = new LinkedList();
 43  
 
 44  
     /**
 45  
      * Configuration that holds in memory stuff.  Inserted as first so any
 46  
      * setProperty() override anything else added.
 47  
      */
 48  
     private Configuration inMemoryConfiguration;
 49  
 
 50  
     /**
 51  
      * Creates an empty CompositeConfiguration object which can then
 52  
      * be added some other Configuration files
 53  
      */
 54  
     public CompositeConfiguration()
 55  115
     {
 56  115
         clear();
 57  115
     }
 58  
 
 59  
     /**
 60  
      * Creates a CompositeConfiguration object with a specified in memory
 61  
      * configuration. This configuration will store any changes made to
 62  
      * the CompositeConfiguration.
 63  
      *
 64  
      * @param inMemoryConfiguration the in memory configuration to use
 65  
      */
 66  
     public CompositeConfiguration(Configuration inMemoryConfiguration)
 67  5
     {
 68  5
         configList.clear();
 69  5
         this.inMemoryConfiguration = inMemoryConfiguration;
 70  5
         configList.add(inMemoryConfiguration);
 71  5
     }
 72  
 
 73  
     /**
 74  
      * Create a CompositeConfiguration with an empty in memory configuration
 75  
      * and adds the collection of configurations specified.
 76  
      *
 77  
      * @param configurations the collection of configurations to add
 78  
      */
 79  
     public CompositeConfiguration(Collection configurations)
 80  
     {
 81  1
         this(new BaseConfiguration(), configurations);
 82  1
     }
 83  
 
 84  
     /**
 85  
      * Creates a CompositeConfiguration with a specified in memory
 86  
      * configuration, and then adds the given collection of configurations.
 87  
      *
 88  
      * @param inMemoryConfiguration the in memory configuration to use
 89  
      * @param configurations        the collection of configurations to add
 90  
      */
 91  
     public CompositeConfiguration(Configuration inMemoryConfiguration, Collection configurations)
 92  
     {
 93  1
         this(inMemoryConfiguration);
 94  
 
 95  1
         if (configurations != null)
 96  
         {
 97  1
             Iterator it = configurations.iterator();
 98  5
             while (it.hasNext())
 99  
             {
 100  3
                 addConfiguration((Configuration) it.next());
 101  
             }
 102  
         }
 103  1
     }
 104  
 
 105  
     /**
 106  
      * Add a configuration.
 107  
      *
 108  
      * @param config the configuration to add
 109  
      */
 110  
     public void addConfiguration(Configuration config)
 111  
     {
 112  156
         if (!configList.contains(config))
 113  
         {
 114  
             // As the inMemoryConfiguration contains all manually added keys,
 115  
             // we must make sure that it is always last. "Normal", non composed
 116  
             // configuration add their keys at the end of the configuration and
 117  
             // we want to mimic this behaviour.
 118  154
             configList.add(configList.indexOf(inMemoryConfiguration), config);
 119  
 
 120  154
             if (config instanceof AbstractConfiguration)
 121  
             {
 122  154
                 ((AbstractConfiguration) config).setThrowExceptionOnMissing(isThrowExceptionOnMissing());
 123  
             }
 124  
         }
 125  156
     }
 126  
 
 127  
     /**
 128  
      * Remove a configuration. The in memory configuration cannot be removed.
 129  
      *
 130  
      * @param config The configuration to remove
 131  
      */
 132  
     public void removeConfiguration(Configuration config)
 133  
     {
 134  
         // Make sure that you can't remove the inMemoryConfiguration from
 135  
         // the CompositeConfiguration object
 136  4
         if (!config.equals(inMemoryConfiguration))
 137  
         {
 138  2
             configList.remove(config);
 139  
         }
 140  4
     }
 141  
 
 142  
     /**
 143  
      * Return the number of configurations.
 144  
      *
 145  
      * @return the number of configuration
 146  
      */
 147  
     public int getNumberOfConfigurations()
 148  
     {
 149  31
         return configList.size();
 150  
     }
 151  
 
 152  
     /**
 153  
      * Remove all configuration reinitialize the in memory configuration.
 154  
      */
 155  
     public void clear()
 156  
     {
 157  125
         configList.clear();
 158  
         // recreate the in memory configuration
 159  125
         inMemoryConfiguration = new BaseConfiguration();
 160  125
         ((BaseConfiguration) inMemoryConfiguration).setThrowExceptionOnMissing(isThrowExceptionOnMissing());
 161  125
         ((BaseConfiguration) inMemoryConfiguration).setListDelimiter(getListDelimiter());
 162  125
         ((BaseConfiguration) inMemoryConfiguration).setDelimiterParsingDisabled(isDelimiterParsingDisabled());
 163  125
         configList.add(inMemoryConfiguration);
 164  125
     }
 165  
 
 166  
     /**
 167  
      * Add this property to the inmemory Configuration.
 168  
      *
 169  
      * @param key The Key to add the property to.
 170  
      * @param token The Value to add.
 171  
      */
 172  
     protected void addPropertyDirect(String key, Object token)
 173  
     {
 174  33
         inMemoryConfiguration.addProperty(key, token);
 175  33
     }
 176  
 
 177  
     /**
 178  
      * Read property from underlying composite
 179  
      *
 180  
      * @param key key to use for mapping
 181  
      *
 182  
      * @return object associated with the given configuration key.
 183  
      */
 184  
     public Object getProperty(String key)
 185  
     {
 186  133
         Configuration firstMatchingConfiguration = null;
 187  359
         for (Iterator i = configList.iterator(); i.hasNext();)
 188  
         {
 189  201
             Configuration config = (Configuration) i.next();
 190  201
             if (config.containsKey(key))
 191  
             {
 192  108
                 firstMatchingConfiguration = config;
 193  108
                 break;
 194  
             }
 195  
         }
 196  
 
 197  133
         if (firstMatchingConfiguration != null)
 198  
         {
 199  108
             return firstMatchingConfiguration.getProperty(key);
 200  
         }
 201  
         else
 202  
         {
 203  25
             return null;
 204  
         }
 205  
     }
 206  
 
 207  
     /**
 208  
      * {@inheritDoc}
 209  
      */
 210  
     public Iterator getKeys()
 211  
     {
 212  14
         List keys = new ArrayList();
 213  52
         for (Iterator i = configList.iterator(); i.hasNext();)
 214  
         {
 215  24
             Configuration config = (Configuration) i.next();
 216  
 
 217  24
             Iterator j = config.getKeys();
 218  174
             while (j.hasNext())
 219  
             {
 220  126
                 String key = (String) j.next();
 221  126
                 if (!keys.contains(key))
 222  
                 {
 223  125
                     keys.add(key);
 224  
                 }
 225  
             }
 226  
         }
 227  
 
 228  14
         return keys.iterator();
 229  
     }
 230  
 
 231  
     /**
 232  
      * {@inheritDoc}
 233  
      */
 234  
     public Iterator getKeys(String key)
 235  
     {
 236  9
         List keys = new ArrayList();
 237  40
         for (Iterator i = configList.iterator(); i.hasNext();)
 238  
         {
 239  22
             Configuration config = (Configuration) i.next();
 240  
 
 241  22
             Iterator j = config.getKeys(key);
 242  240
             while (j.hasNext())
 243  
             {
 244  196
                 String newKey = (String) j.next();
 245  196
                 if (!keys.contains(newKey))
 246  
                 {
 247  194
                     keys.add(newKey);
 248  
                 }
 249  
             }
 250  
         }
 251  
 
 252  9
         return keys.iterator();
 253  
     }
 254  
 
 255  
     /**
 256  
      * {@inheritDoc}
 257  
      */
 258  
     public boolean isEmpty()
 259  
     {
 260  4
         boolean isEmpty = true;
 261  8
         for (Iterator i = configList.iterator(); i.hasNext();)
 262  
         {
 263  4
             Configuration config = (Configuration) i.next();
 264  4
             if (!config.isEmpty())
 265  
             {
 266  4
                 return false;
 267  
             }
 268  
         }
 269  
 
 270  0
         return isEmpty;
 271  
     }
 272  
 
 273  
     /**
 274  
      * {@inheritDoc}
 275  
      */
 276  
     protected void clearPropertyDirect(String key)
 277  
     {
 278  67
         for (Iterator i = configList.iterator(); i.hasNext();)
 279  
         {
 280  35
             Configuration config = (Configuration) i.next();
 281  35
             config.clearProperty(key);
 282  
         }
 283  16
     }
 284  
 
 285  
     /**
 286  
      * {@inheritDoc}
 287  
      */
 288  
     public boolean containsKey(String key)
 289  
     {
 290  138
         for (Iterator i = configList.iterator(); i.hasNext();)
 291  
         {
 292  72
             Configuration config = (Configuration) i.next();
 293  72
             if (config.containsKey(key))
 294  
             {
 295  44
                 return true;
 296  
             }
 297  
         }
 298  11
         return false;
 299  
     }
 300  
 
 301  
     /**
 302  
      * {@inheritDoc}
 303  
      */
 304  
     public List getList(String key, List defaultValue)
 305  
     {
 306  46
         List list = new ArrayList();
 307  
 
 308  
         // add all elements from the first configuration containing the requested key
 309  46
         Iterator it = configList.iterator();
 310  153
         while (it.hasNext() && list.isEmpty())
 311  
         {
 312  61
             Configuration config = (Configuration) it.next();
 313  61
             if (config != inMemoryConfiguration && config.containsKey(key))
 314  
             {
 315  32
                 list.addAll(config.getList(key));
 316  
             }
 317  
         }
 318  
 
 319  
         // add all elements from the in memory configuration
 320  46
         list.addAll(inMemoryConfiguration.getList(key));
 321  
 
 322  46
         if (list.isEmpty())
 323  
         {
 324  5
             return defaultValue;
 325  
         }
 326  
 
 327  41
         ListIterator lit = list.listIterator();
 328  161
         while (lit.hasNext())
 329  
         {
 330  79
             lit.set(interpolate(lit.next()));
 331  
         }
 332  
 
 333  41
         return list;
 334  
     }
 335  
 
 336  
     /**
 337  
      * {@inheritDoc}
 338  
      */
 339  
     public String[] getStringArray(String key)
 340  
     {
 341  13
         List list = getList(key);
 342  
 
 343  
         // interpolate the strings
 344  13
         String[] tokens = new String[list.size()];
 345  
 
 346  33
         for (int i = 0; i < tokens.length; i++)
 347  
         {
 348  20
             tokens[i] = interpolate(String.valueOf(list.get(i)));
 349  
         }
 350  
 
 351  13
         return tokens;
 352  
     }
 353  
 
 354  
     /**
 355  
      * Return the configuration at the specified index.
 356  
      *
 357  
      * @param index The index of the configuration to retrieve
 358  
      * @return the configuration at this index
 359  
      */
 360  
     public Configuration getConfiguration(int index)
 361  
     {
 362  29
         return (Configuration) configList.get(index);
 363  
     }
 364  
 
 365  
     /**
 366  
      * Returns the &quot;in memory configuration&quot;. In this configuration
 367  
      * changes are stored.
 368  
      *
 369  
      * @return the in memory configuration
 370  
      */
 371  
     public Configuration getInMemoryConfiguration()
 372  
     {
 373  11
         return inMemoryConfiguration;
 374  
     }
 375  
 
 376  
     /**
 377  
      * Returns a copy of this object. This implementation will create a deep
 378  
      * clone, i.e. all configurations contained in this composite will also be
 379  
      * cloned. This only works if all contained configurations support cloning;
 380  
      * otherwise a runtime exception will be thrown. Registered event handlers
 381  
      * won't get cloned.
 382  
      *
 383  
      * @return the copy
 384  
      * @since 1.3
 385  
      */
 386  
     public Object clone()
 387  
     {
 388  
         try
 389  
         {
 390  3
             CompositeConfiguration copy = (CompositeConfiguration) super
 391  
                     .clone();
 392  3
             copy.clearConfigurationListeners();
 393  3
             copy.configList = new LinkedList();
 394  3
             copy.inMemoryConfiguration = ConfigurationUtils
 395  
                     .cloneConfiguration(getInMemoryConfiguration());
 396  3
             copy.configList.add(copy.inMemoryConfiguration);
 397  
 
 398  5
             for (int i = 0; i < getNumberOfConfigurations(); i++)
 399  
             {
 400  3
                 Configuration config = getConfiguration(i);
 401  3
                 if (config != getInMemoryConfiguration())
 402  
                 {
 403  1
                     copy.addConfiguration(ConfigurationUtils
 404  
                             .cloneConfiguration(config));
 405  
                 }
 406  
             }
 407  
 
 408  2
             return copy;
 409  
         }
 410  
         catch (CloneNotSupportedException cnex)
 411  
         {
 412  
             // cannot happen
 413  0
             throw new ConfigurationRuntimeException(cnex);
 414  
         }
 415  
     }
 416  
 
 417  
     /**
 418  
      * Sets a flag whether added values for string properties should be checked
 419  
      * for the list delimiter. This implementation ensures that the in memory
 420  
      * configuration is correctly initialized.
 421  
      *
 422  
      * @param delimiterParsingDisabled the new value of the flag
 423  
      * @since 1.4
 424  
      */
 425  
     public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled)
 426  
     {
 427  2
         ((BaseConfiguration) getInMemoryConfiguration())
 428  
                 .setDelimiterParsingDisabled(delimiterParsingDisabled);
 429  2
         super.setDelimiterParsingDisabled(delimiterParsingDisabled);
 430  2
     }
 431  
 
 432  
     /**
 433  
      * Sets the character that is used as list delimiter. This implementation
 434  
      * ensures that the in memory configuration is correctly initialized.
 435  
      *
 436  
      * @param listDelimiter the new list delimiter character
 437  
      * @since 1.4
 438  
      */
 439  
     public void setListDelimiter(char listDelimiter)
 440  
     {
 441  2
         ((BaseConfiguration) getInMemoryConfiguration())
 442  
                 .setListDelimiter(listDelimiter);
 443  2
         super.setListDelimiter(listDelimiter);
 444  2
     }
 445  
 }