1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration2;
18
19 import java.io.IOException;
20 import java.io.Reader;
21 import java.io.Writer;
22 import java.math.BigDecimal;
23 import java.math.BigInteger;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Objects;
29 import java.util.Properties;
30
31 import org.apache.commons.configuration2.event.Event;
32 import org.apache.commons.configuration2.event.EventListener;
33 import org.apache.commons.configuration2.event.EventType;
34 import org.apache.commons.configuration2.ex.ConfigurationException;
35 import org.apache.commons.configuration2.io.FileBased;
36 import org.apache.commons.configuration2.tree.ExpressionEngine;
37 import org.apache.commons.configuration2.tree.ImmutableNode;
38
39
40
41
42
43
44
45
46 public class PatternSubtreeConfigurationWrapper extends BaseHierarchicalConfiguration implements FileBasedConfiguration {
47
48 private final HierarchicalConfiguration<ImmutableNode> config;
49
50
51 private final String path;
52
53
54 private final boolean trailing;
55
56
57 private final boolean init;
58
59
60
61
62
63
64
65 public PatternSubtreeConfigurationWrapper(final HierarchicalConfiguration<ImmutableNode> config, final String path) {
66 this.config = Objects.requireNonNull(config, "config");
67 this.path = path;
68 this.trailing = path.endsWith("/");
69 this.init = true;
70 }
71
72 @Override
73 public <T extends Event> void addEventListener(final EventType<T> eventType, final EventListener<? super T> listener) {
74 getConfig().addEventListener(eventType, listener);
75 }
76
77 @Override
78 protected void addNodesInternal(final String key, final Collection<? extends ImmutableNode> nodes) {
79 getConfig().addNodes(key, nodes);
80 }
81
82 @Override
83 protected void addPropertyInternal(final String key, final Object value) {
84 config.addProperty(makePath(key), value);
85 }
86
87 @Override
88 public void clearErrorListeners() {
89 getConfig().clearErrorListeners();
90 }
91
92 @Override
93 public void clearEventListeners() {
94 getConfig().clearEventListeners();
95 }
96
97 @Override
98 protected void clearInternal() {
99 getConfig().clear();
100 }
101
102 @Override
103 protected void clearPropertyDirect(final String key) {
104 config.clearProperty(makePath(key));
105 }
106
107 @Override
108 protected Object clearTreeInternal(final String key) {
109 config.clearTree(makePath(key));
110 return Collections.emptyList();
111 }
112
113 @Override
114 public HierarchicalConfiguration<ImmutableNode> configurationAt(final String key) {
115 return config.configurationAt(makePath(key));
116 }
117
118 @Override
119 public HierarchicalConfiguration<ImmutableNode> configurationAt(final String key, final boolean supportUpdates) {
120 return config.configurationAt(makePath(key), supportUpdates);
121 }
122
123 @Override
124 public List<HierarchicalConfiguration<ImmutableNode>> configurationsAt(final String key) {
125 return config.configurationsAt(makePath(key));
126 }
127
128 @Override
129 protected boolean containsKeyInternal(final String key) {
130 return config.containsKey(makePath(key));
131 }
132
133
134
135
136
137
138 @Override
139 protected boolean containsValueInternal(final Object value) {
140 return config.containsValue(value);
141 }
142
143
144
145
146
147
148
149
150 private FileBased fetchFileBased() throws ConfigurationException {
151 if (!(config instanceof FileBased)) {
152 throw new ConfigurationException("Wrapped configuration does not implement FileBased!" + " No I/O operations are supported.");
153 }
154 return (FileBased) config;
155 }
156
157 @Override
158 public BigDecimal getBigDecimal(final String key) {
159 return config.getBigDecimal(makePath(key));
160 }
161
162 @Override
163 public BigDecimal getBigDecimal(final String key, final BigDecimal defaultValue) {
164 return config.getBigDecimal(makePath(key), defaultValue);
165 }
166
167 @Override
168 public BigInteger getBigInteger(final String key) {
169 return config.getBigInteger(makePath(key));
170 }
171
172 @Override
173 public BigInteger getBigInteger(final String key, final BigInteger defaultValue) {
174 return config.getBigInteger(makePath(key), defaultValue);
175 }
176
177 @Override
178 public boolean getBoolean(final String key) {
179 return config.getBoolean(makePath(key));
180 }
181
182 @Override
183 public boolean getBoolean(final String key, final boolean defaultValue) {
184 return config.getBoolean(makePath(key), defaultValue);
185 }
186
187 @Override
188 public Boolean getBoolean(final String key, final Boolean defaultValue) {
189 return config.getBoolean(makePath(key), defaultValue);
190 }
191
192 @Override
193 public byte getByte(final String key) {
194 return config.getByte(makePath(key));
195 }
196
197 @Override
198 public byte getByte(final String key, final byte defaultValue) {
199 return config.getByte(makePath(key), defaultValue);
200 }
201
202 @Override
203 public Byte getByte(final String key, final Byte defaultValue) {
204 return config.getByte(makePath(key), defaultValue);
205 }
206
207 private BaseHierarchicalConfiguration getConfig() {
208 return (BaseHierarchicalConfiguration) config.configurationAt(makePath());
209 }
210
211 @Override
212 public double getDouble(final String key) {
213 return config.getDouble(makePath(key));
214 }
215
216 @Override
217 public double getDouble(final String key, final double defaultValue) {
218 return config.getDouble(makePath(key), defaultValue);
219 }
220
221 @Override
222 public Double getDouble(final String key, final Double defaultValue) {
223 return config.getDouble(makePath(key), defaultValue);
224 }
225
226 @Override
227 public <T extends Event> Collection<EventListener<? super T>> getEventListeners(final EventType<T> eventType) {
228 return getConfig().getEventListeners(eventType);
229 }
230
231 @Override
232 public ExpressionEngine getExpressionEngine() {
233 return config.getExpressionEngine();
234 }
235
236 @Override
237 public float getFloat(final String key) {
238 return config.getFloat(makePath(key));
239 }
240
241 @Override
242 public float getFloat(final String key, final float defaultValue) {
243 return config.getFloat(makePath(key), defaultValue);
244 }
245
246 @Override
247 public Float getFloat(final String key, final Float defaultValue) {
248 return config.getFloat(makePath(key), defaultValue);
249 }
250
251 @Override
252 public int getInt(final String key) {
253 return config.getInt(makePath(key));
254 }
255
256 @Override
257 public int getInt(final String key, final int defaultValue) {
258 return config.getInt(makePath(key), defaultValue);
259 }
260
261 @Override
262 public Integer getInteger(final String key, final Integer defaultValue) {
263 return config.getInteger(makePath(key), defaultValue);
264 }
265
266 @Override
267 protected Iterator<String> getKeysInternal() {
268 return config.getKeys(makePath());
269 }
270
271 @Override
272 protected Iterator<String> getKeysInternal(final String prefix) {
273 return config.getKeys(makePath(prefix));
274 }
275
276 @Override
277 public List<Object> getList(final String key) {
278 return config.getList(makePath(key));
279 }
280
281 @Override
282 public List<Object> getList(final String key, final List<?> defaultValue) {
283 return config.getList(makePath(key), defaultValue);
284 }
285
286 @Override
287 public long getLong(final String key) {
288 return config.getLong(makePath(key));
289 }
290
291 @Override
292 public long getLong(final String key, final long defaultValue) {
293 return config.getLong(makePath(key), defaultValue);
294 }
295
296 @Override
297 public Long getLong(final String key, final Long defaultValue) {
298 return config.getLong(makePath(key), defaultValue);
299 }
300
301 @Override
302 protected int getMaxIndexInternal(final String key) {
303 return config.getMaxIndex(makePath(key));
304 }
305
306 @Override
307 public Properties getProperties(final String key) {
308 return config.getProperties(makePath(key));
309 }
310
311 @Override
312 protected Object getPropertyInternal(final String key) {
313 return config.getProperty(makePath(key));
314 }
315
316 @Override
317 public short getShort(final String key) {
318 return config.getShort(makePath(key));
319 }
320
321 @Override
322 public short getShort(final String key, final short defaultValue) {
323 return config.getShort(makePath(key), defaultValue);
324 }
325
326 @Override
327 public Short getShort(final String key, final Short defaultValue) {
328 return config.getShort(makePath(key), defaultValue);
329 }
330
331 @Override
332 public String getString(final String key) {
333 return config.getString(makePath(key));
334 }
335
336 @Override
337 public String getString(final String key, final String defaultValue) {
338 return config.getString(makePath(key), defaultValue);
339 }
340
341 @Override
342 public String[] getStringArray(final String key) {
343 return config.getStringArray(makePath(key));
344 }
345
346 @Override
347 public Configuration interpolatedConfiguration() {
348 return getConfig().interpolatedConfiguration();
349 }
350
351 @Override
352 protected boolean isEmptyInternal() {
353 return getConfig().isEmpty();
354 }
355
356 private String makePath() {
357 final String pathPattern = trailing ? path.substring(0, path.length() - 1) : path;
358 return substitute(pathPattern);
359 }
360
361
362
363
364 private String makePath(final String item) {
365 final String pathPattern;
366 if ((item.isEmpty() || item.startsWith("/")) && trailing) {
367 pathPattern = path.substring(0, path.length() - 1);
368 } else if (!item.startsWith("/") || !trailing) {
369 pathPattern = path + "/";
370 } else {
371 pathPattern = path;
372 }
373 return substitute(pathPattern) + item;
374 }
375
376 @Override
377 public void read(final Reader reader) throws ConfigurationException, IOException {
378 fetchFileBased().read(reader);
379 }
380
381 @Override
382 public <T extends Event> boolean removeEventListener(final EventType<T> eventType, final EventListener<? super T> listener) {
383 return getConfig().removeEventListener(eventType, listener);
384 }
385
386 @Override
387 public void setExpressionEngine(final ExpressionEngine expressionEngine) {
388 if (init) {
389 config.setExpressionEngine(expressionEngine);
390 } else {
391 super.setExpressionEngine(expressionEngine);
392 }
393 }
394
395 @Override
396 protected void setPropertyInternal(final String key, final Object value) {
397 getConfig().setProperty(key, value);
398 }
399
400 @Override
401 public Configuration subset(final String prefix) {
402 return getConfig().subset(prefix);
403 }
404
405
406
407
408
409
410
411
412 private String substitute(final String pattern) {
413 return Objects.toString(getInterpolator().interpolate(pattern), null);
414 }
415
416 @Override
417 public void write(final Writer writer) throws ConfigurationException, IOException {
418 fetchFileBased().write(writer);
419 }
420 }