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: 439648 $, $Date: 2006-09-02 22:42:10 +0200 (Sa, 02 Sep 2006) $
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 /***
153 * {@inheritDoc}
154 */
155 public Configuration subset(String prefix)
156 {
157 return parent.subset(getParentKey(prefix));
158 }
159
160 /***
161 * {@inheritDoc}
162 */
163 public boolean isEmpty()
164 {
165 return !getKeys().hasNext();
166 }
167
168 /***
169 * {@inheritDoc}
170 */
171 public boolean containsKey(String key)
172 {
173 return parent.containsKey(getParentKey(key));
174 }
175
176 /***
177 * {@inheritDoc}
178 */
179 public void addPropertyDirect(String key, Object value)
180 {
181 parent.addProperty(getParentKey(key), value);
182 }
183
184 /***
185 * {@inheritDoc}
186 */
187 public void setProperty(String key, Object value)
188 {
189 parent.setProperty(getParentKey(key), value);
190 }
191
192 /***
193 * {@inheritDoc}
194 */
195 public void clearProperty(String key)
196 {
197 parent.clearProperty(getParentKey(key));
198 }
199
200 /***
201 * {@inheritDoc}
202 */
203 public Object getProperty(String key)
204 {
205 return parent.getProperty(getParentKey(key));
206 }
207
208 /***
209 * {@inheritDoc}
210 */
211 public Iterator getKeys(String prefix)
212 {
213 return new TransformIterator(parent.getKeys(getParentKey(prefix)), new Transformer()
214 {
215 public Object transform(Object obj)
216 {
217 return getChildKey((String) obj);
218 }
219 });
220 }
221
222 /***
223 * {@inheritDoc}
224 */
225 public Iterator getKeys()
226 {
227 return new TransformIterator(parent.getKeys(prefix), new Transformer()
228 {
229 public Object transform(Object obj)
230 {
231 return getChildKey((String) obj);
232 }
233 });
234 }
235
236 /***
237 * {@inheritDoc}
238 */
239 protected String interpolate(String base)
240 {
241 if (delimiter == null && "".equals(prefix))
242 {
243 return super.interpolate(base);
244 }
245 else
246 {
247 SubsetConfiguration config = new SubsetConfiguration(parent, "");
248 return config.interpolate(base);
249 }
250 }
251
252 /***
253 * {@inheritDoc}
254 *
255 * Change the behaviour of the parent configuration if it supports this feature.
256 */
257 public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
258 {
259 if (parent instanceof AbstractConfiguration)
260 {
261 ((AbstractConfiguration) parent).setThrowExceptionOnMissing(throwExceptionOnMissing);
262 }
263 else
264 {
265 super.setThrowExceptionOnMissing(throwExceptionOnMissing);
266 }
267 }
268
269 /***
270 * {@inheritDoc}
271 *
272 * The subset inherits this feature from its parent if it supports this feature.
273 */
274 public boolean isThrowExceptionOnMissing()
275 {
276 if (parent instanceof AbstractConfiguration)
277 {
278 return ((AbstractConfiguration) parent).isThrowExceptionOnMissing();
279 }
280 else
281 {
282 return super.isThrowExceptionOnMissing();
283 }
284 }
285 }