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.ArrayList;
21 import java.util.Collection;
22 import java.util.Iterator;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.ListIterator;
26
27 /***
28 * This Configuration class allows you to add multiple different types of Configuration
29 * to this CompositeConfiguration. If you add Configuration1, and then Configuration2,
30 * any properties shared will mean that Configuration1 will be returned.
31 * You can add multiple different types or the same type of properties file.
32 * If Configuration1 doesn't have the property, then Configuration2 will be checked.
33 *
34 * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
35 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
36 * @version $Id: CompositeConfiguration.java 494581 2007-01-09 21:14:20Z oheger $
37 */
38 public class CompositeConfiguration extends AbstractConfiguration
39 implements Cloneable
40 {
41 /*** List holding all the configuration */
42 private List configList = new LinkedList();
43
44 /***
45 * Configuration that holds in memory stuff. Inserted as first so any
46 * setProperty() override anything else added.
47 */
48 private Configuration inMemoryConfiguration;
49
50 /***
51 * Creates an empty CompositeConfiguration object which can then
52 * be added some other Configuration files
53 */
54 public CompositeConfiguration()
55 {
56 clear();
57 }
58
59 /***
60 * Creates a CompositeConfiguration object with a specified in memory
61 * configuration. This configuration will store any changes made to
62 * the CompositeConfiguration.
63 *
64 * @param inMemoryConfiguration the in memory configuration to use
65 */
66 public CompositeConfiguration(Configuration inMemoryConfiguration)
67 {
68 configList.clear();
69 this.inMemoryConfiguration = inMemoryConfiguration;
70 configList.add(inMemoryConfiguration);
71 }
72
73 /***
74 * Create a CompositeConfiguration with an empty in memory configuration
75 * and adds the collection of configurations specified.
76 *
77 * @param configurations the collection of configurations to add
78 */
79 public CompositeConfiguration(Collection configurations)
80 {
81 this(new BaseConfiguration(), configurations);
82 }
83
84 /***
85 * Creates a CompositeConfiguration with a specified in memory
86 * configuration, and then adds the given collection of configurations.
87 *
88 * @param inMemoryConfiguration the in memory configuration to use
89 * @param configurations the collection of configurations to add
90 */
91 public CompositeConfiguration(Configuration inMemoryConfiguration, Collection configurations)
92 {
93 this(inMemoryConfiguration);
94
95 if (configurations != null)
96 {
97 Iterator it = configurations.iterator();
98 while (it.hasNext())
99 {
100 addConfiguration((Configuration) it.next());
101 }
102 }
103 }
104
105 /***
106 * Add a configuration.
107 *
108 * @param config the configuration to add
109 */
110 public void addConfiguration(Configuration config)
111 {
112 if (!configList.contains(config))
113 {
114
115
116
117
118 configList.add(configList.indexOf(inMemoryConfiguration), config);
119
120 if (config instanceof AbstractConfiguration)
121 {
122 ((AbstractConfiguration) config).setThrowExceptionOnMissing(isThrowExceptionOnMissing());
123 }
124 }
125 }
126
127 /***
128 * Remove a configuration. The in memory configuration cannot be removed.
129 *
130 * @param config The configuration to remove
131 */
132 public void removeConfiguration(Configuration config)
133 {
134
135
136 if (!config.equals(inMemoryConfiguration))
137 {
138 configList.remove(config);
139 }
140 }
141
142 /***
143 * Return the number of configurations.
144 *
145 * @return the number of configuration
146 */
147 public int getNumberOfConfigurations()
148 {
149 return configList.size();
150 }
151
152 /***
153 * Remove all configuration reinitialize the in memory configuration.
154 */
155 public void clear()
156 {
157 configList.clear();
158
159 inMemoryConfiguration = new BaseConfiguration();
160 ((BaseConfiguration) inMemoryConfiguration).setThrowExceptionOnMissing(isThrowExceptionOnMissing());
161 ((BaseConfiguration) inMemoryConfiguration).setListDelimiter(getListDelimiter());
162 ((BaseConfiguration) inMemoryConfiguration).setDelimiterParsingDisabled(isDelimiterParsingDisabled());
163 configList.add(inMemoryConfiguration);
164 }
165
166 /***
167 * Add this property to the inmemory Configuration.
168 *
169 * @param key The Key to add the property to.
170 * @param token The Value to add.
171 */
172 protected void addPropertyDirect(String key, Object token)
173 {
174 inMemoryConfiguration.addProperty(key, token);
175 }
176
177 /***
178 * Read property from underlying composite
179 *
180 * @param key key to use for mapping
181 *
182 * @return object associated with the given configuration key.
183 */
184 public Object getProperty(String key)
185 {
186 Configuration firstMatchingConfiguration = null;
187 for (Iterator i = configList.iterator(); i.hasNext();)
188 {
189 Configuration config = (Configuration) i.next();
190 if (config.containsKey(key))
191 {
192 firstMatchingConfiguration = config;
193 break;
194 }
195 }
196
197 if (firstMatchingConfiguration != null)
198 {
199 return firstMatchingConfiguration.getProperty(key);
200 }
201 else
202 {
203 return null;
204 }
205 }
206
207 /***
208 * {@inheritDoc}
209 */
210 public Iterator getKeys()
211 {
212 List keys = new ArrayList();
213 for (Iterator i = configList.iterator(); i.hasNext();)
214 {
215 Configuration config = (Configuration) i.next();
216
217 Iterator j = config.getKeys();
218 while (j.hasNext())
219 {
220 String key = (String) j.next();
221 if (!keys.contains(key))
222 {
223 keys.add(key);
224 }
225 }
226 }
227
228 return keys.iterator();
229 }
230
231 /***
232 * {@inheritDoc}
233 */
234 public Iterator getKeys(String key)
235 {
236 List keys = new ArrayList();
237 for (Iterator i = configList.iterator(); i.hasNext();)
238 {
239 Configuration config = (Configuration) i.next();
240
241 Iterator j = config.getKeys(key);
242 while (j.hasNext())
243 {
244 String newKey = (String) j.next();
245 if (!keys.contains(newKey))
246 {
247 keys.add(newKey);
248 }
249 }
250 }
251
252 return keys.iterator();
253 }
254
255 /***
256 * {@inheritDoc}
257 */
258 public boolean isEmpty()
259 {
260 boolean isEmpty = true;
261 for (Iterator i = configList.iterator(); i.hasNext();)
262 {
263 Configuration config = (Configuration) i.next();
264 if (!config.isEmpty())
265 {
266 return false;
267 }
268 }
269
270 return isEmpty;
271 }
272
273 /***
274 * {@inheritDoc}
275 */
276 protected void clearPropertyDirect(String key)
277 {
278 for (Iterator i = configList.iterator(); i.hasNext();)
279 {
280 Configuration config = (Configuration) i.next();
281 config.clearProperty(key);
282 }
283 }
284
285 /***
286 * {@inheritDoc}
287 */
288 public boolean containsKey(String key)
289 {
290 for (Iterator i = configList.iterator(); i.hasNext();)
291 {
292 Configuration config = (Configuration) i.next();
293 if (config.containsKey(key))
294 {
295 return true;
296 }
297 }
298 return false;
299 }
300
301 /***
302 * {@inheritDoc}
303 */
304 public List getList(String key, List defaultValue)
305 {
306 List list = new ArrayList();
307
308
309 Iterator it = configList.iterator();
310 while (it.hasNext() && list.isEmpty())
311 {
312 Configuration config = (Configuration) it.next();
313 if (config != inMemoryConfiguration && config.containsKey(key))
314 {
315 list.addAll(config.getList(key));
316 }
317 }
318
319
320 list.addAll(inMemoryConfiguration.getList(key));
321
322 if (list.isEmpty())
323 {
324 return defaultValue;
325 }
326
327 ListIterator lit = list.listIterator();
328 while (lit.hasNext())
329 {
330 lit.set(interpolate(lit.next()));
331 }
332
333 return list;
334 }
335
336 /***
337 * {@inheritDoc}
338 */
339 public String[] getStringArray(String key)
340 {
341 List list = getList(key);
342
343
344 String[] tokens = new String[list.size()];
345
346 for (int i = 0; i < tokens.length; i++)
347 {
348 tokens[i] = interpolate(String.valueOf(list.get(i)));
349 }
350
351 return tokens;
352 }
353
354 /***
355 * Return the configuration at the specified index.
356 *
357 * @param index The index of the configuration to retrieve
358 * @return the configuration at this index
359 */
360 public Configuration getConfiguration(int index)
361 {
362 return (Configuration) configList.get(index);
363 }
364
365 /***
366 * Returns the "in memory configuration". In this configuration
367 * changes are stored.
368 *
369 * @return the in memory configuration
370 */
371 public Configuration getInMemoryConfiguration()
372 {
373 return inMemoryConfiguration;
374 }
375
376 /***
377 * Returns a copy of this object. This implementation will create a deep
378 * clone, i.e. all configurations contained in this composite will also be
379 * cloned. This only works if all contained configurations support cloning;
380 * otherwise a runtime exception will be thrown. Registered event handlers
381 * won't get cloned.
382 *
383 * @return the copy
384 * @since 1.3
385 */
386 public Object clone()
387 {
388 try
389 {
390 CompositeConfiguration copy = (CompositeConfiguration) super
391 .clone();
392 copy.clearConfigurationListeners();
393 copy.configList = new LinkedList();
394 copy.inMemoryConfiguration = ConfigurationUtils
395 .cloneConfiguration(getInMemoryConfiguration());
396 copy.configList.add(copy.inMemoryConfiguration);
397
398 for (int i = 0; i < getNumberOfConfigurations(); i++)
399 {
400 Configuration config = getConfiguration(i);
401 if (config != getInMemoryConfiguration())
402 {
403 copy.addConfiguration(ConfigurationUtils
404 .cloneConfiguration(config));
405 }
406 }
407
408 return copy;
409 }
410 catch (CloneNotSupportedException cnex)
411 {
412
413 throw new ConfigurationRuntimeException(cnex);
414 }
415 }
416
417 /***
418 * Sets a flag whether added values for string properties should be checked
419 * for the list delimiter. This implementation ensures that the in memory
420 * configuration is correctly initialized.
421 *
422 * @param delimiterParsingDisabled the new value of the flag
423 * @since 1.4
424 */
425 public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled)
426 {
427 ((BaseConfiguration) getInMemoryConfiguration())
428 .setDelimiterParsingDisabled(delimiterParsingDisabled);
429 super.setDelimiterParsingDisabled(delimiterParsingDisabled);
430 }
431
432 /***
433 * Sets the character that is used as list delimiter. This implementation
434 * ensures that the in memory configuration is correctly initialized.
435 *
436 * @param listDelimiter the new list delimiter character
437 * @since 1.4
438 */
439 public void setListDelimiter(char listDelimiter)
440 {
441 ((BaseConfiguration) getInMemoryConfiguration())
442 .setListDelimiter(listDelimiter);
443 super.setListDelimiter(listDelimiter);
444 }
445 }