View Javadoc

1   /*
2    * Copyright 2004-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.configuration;
18  
19  import java.util.Iterator;
20  
21  import org.apache.commons.collections.Transformer;
22  import org.apache.commons.collections.iterators.TransformIterator;
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   * <code>{@link Configuration#subset(String)}</code> method should be used,
30   * which will return a correctly initialized instance.</p>
31   *
32   * @author Emmanuel Bourg
33   * @version $Revision$, $Date: 2005-10-05 21:36:15 +0200 (Wed, 05 Oct 2005) $
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      {
54          this.parent = parent;
55          this.prefix = prefix;
56      }
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      {
67          this.parent = parent;
68          this.prefix = prefix;
69          this.delimiter = delimiter;
70      }
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          if ("".equals(key) || key == null)
82          {
83              return prefix;
84          }
85          else
86          {
87              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         if (!key.startsWith(prefix))
101         {
102             throw new IllegalArgumentException("The parent key '" + key + "' is not in the subset.");
103         }
104         else
105         {
106             String modifiedKey = null;
107             if (key.length() == prefix.length())
108             {
109                 modifiedKey = "";
110             }
111             else
112             {
113                 int i = prefix.length() + (delimiter != null ? delimiter.length() : 0);
114                 modifiedKey = key.substring(i);
115             }
116 
117             return modifiedKey;
118         }
119     }
120 
121     /***
122      * Return the parent configuation for this subset.
123      *
124      * @return the parent configuration
125      */
126     public Configuration getParent()
127     {
128         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         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         this.prefix = prefix;
149     }
150 
151     /***
152      * {@inheritDoc}
153      */
154     public Configuration subset(String prefix)
155     {
156         return parent.subset(getParentKey(prefix));
157     }
158 
159     /***
160      * {@inheritDoc}
161      */
162     public boolean isEmpty()
163     {
164         return !getKeys().hasNext();
165     }
166 
167     /***
168      * {@inheritDoc}
169      */
170     public boolean containsKey(String key)
171     {
172         return parent.containsKey(getParentKey(key));
173     }
174 
175     /***
176      * {@inheritDoc}
177      */
178     public void addPropertyDirect(String key, Object value)
179     {
180         parent.addProperty(getParentKey(key), value);
181     }
182 
183     /***
184      * {@inheritDoc}
185      */
186     public void setProperty(String key, Object value)
187     {
188         parent.setProperty(getParentKey(key), value);
189     }
190 
191     /***
192      * {@inheritDoc}
193      */
194     public void clearProperty(String key)
195     {
196         parent.clearProperty(getParentKey(key));
197     }
198 
199     /***
200      * {@inheritDoc}
201      */
202     public Object getProperty(String key)
203     {
204         return parent.getProperty(getParentKey(key));
205     }
206 
207     /***
208      * {@inheritDoc}
209      */
210     public Iterator getKeys(String prefix)
211     {
212         return new TransformIterator(parent.getKeys(getParentKey(prefix)), new Transformer()
213         {
214             public Object transform(Object obj)
215             {
216                 return getChildKey((String) obj);
217             }
218         });
219     }
220 
221     /***
222      * {@inheritDoc}
223      */
224     public Iterator getKeys()
225     {
226         return new TransformIterator(parent.getKeys(prefix), new Transformer()
227         {
228             public Object transform(Object obj)
229             {
230                 return getChildKey((String) obj);
231             }
232         });
233     }
234 
235     /***
236      * {@inheritDoc}
237      */
238     protected String interpolate(String base)
239     {
240         if (delimiter == null && "".equals(prefix))
241         {
242             return super.interpolate(base);
243         }
244         else
245         {
246             SubsetConfiguration config = new SubsetConfiguration(parent, "");
247             return config.interpolate(base);
248         }
249     }
250 
251     /***
252      * {@inheritDoc}
253      *
254      * Change the behaviour of the parent configuration if it supports this feature.
255      */
256     public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
257     {
258         if (parent instanceof AbstractConfiguration)
259         {
260             ((AbstractConfiguration) parent).setThrowExceptionOnMissing(throwExceptionOnMissing);
261         }
262         else
263         {
264             super.setThrowExceptionOnMissing(throwExceptionOnMissing);
265         }
266     }
267 
268     /***
269      * {@inheritDoc}
270      *
271      * The subset inherits this feature from its parent if it supports this feature.
272      */
273     public boolean isThrowExceptionOnMissing()
274     {
275         if (parent instanceof AbstractConfiguration)
276         {
277             return ((AbstractConfiguration) parent).isThrowExceptionOnMissing();
278         }
279         else
280         {
281             return super.isThrowExceptionOnMissing();
282         }
283     }
284 }