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: 439648 $, $Date: 2006-09-02 22:42:10 +0200 (Sa, 02 Sep 2006) $
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     /***
153      * {@inheritDoc}
154      */
155     public Configuration subset(String prefix)
156     {
157         return parent.subset(getParentKey(prefix));
158     }
159 
160     /***
161      * {@inheritDoc}
162      */
163     public boolean isEmpty()
164     {
165         return !getKeys().hasNext();
166     }
167 
168     /***
169      * {@inheritDoc}
170      */
171     public boolean containsKey(String key)
172     {
173         return parent.containsKey(getParentKey(key));
174     }
175 
176     /***
177      * {@inheritDoc}
178      */
179     public void addPropertyDirect(String key, Object value)
180     {
181         parent.addProperty(getParentKey(key), value);
182     }
183 
184     /***
185      * {@inheritDoc}
186      */
187     public void setProperty(String key, Object value)
188     {
189         parent.setProperty(getParentKey(key), value);
190     }
191 
192     /***
193      * {@inheritDoc}
194      */
195     public void clearProperty(String key)
196     {
197         parent.clearProperty(getParentKey(key));
198     }
199 
200     /***
201      * {@inheritDoc}
202      */
203     public Object getProperty(String key)
204     {
205         return parent.getProperty(getParentKey(key));
206     }
207 
208     /***
209      * {@inheritDoc}
210      */
211     public Iterator getKeys(String prefix)
212     {
213         return new TransformIterator(parent.getKeys(getParentKey(prefix)), new Transformer()
214         {
215             public Object transform(Object obj)
216             {
217                 return getChildKey((String) obj);
218             }
219         });
220     }
221 
222     /***
223      * {@inheritDoc}
224      */
225     public Iterator getKeys()
226     {
227         return new TransformIterator(parent.getKeys(prefix), new Transformer()
228         {
229             public Object transform(Object obj)
230             {
231                 return getChildKey((String) obj);
232             }
233         });
234     }
235 
236     /***
237      * {@inheritDoc}
238      */
239     protected String interpolate(String base)
240     {
241         if (delimiter == null && "".equals(prefix))
242         {
243             return super.interpolate(base);
244         }
245         else
246         {
247             SubsetConfiguration config = new SubsetConfiguration(parent, "");
248             return config.interpolate(base);
249         }
250     }
251 
252     /***
253      * {@inheritDoc}
254      *
255      * Change the behaviour of the parent configuration if it supports this feature.
256      */
257     public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
258     {
259         if (parent instanceof AbstractConfiguration)
260         {
261             ((AbstractConfiguration) parent).setThrowExceptionOnMissing(throwExceptionOnMissing);
262         }
263         else
264         {
265             super.setThrowExceptionOnMissing(throwExceptionOnMissing);
266         }
267     }
268 
269     /***
270      * {@inheritDoc}
271      *
272      * The subset inherits this feature from its parent if it supports this feature.
273      */
274     public boolean isThrowExceptionOnMissing()
275     {
276         if (parent instanceof AbstractConfiguration)
277         {
278             return ((AbstractConfiguration) parent).isThrowExceptionOnMissing();
279         }
280         else
281         {
282             return super.isThrowExceptionOnMissing();
283         }
284     }
285 }