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