##### Coverage Report - org.apache.commons.configuration.CompositeConfiguration

Classes in this File | Line Coverage | Branch Coverage | Complexity
CompositeConfiguration |
98% | 101/103
100% | 25/25
| 2.6;2,6

1 |  |
     /*
2 |  |
      * Licensed to the Apache Software Foundation (ASF) under one or more
3 |  |
      * contributor license agreements.  See the NOTICE file distributed with
4 |  |
      * this work for additional information regarding copyright ownership.
5 |  |
      * The ASF licenses this file to You under the Apache License, Version 2.0
6 |  |
      * (the "License"); you may not use this file except in compliance with
7 |  |
      * the License.  You may obtain a copy of the License at
8 |  |
      *
9 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
10 |  |
      *
11 |  |
      * Unless required by applicable law or agreed to in writing, software
12 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
13 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |  |
      * See the License for the specific language governing permissions and
15 |  |
      * limitations under the License.
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 | 109 |
         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 | 104 |
         {
55 | 104 |
             clear();
56 | 104 |
         }
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 | 5 |
         {
67 | 5 |
             configList.clear();
68 | 5 |
             this.inMemoryConfiguration = inMemoryConfiguration;
69 | 5 |
             configList.add(inMemoryConfiguration);
70 | 5 |
         }
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 | 1 |
             this(new BaseConfiguration(), configurations);
81 | 1 |
         }
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 | 1 |
             this(inMemoryConfiguration);
93 |  |
94 | 1 |
             if (configurations != null)
95 |  |
             {
96 | 1 |
                 Iterator it = configurations.iterator();
97 | 5 |
                 while (it.hasNext())
98 |  |
                 {
99 | 3 |
                     addConfiguration((Configuration) it.next());
100 |  |
                 }
101 |  |
             }
102 | 1 |
         }
103 |  |
104 |  |
         /**
105 |  |
          * Add a configuration.
106 |  |
          *
107 |  |
          * @param config the configuration to add
108 |  |
          */
109 |  |
         public void addConfiguration(Configuration config)
110 |  |
         {
111 | 149 |
             if (!configList.contains(config))
112 |  |
             {
113 |  |
                 // As the inMemoryConfiguration contains all manually added keys,
114 |  |
                 // we must make sure that it is always last. "Normal", non composed
115 |  |
                 // configuration add their keys at the end of the configuration and
116 |  |
                 // we want to mimic this behaviour.
117 | 147 |
                 configList.add(configList.indexOf(inMemoryConfiguration), config);
118 |  |
119 | 147 |
                 if (config instanceof AbstractConfiguration)
120 |  |
                 {
121 | 147 |
                     ((AbstractConfiguration) config).setThrowExceptionOnMissing(isThrowExceptionOnMissing());
122 |  |
                 }
123 |  |
             }
124 | 149 |
         }
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 |  |
             // Make sure that you can't remove the inMemoryConfiguration from
134 |  |
             // the CompositeConfiguration object
135 | 4 |
             if (!config.equals(inMemoryConfiguration))
136 |  |
             {
137 | 2 |
                 configList.remove(config);
138 |  |
             }
139 | 4 |
         }
140 |  |
141 |  |
         /**
142 |  |
          * Return the number of configurations.
143 |  |
          *
144 |  |
          * @return the number of configuration
145 |  |
          */
146 |  |
         public int getNumberOfConfigurations()
147 |  |
         {
148 | 31 |
             return configList.size();
149 |  |
         }
150 |  |
151 |  |
         /**
152 |  |
          * Remove all configuration reinitialize the in memory configuration.
153 |  |
          */
154 |  |
         public void clear()
155 |  |
         {
156 | 112 |
             configList.clear();
157 |  |
             // recreate the in memory configuration
158 | 112 |
             inMemoryConfiguration = new BaseConfiguration();
159 | 112 |
             ((BaseConfiguration) inMemoryConfiguration).setThrowExceptionOnMissing(isThrowExceptionOnMissing());
160 | 112 |
             configList.add(inMemoryConfiguration);
161 | 112 |
         }
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 | 21 |
             inMemoryConfiguration.addProperty(key, token);
