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.Iterator;
    21
    22  import org.apache.commons.collections.Transformer;
    23  import org.apache.commons.collections.iterators.TransformIterator;
    24
    25  /***
    26   * <p>A subset of another configuration. The new Configuration object contains
    27   * every key from the parent Configuration that starts with prefix. The prefix
    28   * is removed from the keys in the subset.</p>
    29   * <p>It is usually not necessary to use this class directly. Instead the
    30   * <code>{@link Configuration#subset(String)}</code> method should be used,
    31   * which will return a correctly initialized instance.</p>
    32   *
    33   * @author Emmanuel Bourg
    34   * @version $Revision: 529531 $, $Date: 2007-04-17 10:52:41 +0200 (Di, 17 Apr 2007) $
    35   */
    36  public class SubsetConfiguration extends AbstractConfiguration
    37  {
    38      /*** The parent configuration. */
    39      protected Configuration parent;
    40
    41      /*** The prefix used to select the properties. */
    42      protected String prefix;
    43
    44      /*** The prefix delimiter */
    45      protected String delimiter;
    46
    47      /***
    48       * Create a subset of the specified configuration
    49       *
    50       * @param parent The parent configuration
    51       * @param prefix The prefix used to select the properties
    52       */
    53      public SubsetConfiguration(Configuration parent, String prefix)
    54      {
    55          this.parent = parent;
    56          this.prefix = prefix;
    57      }
    58
    59      /***
    60       * Create a subset of the specified configuration
    61       *
    62       * @param parent    The parent configuration
    63       * @param prefix    The prefix used to select the properties
    64       * @param delimiter The prefix delimiter
    65       */
    66      public SubsetConfiguration(Configuration parent, String prefix, String delimiter)
    67      {
    68          this.parent = parent;
    69          this.prefix = prefix;
    70          this.delimiter = delimiter;
    71      }
    72
    73      /***
    74       * Return the key in the parent configuration associated to the specified
    75       * key in this subset.
    76       *
    77       * @param key The key in the subset.
    78       * @return the key as to be used by the parent
    79       */
    80      protected String getParentKey(String key)
    81      {
    82          if ("".equals(key) || key == null)
    83          {
    84              return prefix;
    85          }
    86          else
    87          {
    88              return delimiter == null ? prefix + key : prefix + delimiter + key;
    89          }
    90      }
    91
    92      /***
    93       * Return the key in the subset configuration associated to the specified
    94       * key in the parent configuration.
    95       *
    96       * @param key The key in the parent configuration.
    97       * @return the key in the context of this subset configuration
    98       */
    99      protected String getChildKey(String key)
    100     {
    101         if (!key.startsWith(prefix))
    102         {
    103             throw new IllegalArgumentException("The parent key '" + key + "' is not in the subset.");
    104         }
    105         else
    106         {
    107             String modifiedKey = null;
    108             if (key.length() == prefix.length())
    109             {
    110                 modifiedKey = "";
    111             }
    112             else
    113             {
    114                 int i = prefix.length() + (delimiter != null ? delimiter.length() : 0);
    115                 modifiedKey = key.substring(i);
    116             }
    117
    118             return modifiedKey;
    119         }
    120     }
    121
    122     /***
    123      * Return the parent configuation for this subset.
    124      *
    125      * @return the parent configuration
    126      */
    127     public Configuration getParent()
    128     {
    129         return parent;
    130     }
    131
    132     /***
    133      * Return the prefix used to select the properties in the parent configuration.
    134      *
    135      * @return the prefix used by this subset
    136      */
    137     public String getPrefix()
    138     {
    139         return prefix;
    140     }
    141
    142     /***
    143      * Set the prefix used to select the properties in the parent configuration.
    144      *
    145      * @param prefix the prefix
    146      */
    147     public void setPrefix(String prefix)
    148     {
    149         this.prefix = prefix;
    150     }
    151
    152     public Configuration subset(String prefix)
    153     {
    154         return parent.subset(getParentKey(prefix));
    155     }
    156
    157     public boolean isEmpty()
    158     {
    159         return !getKeys().hasNext();
    160     }
    161
    162     public boolean containsKey(String key)
    163     {
    164         return parent.containsKey(getParentKey(key));
    165     }
    166
    167     public void addPropertyDirect(String key, Object value)
    168     {
    169         parent.addProperty(getParentKey(key), value);
    170     }
    171
    172     public void setProperty(String key, Object value)
    173     {
    174         parent.setProperty(getParentKey(key), value);
    175     }
    176
    177     public void clearProperty(String key)
    178     {
    179         parent.clearProperty(getParentKey(key));
    180     }
    181
    182     public Object getProperty(String key)
    183     {
    184         return parent.getProperty(getParentKey(key));
    185     }
    186
    187     public Iterator getKeys(String prefix)
    188     {
    189         return new TransformIterator(parent.getKeys(getParentKey(prefix)), new Transformer()
    190         {
    191             public Object transform(Object obj)
    192             {
    193                 return getChildKey((String) obj);
    194             }
    195         });
    196     }
    197
    198     public Iterator getKeys()
    199     {
    200         return new TransformIterator(parent.getKeys(prefix), new Transformer()
    201         {
    202             public Object transform(Object obj)
    203             {
    204                 return getChildKey((String) obj);
    205             }
    206         });
    207     }
    208
    209     protected Object interpolate(Object base)
    210     {
    211         if (delimiter == null && "".equals(prefix))
    212         {
    213             return super.interpolate(base);
    214         }
    215         else
    216         {
    217             SubsetConfiguration config = new SubsetConfiguration(parent, "");
    218             return config.interpolate(base);
    219         }
    220     }
    221
    222     protected String interpolate(String base)
    223     {
    224         return super.interpolate(base);
    225     }
    226
    227     /***
    228      * {@inheritDoc}
    229      *
    230      * Change the behaviour of the parent configuration if it supports this feature.
    231      */
    232     public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
    233     {
    234         if (parent instanceof AbstractConfiguration)
    235         {
    236             ((AbstractConfiguration) parent).setThrowExceptionOnMissing(throwExceptionOnMissing);
    237         }
    238         else
    239         {
    240             super.setThrowExceptionOnMissing(throwExceptionOnMissing);
    241         }
    242     }
    243
    244     /***
    245      * {@inheritDoc}
    246      *
    247      * The subset inherits this feature from its parent if it supports this feature.
    248      */
    249     public boolean isThrowExceptionOnMissing()
    250     {
    251         if (parent instanceof AbstractConfiguration)
    252         {
    253             return ((AbstractConfiguration) parent).isThrowExceptionOnMissing();
    254         }
    255         else
    256         {
    257             return super.isThrowExceptionOnMissing();
    258         }
    259     }
    260
    261     /***
    262      * Returns the list delimiter. This property will be fetched from the parent
    263      * configuration if supported.
    264      *
    265      * @return the list delimiter
    266      * @since 1.4
    267      */
    268     public char getListDelimiter()
    269     {
    270         return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent)
    271                 .getListDelimiter()
    272                 : super.getListDelimiter();
    273     }
    274
    275     /***
    276      * Sets the list delimiter. If the parent configuration supports this
    277      * feature, the delimiter will be set at the parent.
    278      *
    279      * @param delim the new list delimiter
    280      * @since 1.4
    281      */
    282     public void setListDelimiter(char delim)
    283     {
    284         if (parent instanceof AbstractConfiguration)
    285         {
    286             ((AbstractConfiguration) parent).setListDelimiter(delim);
    287         }
    288         else
    289         {
    290             super.setListDelimiter(delim);
    291         }
    292     }
    293
    294     /***
    295      * Returns a flag whether string properties should be checked for list
    296      * delimiter characters. This implementation ensures that this flag is kept
    297      * in sync with the parent configuration if this object supports this
    298      * feature.
    299      *
    300      * @return the delimiter parsing disabled flag
    301      * @since 1.4
    302      */
    303     public boolean isDelimiterParsingDisabled()
    304     {
    305         return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent)
    306                 .isDelimiterParsingDisabled()
    307                 : super.isDelimiterParsingDisabled();
    308     }
    309
    310     /***
    311      * Sets a flag whether list parsing is disabled. This implementation will
    312      * also set the flag at the parent configuration if this object supports
    313      * this feature.
    314      *
    315      * @param delimiterParsingDisabled the delimiter parsing disabled flag
    316      * @since 1.4
    317      */
    318     public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled)
    319     {
    320         if (parent instanceof AbstractConfiguration)
    321         {
    322             ((AbstractConfiguration) parent)
    323                     .setDelimiterParsingDisabled(delimiterParsingDisabled);
    324         }
    325         else
    326         {
    327             super.setDelimiterParsingDisabled(delimiterParsingDisabled);
    328         }
    329     }
    330 }