1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 }