172 | 21 |
         }
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 | 122 |
             Configuration firstMatchingConfiguration = null;
184 | 334 |
             for (Iterator i = configList.iterator(); i.hasNext();)
185 |  |
             {
186 | 187 |
                 Configuration config = (Configuration) i.next();
187 | 187 |
                 if (config.containsKey(key))
188 |  |
                 {
189 | 97 |
                     firstMatchingConfiguration = config;
190 | 97 |
                     break;
191 |  |
                 }
192 |  |
             }
193 |  |
194 | 122 |
             if (firstMatchingConfiguration != null)
195 |  |
             {
196 | 97 |
                 return firstMatchingConfiguration.getProperty(key);
197 |  |
             }
198 |  |
             else
199 |  |
             {
200 | 25 |
                 return null;
201 |  |
             }
202 |  |
         }
203 |  |
204 |  |
         /**
205 |  |
          * {@inheritDoc}
206 |  |
          */
207 |  |
         public Iterator getKeys()
208 |  |
         {
209 | 14 |
             List keys = new ArrayList();
210 | 52 |
             for (Iterator i = configList.iterator(); i.hasNext();)
211 |  |
             {
212 | 24 |
                 Configuration config = (Configuration) i.next();
213 |  |
214 | 24 |
                 Iterator j = config.getKeys();
215 | 174 |
                 while (j.hasNext())
216 |  |
                 {
217 | 126 |
                     String key = (String) j.next();
218 | 126 |
                     if (!keys.contains(key))
219 |  |
                     {
220 | 125 |
                         keys.add(key);
221 |  |
                     }
222 |  |
                 }
223 |  |
             }
224 |  |
225 | 14 |
             return keys.iterator();
226 |  |
         }
227 |  |
228 |  |
         /**
229 |  |
          * {@inheritDoc}
230 |  |
          */
231 |  |
         public Iterator getKeys(String key)
232 |  |
         {
233 | 9 |
             List keys = new ArrayList();
234 | 40 |
             for (Iterator i = configList.iterator(); i.hasNext();)
235 |  |
             {
236 | 22 |
                 Configuration config = (Configuration) i.next();
237 |  |
238 | 22 |
                 Iterator j = config.getKeys(key);
239 | 240 |
                 while (j.hasNext())
240 |  |
                 {
241 | 196 |
                     String newKey = (String) j.next();
242 | 196 |
                     if (!keys.contains(newKey))
243 |  |
                     {
244 | 194 |
                         keys.add(newKey);
245 |  |
                     }
246 |  |
                 }
247 |  |
             }
248 |  |
249 | 9 |
             return keys.iterator();
250 |  |
         }
251 |  |
252 |  |
         /**
253 |  |
          * {@inheritDoc}
254 |  |
          */
255 |  |
         public boolean isEmpty()
256 |  |
         {
257 | 4 |
             boolean isEmpty = true;
258 | 8 |
             for (Iterator i = configList.iterator(); i.hasNext();)
259 |  |
             {
260 | 4 |
                 Configuration config = (Configuration) i.next();
261 | 4 |
                 if (!config.isEmpty())
262 |  |
                 {
263 | 4 |
                     return false;
264 |  |
                 }
265 |  |
             }
266 |  |
267 | 0 |
             return isEmpty;
268 |  |
         }
269 |  |
270 |  |
         /**
271 |  |
          * {@inheritDoc}
272 |  |
          */
273 |  |
         public void clearProperty(String key)
274 |  |
         {
275 | 60 |
             for (Iterator i = configList.iterator(); i.hasNext();)
276 |  |
             {
277 | 32 |
                 Configuration config = (Configuration) i.next();
278 | 32 |
                 config.clearProperty(key);
279 |  |
             }
280 | 14 |
         }
281 |  |
282 |  |
         /**
283 |  |
          * {@inheritDoc}
284 |  |
          */
