1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration;
18
19 import java.util.Iterator;
20
21 import org.apache.commons.collections.Transformer;
22 import org.apache.commons.collections.iterators.TransformIterator;
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 * <code>{@link Configuration#subset(String)}</code> method should be used,
30 * which will return a correctly initialized instance.</p>
31 *
32 * @author Emmanuel Bourg
33 * @version $Revision$, $Date: 2005-10-05 21:36:15 +0200 (Wed, 05 Oct 2005) $
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 {
54 this.parent = parent;
55 this.prefix = prefix;
56 }
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 {
67 this.parent = parent;
68 this.prefix = prefix;
69 this.delimiter = delimiter;
70 }
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 if ("".equals(key) || key == null)
82 {
83 return prefix;
84 }
85 else
86 {
87 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 if (!key.startsWith(prefix))
101 {
102 throw new IllegalArgumentException("The parent key '" + key + "' is not in the subset.");
103 }
104 else
105 {
106 String modifiedKey = null;
107 if (key.length() == prefix.length())
108 {
109 modifiedKey = "";
110 }
111 else
112 {
113 int i = prefix.length() + (delimiter != null ? delimiter.length() : 0);
114 modifiedKey = key.substring(i);
115 }
116
117 return modifiedKey;
118 }
119 }
120
121 /***
122 * Return the parent configuation for this subset.
123 *
124 * @return the parent configuration
125 */
126 public Configuration getParent()
127 {
128 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 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 this.prefix = prefix;
149 }
150
151 /***
152 * {@inheritDoc}
153 */
154 public Configuration subset(String prefix)
155 {
156 return parent.subset(getParentKey(prefix));
157 }
158
159 /***
160 * {@inheritDoc}
161 */
162 public boolean isEmpty()
163 {
164 return !getKeys().hasNext();
165 }
166
167 /***
168 * {@inheritDoc}
169 */
170 public boolean containsKey(String key)
171 {
172 return parent.containsKey(getParentKey(key));
173 }
174
175 /***
176 * {@inheritDoc}
177 */
178 public void addPropertyDirect(String key, Object value)
179 {
180 parent.addProperty(getParentKey(key), value);
181 }
182
183 /***
184 * {@inheritDoc}
185 */
186 public void setProperty(String key, Object value)
187 {
188 parent.setProperty(getParentKey(key), value);
189 }
190
191 /***
192 * {@inheritDoc}
193 */
194 public void clearProperty(String key)
195 {
196 parent.clearProperty(getParentKey(key));
197 }
198
199 /***
200 * {@inheritDoc}
201 */
202 public Object getProperty(String key)
203 {
204 return parent.getProperty(getParentKey(key));
205 }
206
207 /***
208 * {@inheritDoc}
209 */
210 public Iterator getKeys(String prefix)
211 {
212 return new TransformIterator(parent.getKeys(getParentKey(prefix)), new Transformer()
213 {
214 public Object transform(Object obj)
215 {
216 return getChildKey((String) obj);
217 }
218 });
219 }
220
221 /***
222 * {@inheritDoc}
223 */
224 public Iterator getKeys()
225 {
226 return new TransformIterator(parent.getKeys(prefix), new Transformer()
227 {
228 public Object transform(Object obj)
229 {
230 return getChildKey((String) obj);
231 }
232 });
233 }
234
235 /***
236 * {@inheritDoc}
237 */
238 protected String interpolate(String base)
239 {
240 if (delimiter == null && "".equals(prefix))
241 {
242 return super.interpolate(base);
243 }
244 else
245 {
246 SubsetConfiguration config = new SubsetConfiguration(parent, "");
247 return config.interpolate(base);
248 }
249 }
250
251 /***
252 * {@inheritDoc}
253 *
254 * Change the behaviour of the parent configuration if it supports this feature.
255 */
256 public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
257 {
258 if (parent instanceof AbstractConfiguration)
259 {
260 ((AbstractConfiguration) parent).setThrowExceptionOnMissing(throwExceptionOnMissing);
261 }
262 else
263 {
264 super.setThrowExceptionOnMissing(throwExceptionOnMissing);
265 }
266 }
267
268 /***
269 * {@inheritDoc}
270 *
271 * The subset inherits this feature from its parent if it supports this feature.
272 */
273 public boolean isThrowExceptionOnMissing()
274 {
275 if (parent instanceof AbstractConfiguration)
276 {
277 return ((AbstractConfiguration) parent).isThrowExceptionOnMissing();
278 }
279 else
280 {
281 return super.isThrowExceptionOnMissing();
282 }
283 }
284 }