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