285 |  |
         public boolean containsKey(String key)
286 |  |
         {
287 | 134 |
             for (Iterator i = configList.iterator(); i.hasNext();)
288 |  |
             {
289 | 70 |
                 Configuration config = (Configuration) i.next();
290 | 70 |
                 if (config.containsKey(key))
291 |  |
                 {
292 | 44 |
                     return true;
293 |  |
                 }
294 |  |
             }
295 | 10 |
             return false;
296 |  |
         }
297 |  |
298 |  |
         /**
299 |  |
          * {@inheritDoc}
300 |  |
          */
301 |  |
         public List getList(String key, List defaultValue)
302 |  |
         {
303 | 43 |
             List list = new ArrayList();
304 |  |
305 |  |
             // add all elements from the first configuration containing the requested key
306 | 43 |
             Iterator it = configList.iterator();
307 | 144 |
             while (it.hasNext() && list.isEmpty())
308 |  |
             {
309 | 58 |
                 Configuration config = (Configuration) it.next();
310 | 58 |
                 if (config != inMemoryConfiguration && config.containsKey(key))
311 |  |
                 {
312 | 31 |
                     list.addAll(config.getList(key));
313 |  |
                 }
314 |  |
             }
315 |  |
316 |  |
             // add all elements from the in memory configuration
317 | 43 |
             list.addAll(inMemoryConfiguration.getList(key));
318 |  |
319 | 43 |
             if (list.isEmpty())
320 |  |
             {
321 | 5 |
                 return defaultValue;
322 |  |
             }
323 |  |
324 | 38 |
             return list;
325 |  |
         }
326 |  |
327 |  |
         /**
328 |  |
          * {@inheritDoc}
329 |  |
          */
330 |  |
         public String[] getStringArray(String key)
331 |  |
         {
332 | 13 |
             List list = getList(key);
333 |  |
334 |  |
             // interpolate the strings
335 | 13 |
             String[] tokens = new String[list.size()];
336 |  |
337 | 33 |
             for (int i = 0; i < tokens.length; i++)
338 |  |
             {
339 | 20 |
                 tokens[i] = interpolate(String.valueOf(list.get(i)));
340 |  |
             }
341 |  |
342 | 13 |
             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 | 28 |
             return (Configuration) configList.get(index);
354 |  |
         }
355 |  |
356 |  |
         /**
357 |  |
          * Returns the &quot;in memory configuration&quot;. In this configuration
358 |  |
          * changes are stored.
359 |  |
          *
360 |  |
          * @return the in memory configuration
361 |  |
          */
362 |  |
         public Configuration getInMemoryConfiguration()
363 |  |
         {
364 | 7 |
             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 | 3 |
                 CompositeConfiguration copy = (CompositeConfiguration) super
382 |  |
                         .clone();
383 | 3 |
                 copy.clearConfigurationListeners();
384 | 3 |
                 copy.configList = new LinkedList();
385 | 3 |
                 copy.inMemoryConfiguration = ConfigurationUtils
386 |  |
                         .cloneConfiguration(getInMemoryConfiguration());
387 | 3 |
                 copy.configList.add(copy.inMemoryConfiguration);
388 |  |
389 | 5 |
                 for (int i = 0; i < getNumberOfConfigurations(); i++)
390 |  |
                 {
391 | 3 |
                     Configuration config = getConfiguration(i);
392 | 3 |
                     if (config != getInMemoryConfiguration())
393 |  |
                     {
394 | 1 |
                         copy.addConfiguration(ConfigurationUtils
395 |  |
                                 .cloneConfiguration(config));
396 |  |
                     }
397 |  |
                 }
398 |  |
399 | 2 |
                 return copy;
400 |  |
             }
401 |  |
             catch (CloneNotSupportedException cnex)
402 |  |
             {
403 |  |
                 // cannot happen
404 | 0 |
                 throw new ConfigurationRuntimeException(cnex);
405 |  |
             }
406 |  |
         }
407 |  |
     }