View Javadoc

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