Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
SubsetConfiguration |
|
| 1.7037037037037037;1,704 | ||||
SubsetConfiguration$SubsetIterator |
|
| 1.7037037037037037;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 | } |