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