Coverage Report - org.apache.commons.configuration.SubsetConfiguration
 
Classes in this File Line Coverage Branch Coverage Complexity
SubsetConfiguration
91%
55/60
71%
23/32
1,704
SubsetConfiguration$SubsetIterator
100%
8/8
N/A
1,704
 
 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.configuration.interpol.ConfigurationInterpolator;
 23  
 
 24  
 /**
 25  
  * <p>A subset of another configuration. The new Configuration object contains
 26  
  * every key from the parent Configuration that starts with prefix. The prefix
 27  
  * is removed from the keys in the subset.</p>
 28  
  * <p>It is usually not necessary to use this class directly. Instead the
 29  
  * {@link Configuration#subset(String)} method should be used,
 30  
  * which will return a correctly initialized instance.</p>
 31  
  *
 32  
  * @author Emmanuel Bourg
 33  
  * @version $Id: SubsetConfiguration.java 1210202 2011-12-04 20:30:46Z oheger $
 34  
  */
 35  
 public class SubsetConfiguration extends AbstractConfiguration
 36  
 {
 37  
     /** The parent configuration. */
 38  
     protected Configuration parent;
 39  
 
 40  
     /** The prefix used to select the properties. */
 41  
     protected String prefix;
 42  
 
 43  
     /** The prefix delimiter */
 44  
     protected String delimiter;
 45  
 
 46  
     /**
 47  
      * Create a subset of the specified configuration
 48  
      *
 49  
      * @param parent The parent configuration
 50  
      * @param prefix The prefix used to select the properties
 51  
      */
 52  
     public SubsetConfiguration(Configuration parent, String prefix)
 53  22
     {
 54  22
         this.parent = parent;
 55  22
         this.prefix = prefix;
 56  22
     }
 57  
 
 58  
     /**
 59  
      * Create a subset of the specified configuration
 60  
      *
 61  
      * @param parent    The parent configuration
 62  
      * @param prefix    The prefix used to select the properties
 63  
      * @param delimiter The prefix delimiter
 64  
      */
 65  
     public SubsetConfiguration(Configuration parent, String prefix, String delimiter)
 66  78
     {
 67  78
         this.parent = parent;
 68  78
         this.prefix = prefix;
 69  78
         this.delimiter = delimiter;
 70  78
     }
 71  
 
 72  
     /**
 73  
      * Return the key in the parent configuration associated to the specified
 74  
      * key in this subset.
 75  
      *
 76  
      * @param key The key in the subset.
 77  
      * @return the key as to be used by the parent
 78  
      */
 79  
     protected String getParentKey(String key)
 80  
     {
 81  112
         if ("".equals(key) || key == null)
 82  
         {
 83  4
             return prefix;
 84  
         }
 85  
         else
 86  
         {
 87  108
             return delimiter == null ? prefix + key : prefix + delimiter + key;
 88  
         }
 89  
     }
 90  
 
 91  
     /**
 92  
      * Return the key in the subset configuration associated to the specified
 93  
      * key in the parent configuration.
 94  
      *
 95  
      * @param key The key in the parent configuration.
 96  
      * @return the key in the context of this subset configuration
 97  
      */
 98  
     protected String getChildKey(String key)
 99  
     {
 100  108
         if (!key.startsWith(prefix))
 101  
         {
 102  0
             throw new IllegalArgumentException("The parent key '" + key + "' is not in the subset.");
 103  
         }
 104  
         else
 105  
         {
 106  108
             String modifiedKey = null;
 107  108
             if (key.length() == prefix.length())
 108  
             {
 109  4
                 modifiedKey = "";
 110  
             }
 111  
             else
 112  
             {
 113  104
                 int i = prefix.length() + (delimiter != null ? delimiter.length() : 0);
 114  104
                 modifiedKey = key.substring(i);
 115  
             }
 116  
 
 117  108
             return modifiedKey;
 118  
         }
 119  
     }
 120  
 
 121  
     /**
 122  
      * Return the parent configuration for this subset.
 123  
      *
 124  
      * @return the parent configuration
 125  
      */
 126  
     public Configuration getParent()
 127  
     {
 128  1
         return parent;
 129  
     }
 130  
 
 131  
     /**
 132  
      * Return the prefix used to select the properties in the parent configuration.
 133  
      *
 134  
      * @return the prefix used by this subset
 135  
      */
 136  
     public String getPrefix()
 137  
     {
 138  2
         return prefix;
 139  
     }
 140  
 
 141  
     /**
 142  
      * Set the prefix used to select the properties in the parent configuration.
 143  
      *
 144  
      * @param prefix the prefix
 145  
      */
 146  
     public void setPrefix(String prefix)
 147  
     {
 148  1
         this.prefix = prefix;
 149  1
     }
 150  
 
 151  
     @Override
 152  
     public Configuration subset(String prefix)
 153  
     {
 154  1
         return parent.subset(getParentKey(prefix));
 155  
     }
 156  
 
 157  
     public boolean isEmpty()
 158  
     {
 159  11
         return !getKeys().hasNext();
 160  
     }
 161  
 
 162  
     public boolean containsKey(String key)
 163  
     {
 164  20
         return parent.containsKey(getParentKey(key));
 165  
     }
 166  
 
 167  
     @Override
 168  
     public void addPropertyDirect(String key, Object value)
 169  
     {
 170  26
         parent.addProperty(getParentKey(key), value);
 171  26
     }
 172  
 
 173  
     @Override
 174  
     protected void clearPropertyDirect(String key)
 175  
     {
 176  12
         parent.clearProperty(getParentKey(key));
 177  12
     }
 178  
 
 179  
     public Object getProperty(String key)
 180  
     {
 181  48
         return parent.getProperty(getParentKey(key));
 182  
     }
 183  
 
 184  
     @Override
 185  
     public Iterator<String> getKeys(String prefix)
 186  
     {
 187  1
         return new SubsetIterator(parent.getKeys(getParentKey(prefix)));
 188  
     }
 189  
 
 190  
     public Iterator<String> getKeys()
 191  
     {
 192  33
         return new SubsetIterator(parent.getKeys(prefix));
 193  
     }
 194  
 
 195  
     @Override
 196  
     protected Object interpolate(Object base)
 197  
     {
 198  42
         if (delimiter == null && "".equals(prefix))
 199  
         {
 200  21
             return super.interpolate(base);
 201  
         }
 202  
         else
 203  
         {
 204  21
             SubsetConfiguration config = new SubsetConfiguration(parent, "");
 205  21
             ConfigurationInterpolator interpolator = config.getInterpolator();
 206  21
             getInterpolator().registerLocalLookups(interpolator);
 207  21
             if (parent instanceof AbstractConfiguration)
 208  
             {
 209  21
                 interpolator.setParentInterpolator(((AbstractConfiguration) parent).getInterpolator());
 210  
             }
 211  21
             return config.interpolate(base);
 212  
         }
 213  
     }
 214  
 
 215  
     @Override
 216  
     protected String interpolate(String base)
 217  
     {
 218  16
         return super.interpolate(base);
 219  
     }
 220  
 
 221  
     /**
 222  
      * {@inheritDoc}
 223  
      *
 224  
      * Change the behavior of the parent configuration if it supports this feature.
 225  
      */
 226  
     @Override
 227  
     public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
 228  
     {
 229  3
         if (parent instanceof AbstractConfiguration)
 230  
         {
 231  3
             ((AbstractConfiguration) parent).setThrowExceptionOnMissing(throwExceptionOnMissing);
 232  
         }
 233  
         else
 234  
         {
 235  0
             super.setThrowExceptionOnMissing(throwExceptionOnMissing);
 236  
         }
 237  3
     }
 238  
 
 239  
     /**
 240  
      * {@inheritDoc}
 241  
      *
 242  
      * The subset inherits this feature from its parent if it supports this feature.
 243  
      */
 244  
     @Override
 245  
     public boolean isThrowExceptionOnMissing()
 246  
     {
 247  2
         if (parent instanceof AbstractConfiguration)
 248  
         {
 249  2
             return ((AbstractConfiguration) parent).isThrowExceptionOnMissing();
 250  
         }
 251  
         else
 252  
         {
 253  0
             return super.isThrowExceptionOnMissing();
 254  
         }
 255  
     }
 256  
 
 257  
     /**
 258  
      * Returns the list delimiter. This property will be fetched from the parent
 259  
      * configuration if supported.
 260  
      *
 261  
      * @return the list delimiter
 262  
      * @since 1.4
 263  
      */
 264  
     @Override
 265  
     public char getListDelimiter()
 266  
     {
 267  24
         return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent)
 268  
                 .getListDelimiter()
 269  
                 : super.getListDelimiter();
 270  
     }
 271  
 
 272  
     /**
 273  
      * Sets the list delimiter. If the parent configuration supports this
 274  
      * feature, the delimiter will be set at the parent.
 275  
      *
 276  
      * @param delim the new list delimiter
 277  
      * @since 1.4
 278  
      */
 279  
     @Override
 280  
     public void setListDelimiter(char delim)
 281  
     {
 282  2
         if (parent instanceof AbstractConfiguration)
 283  
         {
 284  2
             ((AbstractConfiguration) parent).setListDelimiter(delim);
 285  
         }
 286  
         else
 287  
         {
 288  0
             super.setListDelimiter(delim);
 289  
         }
 290  2
     }
 291  
 
 292  
     /**
 293  
      * Returns a flag whether string properties should be checked for list
 294  
      * delimiter characters. This implementation ensures that this flag is kept
 295  
      * in sync with the parent configuration if this object supports this
 296  
      * feature.
 297  
      *
 298  
      * @return the delimiter parsing disabled flag
 299  
      * @since 1.4
 300  
      */
 301  
     @Override
 302  
     public boolean isDelimiterParsingDisabled()
 303  
     {
 304  25
         return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent)
 305  
                 .isDelimiterParsingDisabled()
 306  
                 : super.isDelimiterParsingDisabled();
 307  
     }
 308  
 
 309  
     /**
 310  
      * Sets a flag whether list parsing is disabled. This implementation will
 311  
      * also set the flag at the parent configuration if this object supports
 312  
      * this feature.
 313  
      *
 314  
      * @param delimiterParsingDisabled the delimiter parsing disabled flag
 315  
      * @since 1.4
 316  
      */
 317  
     @Override
 318  
     public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled)
 319  
     {
 320  2
         if (parent instanceof AbstractConfiguration)
 321  
         {
 322  2
             ((AbstractConfiguration) parent)
 323  
                     .setDelimiterParsingDisabled(delimiterParsingDisabled);
 324  
         }
 325  
         else
 326  
         {
 327  0
             super.setDelimiterParsingDisabled(delimiterParsingDisabled);
 328  
         }
 329  2
     }
 330  
 
 331  
 
 332  
     /**
 333  
      * A specialized iterator to be returned by the {@code getKeys()}
 334  
      * methods. This implementation wraps an iterator from the parent
 335  
      * configuration. The keys returned by this iterator are correspondingly
 336  
      * transformed.
 337  
      */
 338  104
     private class SubsetIterator implements Iterator<String>
 339  
     {
 340  
         /** Stores the wrapped iterator. */
 341  
         private final Iterator<String> parentIterator;
 342  
 
 343  
         /**
 344  
          * Creates a new instance of {@code SubsetIterator} and
 345  
          * initializes it with the parent iterator.
 346  
          *
 347  
          * @param it the iterator of the parent configuration
 348  
          */
 349  
         public SubsetIterator(Iterator<String> it)
 350  34
         {
 351  34
             parentIterator = it;
 352  34
         }
 353  
 
 354  
         /**
 355  
          * Checks whether there are more elements. Delegates to the parent
 356  
          * iterator.
 357  
          *
 358  
          * @return a flag whether there are more elements
 359  
          */
 360  
         public boolean hasNext()
 361  
         {
 362  132
             return parentIterator.hasNext();
 363  
         }
 364  
 
 365  
         /**
 366  
          * Returns the next element in the iteration. This is the next key from
 367  
          * the parent configuration, transformed to correspond to the point of
 368  
          * view of this subset configuration.
 369  
          *
 370  
          * @return the next element
 371  
          */
 372  
         public String next()
 373  
         {
 374  104
             return getChildKey(parentIterator.next());
 375  
         }
 376  
 
 377  
         /**
 378  
          * Removes the current element from the iteration. Delegates to the
 379  
          * parent iterator.
 380  
          */
 381  
         public void remove()
 382  
         {
 383  4
             parentIterator.remove();
 384  4
         }
 385  
     }
 386  
 }