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

Classes in this File | Line Coverage | Branch Coverage | Complexity
CombinedConfiguration |
99% | 81/82
100% | 13/13
| 1.8461538461538463;1,846
CombinedConfiguration$ConfigData |
100% | 28/28
100% | 4/4
| 1.8461538461538463;1,846

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 |  |
     package org.apache.commons.configuration;
18 |  |
19 |  |
     import java.util.ArrayList;
20 |  |
     import java.util.Collection;
21 |  |
     import java.util.HashMap;
22 |  |
     import java.util.Iterator;
23 |  |
     import java.util.List;
24 |  |
     import java.util.Map;
25 |  |
     import java.util.Set;
26 |  |
27 |  |
     import org.apache.commons.configuration.event.ConfigurationEvent;
28 |  |
     import org.apache.commons.configuration.event.ConfigurationListener;
29 |  |
     import org.apache.commons.configuration.tree.ConfigurationNode;
30 |  |
     import org.apache.commons.configuration.tree.DefaultConfigurationKey;
31 |  |
     import org.apache.commons.configuration.tree.DefaultConfigurationNode;
32 |  |
     import org.apache.commons.configuration.tree.DefaultExpressionEngine;
33 |  |
     import org.apache.commons.configuration.tree.NodeCombiner;
34 |  |
     import org.apache.commons.configuration.tree.UnionCombiner;
35 |  |
     import org.apache.commons.configuration.tree.ViewNode;
36 |  |
37 |  |
     /**
38 |  |
      * <p>
39 |  |
      * A hierarchical composite configuration class.
40 |  |
      * </p>
41 |  |
      * <p>
42 |  |
      * This class maintains a list of configuration objects, which can be added
43 |  |
      * using the divers <code>addConfiguration()</code> methods. After that the
44 |  |
      * configurations can be accessed either by name (if one was provided when the
45 |  |
      * configuration was added) or by index. For the whole set of managed
46 |  |
      * configurations a logical node structure is constructed. For this purpose a
47 |  |
      * <code>{@link org.apache.commons.configuration.tree.NodeCombiner NodeCombiner}</code>
48 |  |
      * object can be set. This makes it possible to specify different algorithms for
49 |  |
      * the combination process.
50 |  |
      * </p>
51 |  |
      * <p>
52 |  |
      * The big advantage of this class is that it creates a truely hierarchical
53 |  |
      * structure of all the properties stored in the contained configurations - even
54 |  |
      * if some of them are no hierarchical configurations per se. So all enhanced
55 |  |
      * features provided by a hierarchical configuration (e.g. choosing an
56 |  |
      * expression engine) are applicable.
57 |  |
      * </p>
58 |  |
      * <p>
59 |  |
      * The class works by registering itself as an event listener add all added
60 |  |
      * configurations. So it gets notified whenever one of these configurations is
61 |  |
      * changed and can invalidate its internal node structure. The next time a
62 |  |
      * property is accessed the node structure will be re-constructed using the
63 |  |
      * current state of the managed configurations. Node that, depending on the used
64 |  |
      * <code>NodeCombiner</code>, this may be a complex operation.
65 |  |
      * </p>
66 |  |
      * <p>
67 |  |
      * It is not strictly forbidden to manipulate a
68 |  |
      * <code>CombinedConfiguration</code> directly, but the results may be
69 |  |
      * unpredictable. For instance some node combiners use special view nodes for
70 |  |
      * linking parts of the original configurations' data together. If new
71 |  |
      * properties are added to such a special node, they do not belong to any of the
72 |  |
      * managed configurations and thus hang in the air. It is also possible that
73 |  |
      * direct updates on a <code>CombinedConfiguration</code> are incompatible
74 |  |
      * with the used node combiner (e.g. if the
75 |  |
      * <code>{@link org.apache.commons.configuration.tree.OverrideCombiner OverrideCombiner}</code>
76 |  |
      * is used and properties are removed the resulting node structure may be
77 |  |
      * incorrect because some properties that were hidden by the removed properties
78 |  |
      * are not visible). So it is recommended to perform updates only on the managed
79 |  |
      * configurations.
80 |  |
      * </p>
81 |  |
      * <p>
82 |  |
      * Whenever the node structure of a <code>CombinedConfiguration</code> becomes
83 |  |
      * invalid (either because one of the contained configurations was modified or
84 |  |
      * because the <code>invalidate()</code> method was directly called) an event
85 |  |
      * is generated. So this can be detected by interested event listeners. This
86 |  |
      * also makes it possible to add a combined configuration into another one.
87 |  |
      * </p>
88 |  |
      * <p>
89 |  |
      * Implementation note: Adding and removing configurations to and from a
90 |  |
      * combined configuration is not thread-safe. If a combined configuration is
91 |  |
      * manipulated by multiple threads, the developer has to take care about
92 |  |
      * properly synchronization.
93 |  |
      * </p>
94 |  |
      *
95 |  |
      * @author <a
96 |  |
      * href="http://jakarta.apache.org/commons/configuration/team-list.html">Commons
97 |  |
      * Configuration team</a>
98 |  |
      * @since 1.3
99 |  |
      * @version $Id: CombinedConfiguration.java 439648 2006-09-02 20:42:10Z oheger $
100 |  |
      */
101 | 11 |
     public class CombinedConfiguration extends HierarchicalConfiguration implements
102 |  |
             ConfigurationListener, Cloneable
103 |  |
     {
104 |  |
         /**
105 |  |
          * Constant for the invalidate event that is fired when the internal node
106 |  |
          * structure becomes invalid.
107 |  |
          */
108 |  |
         public static final int EVENT_COMBINED_INVALIDATE = 40;
109 |  |
110 |  |
         /**
111 |  |
          * The serial version ID.
112 |  |
          */
113 |  |
         private static final long serialVersionUID = 8338574525528692307L;
114 |  |
115 |  |
         /** Constant for the expression engine for parsing the at path. */
116 | 6 |
         private static final DefaultExpressionEngine AT_ENGINE = new DefaultExpressionEngine();
117 |  |
118 |  |
         /** Constant for the default node combiner. */
119 | 3 |
         private static final NodeCombiner DEFAULT_COMBINER = new UnionCombiner();
120 |  |
121 |  |
         /** Stores the combiner. */
122 |  |
         private NodeCombiner nodeCombiner;
123 |  |
124 |  |
         /** Stores the combined root node. */
125 |  |
         private ConfigurationNode combinedRoot;
126 |  |
127 |  |
         /** Stores a list with the contained configurations. */
128 |  |
         private List configurations;
129 |  |
130 |  |
         /** Stores a map with the named configurations. */
131 |  |
         private Map namedConfigurations;
132 |  |
133 |  |
         /**
134 |  |
          * Creates a new instance of <code>CombinedConfiguration</code> and
135 |  |
          * initializes the combiner to be used.
136 |  |
          *
137 |  |
          * @param comb the node combiner (can be <b>null</b>, then a union combiner
138 |  |
          * is used as default)
139 |  |
          */
140 |  |
         public CombinedConfiguration(NodeCombiner comb)
141 | 45 |
         {
142 | 45 |
             setNodeCombiner((comb != null) ? comb : DEFAULT_COMBINER);
143 | 45 |
             clear();
144 | 45 |
         }
145 |  |
146 |  |
         /**
147 |  |
          * Creates a new instance of <code>CombinedConfiguration</code> that uses
148 |  |
          * a union combiner.
149 |  |
          *
150 |  |
          * @see org.apache.commons.configuration.tree.UnionCombiner
151 |  |
          */
152 |  |
         public CombinedConfiguration()
153 |  |
         {
154 | 39 |
             this(null);
155 | 39 |
         }
156 |  |
157 |  |
         /**
158 |  |
          * Returns the node combiner that is used for creating the combined node
159 |  |
          * structure.
160 |  |
          *
161 |  |
          * @return the node combiner
162 |  |
          */
163 |  |
         public NodeCombiner getNodeCombiner()
164 |  |
         {
165 | 361 |
             return nodeCombiner;
166 |  |
         }
167 |  |
168 |  |
         /**
169 |  |
          * Sets the node combiner. This object will be used when the combined node
170 |  |
          * structure is to be constructed. It must not be <b>null</b>, otherwise an
171 |  |
          * <code>IllegalArgumentException</code> exception is thrown. Changing the
172 |  |
          * node combiner causes an invalidation of this combined configuration, so
173 |  |
          * that the new combiner immediately takes effect.
174 |  |
          *
175 |  |
          * @param nodeCombiner the node combiner
176 |  |
          */
177 |  |
         public void setNodeCombiner(NodeCombiner nodeCombiner)
178 |  |
         {
179 | 64 |
             if (nodeCombiner == null)
180 |  |
             {
181 | 1 |
                 throw new IllegalArgumentException(
182 |  |
                         "Node combiner must not be null!");
183 |  |
             }
184 | 63 |
             this.nodeCombiner = nodeCombiner;
185 | 63 |
             invalidate();
186 | 63 |
         }
187 |  |
188 |  |
         /**
189 |  |
          * Adds a new configuration to this combined configuration. It is possible
190 |  |
          * (but not mandatory) to give the new configuration a name. This name must
191 |  |
          * be unique, otherwise a <code>ConfigurationRuntimeException</code> will
192 |  |
          * be thrown. With the optional <code>at</code> argument you can specify
193 |  |
          * where in the resulting node structure the content of the added
194 |  |
          * configuration should appear. This is a string that uses dots as property
195 |  |
          * delimiters (independent on the current expression engine). For instance
196 |  |
          * if you pass in the string <code>&quot;database.tables&quot;</code>,
197 |  |
          * all properties of the added configuration will occur in this branch.
198 |  |
          *
199 |  |
          * @param config the configuration to add (must not be <b>null</b>)
200 |  |
          * @param name the name of this configuration (can be <b>null</b>)
201 |  |
          * @param at the position of this configuration in the combined tree (can be
202 |  |
          * <b>null</b>)
203 |  |
          */
204 |  |
         public void addConfiguration(AbstractConfiguration config, String name,
205 |  |
                 String at)
206 |  |
         {
207 | 80 |
             if (config == null)
208 |  |
             {
209 | 1 |
                 throw new IllegalArgumentException(
210 |  |
                         "Added configuration must not be null!");
211 |  |
             }
212 | 79 |
             if (name != null && namedConfigurations.containsKey(name))
213 |  |
             {
214 | 1 |
                 throw new ConfigurationRuntimeException(
215 |  |
                         "A configuration with the name '"
216 |  |
                                 + name
217 |  |
                                 + "' already exists in this combined configuration!");
218 |  |
             }
219 |  |
220 | 78 |
             ConfigData cd = new ConfigData(config, name, at);
221 | 78 |
             configurations.add(cd);
222 | 78 |
             if (name != null)
223 |  |
             {
224 | 32 |
                 namedConfigurations.put(name, config);
225 |  |
             }
226 |  |
227 | 78 |
             config.addConfigurationListener(this);
228 | 78 |
             invalidate();
229 | 78 |
         }
230 |  |
231 |  |
         /**
232 |  |
          * Adds a new configuration to this combined configuration with an optional
233 |  |
          * name. The new configuration's properties will be added under the root of
234 |  |
          * the combined node structure.
235 |  |
          *
236 |  |
          * @param config the configuration to add (must not be <b>null</b>)
237 |  |
          * @param name the name of this configuration (can be <b>null</b>)
238 |  |
          */
239 |  |
         public void addConfiguration(AbstractConfiguration config, String name)
240 |  |
         {
241 | 13 |
             addConfiguration(config, name, null);
242 | 13 |
         }
243 |  |
244 |  |
         /**
245 |  |
          * Adds a new configuration to this combined configuration. The new
246 |  |
          * configuration is not given a name. Its properties will be added under the
247 |  |
          * root of the combined node structure.
248 |  |
          *
249 |  |
          * @param config the configuration to add (must not be <b>null</b>)
250 |  |
          */
251 |  |
         public void addConfiguration(AbstractConfiguration config)
252 |  |
         {
253 | 8 |
             addConfiguration(config, null, null);
254 | 7 |
         }
255 |  |
256 |  |
         /**
257 |  |
          * Returns the number of configurations that are contained in this combined
258 |  |
          * configuration.
259 |  |
          *
260 |  |
          * @return the number of contained configurations
261 |  |
          */
262 |  |
         public int getNumberOfConfigurations()
263 |  |
         {
264 | 65 |
             return configurations.size();
265 |  |
         }
266 |  |
267 |  |
         /**
268 |  |
          * Returns the configuration at the specified index. The contained
269 |  |
          * configurations are numbered in the order they were added to this combined
270 |  |
          * configuration. The index of the first configuration is 0.
271 |  |
          *
272 |  |
          * @param index the index
273 |  |
          * @return the configuration at this index
274 |  |
          */
275 |  |
         public Configuration getConfiguration(int index)
276 |  |
         {
277 | 37 |
             ConfigData cd = (ConfigData) configurations.get(index);
278 | 37 |
             return cd.getConfiguration();
279 |  |
         }
280 |  |
281 |  |
         /**
282 |  |
          * Returns the configuration with the given name. This can be <b>null</b>
283 |  |
          * if no such configuration exists.
284 |  |
          *
285 |  |
          * @param name the name of the configuration
286 |  |
          * @return the configuration with this name
287 |  |
          */
288 |  |
         public Configuration getConfiguration(String name)
289 |  |
         {
290 | 13 |
             return (Configuration) namedConfigurations.get(name);
291 |  |
         }
292 |  |
293 |  |
         /**
294 |  |
          * Removes the specified configuration from this combined configuration.
295 |  |
          *
296 |  |
          * @param config the configuration to be removed
297 |  |
          * @return a flag whether this configuration was found and could be removed
298 |  |
          */
299 |  |
         public boolean removeConfiguration(Configuration config)
300 |  |
         {
301 | 5 |
             for (int index = 0; index < getNumberOfConfigurations(); index++)
302 |  |
             {
303 | 4 |
                 if (((ConfigData) configurations.get(index)).getConfiguration() == config)
304 |  |
                 {
305 | 4 |
                     removeConfigurationAt(index);
306 | 4 |
                     return true;
307 |  |
                 }
308 |  |
             }
309 |  |
310 | 1 |
             return false;
311 |  |
         }
312 |  |
313 |  |
         /**
314 |  |
          * Removes the configuration at the specified index.
315 |  |
          *
316 |  |
          * @param index the index
317 |  |
          * @return the removed configuration
318 |  |
          */
319 |  |
         public Configuration removeConfigurationAt(int index)
320 |  |
         {
321 | 6 |
             ConfigData cd = (ConfigData) configurations.remove(index);
322 | 6 |
             if (cd.getName() != null)
323 |  |
             {
324 | 4 |
                 namedConfigurations.remove(cd.getName());
325 |  |
             }
326 | 6 |
             cd.getConfiguration().removeConfigurationListener(this);
327 | 6 |
             invalidate();
328 | 6 |
             return cd.getConfiguration();
329 |  |
         }
330 |  |
331 |  |
         /**
332 |  |
          * Removes the configuration with the specified name.
333 |  |
          *
334 |  |
          * @param name the name of the configuration to be removed
335 |  |
          * @return the removed configuration (<b>null</b> if this configuration
336 |  |
          * was not found)
337 |  |
          */
338 |  |
         public Configuration removeConfiguration(String name)
339 |  |
         {
340 | 3 |
             Configuration conf = getConfiguration(name);
341 | 3 |
             if (conf != null)
342 |  |
             {
343 | 2 |
                 removeConfiguration(conf);
344 |  |
             }
345 | 3 |
             return conf;
346 |  |
         }
347 |  |
348 |  |
         /**
349 |  |
          * Returns a set with the names of all configurations contained in this
350 |  |
          * combined configuration. Of course here are only these configurations
351 |  |
          * listed, for which a name was specified when they were added.
352 |  |
          *
353 |  |
          * @return a set with the names of the contained configurations (never
354 |  |
          * <b>null</b>)
355 |  |
          */
356 |  |
         public Set getConfigurationNames()
357 |  |
         {
358 | 14 |
             return namedConfigurations.keySet();
359 |  |
         }
360 |  |
361 |  |
         /**
362 |  |
          * Invalidates this combined configuration. This means that the next time a
363 |  |
          * property is accessed the combined node structure must be re-constructed.
364 |  |
          * Invalidation of a combined configuration also means that an event of type
365 |  |
          * <code>EVENT_COMBINED_INVALIDATE</code> is fired. Note that while other
366 |  |
          * events most times appear twice (once before and once after an update),
367 |  |
          * this event is only fired once (after update).
368 |  |
          */
369 |  |
         public void invalidate()
370 |  |
         {
371 | 211 |
             synchronized (getNodeCombiner()) // use combiner as lock
372 |  |
             {
373 | 211 |
                 combinedRoot = null;
374 | 211 |
             }
375 | 211 |
             fireEvent(EVENT_COMBINED_INVALIDATE, null, null, false);
376 | 211 |
         }
377 |  |
378 |  |
         /**
379 |  |
          * Event listener call back for configuration update events. This method is
380 |  |
          * called whenever one of the contained configurations was modified. It
381 |  |
          * invalidates this combined configuration.
382 |  |
          *
383 |  |
          * @param event the update event
384 |  |
          */
385 |  |
         public void configurationChanged(ConfigurationEvent event)
386 |  |
         {
387 | 16 |
             invalidate();
388 | 16 |
         }
389 |  |
390 |  |
         /**
391 |  |
          * Returns the configuration root node of this combined configuration. This
392 |  |
          * method will construct a combined node structure using the current node
393 |  |
          * combiner if necessary.
394 |  |
          *
395 |  |
          * @return the combined root node
396 |  |
          */
397 |  |
         public ConfigurationNode getRootNode()
398 |  |
         {
399 | 97 |
             synchronized (getNodeCombiner())
400 |  |
             {
401 | 97 |
                 if (combinedRoot == null)
402 |  |
                 {
403 | 36 |
                     combinedRoot = constructCombinedNode();
404 |  |
                 }
405 | 97 |
                 return combinedRoot;
406 | 0 |
             }
407 |  |
         }
408 |  |
409 |  |
         /**
410 |  |
          * Clears this configuration. All contained configurations will be removed.
411 |  |
          */
412 |  |
         public void clear()
413 |  |
         {
414 | 48 |
             fireEvent(EVENT_CLEAR, null, null, true);
415 | 48 |
             configurations = new ArrayList();
416 | 48 |
             namedConfigurations = new HashMap();
417 | 48 |
             fireEvent(EVENT_CLEAR, null, null, false);
418 | 48 |
             invalidate();
419 | 48 |
         }
420 |  |
421 |  |
         /**
422 |  |
          * Returns a copy of this object. This implementation performs a deep clone,
423 |  |
          * i.e. all contained configurations will be cloned, too. For this to work,
424 |  |
          * all contained configurations must be cloneable. Registered event
425 |  |
          * listeners won't be cloned. The clone will use the same node combiner than
426 |  |
          * the original.
427 |  |
          *
428 |  |
          * @return the copied object
429 |  |
          */
430 |  |
         public Object clone()
431 |  |
         {
432 | 2 |
             CombinedConfiguration copy = (CombinedConfiguration) super.clone();
433 | 2 |
             copy.clear();
434 | 8 |
             for (Iterator it = configurations.iterator(); it.hasNext();)
435 |  |
             {
436 | 4 |
                 ConfigData cd = (ConfigData) it.next();
437 | 4 |
                 copy.addConfiguration((AbstractConfiguration) ConfigurationUtils
438 |  |
                         .cloneConfiguration(cd.getConfiguration()), cd.getName(),
439 |  |
                         cd.getAt());
440 |  |
             }
441 |  |
442 | 2 |
             copy.setRootNode(new DefaultConfigurationNode());
443 | 2 |
             return copy;
444 |  |
         }
445 |  |
446 |  |
         /**
447 |  |
          * Creates the root node of this combined configuration.
448 |  |
          *
449 |  |
          * @return the combined root node
450 |  |
          */
451 |  |
         private ConfigurationNode constructCombinedNode()
452 |  |
         {
453 | 36 |
             if (getNumberOfConfigurations() < 1)
454 |  |
             {
455 | 7 |
                 return new ViewNode();
456 |  |
             }
457 |  |
458 |  |
             else
459 |  |
             {
460 | 29 |
                 Iterator it = configurations.iterator();
461 | 29 |
                 ConfigurationNode node = ((ConfigData) it.next())
462 |  |
                         .getTransformedRoot();
463 | 99 |
                 while (it.hasNext())
464 |  |
                 {
465 | 41 |
                     node = getNodeCombiner().combine(node,
466 |  |
                             ((ConfigData) it.next()).getTransformedRoot());
467 |  |
                 }
468 | 29 |
                 return node;
469 |  |
             }
470 |  |
         }
471 |  |
472 |  |
         /**
473 |  |
          * An internal helper class for storing information about contained
474 |  |
          * configurations.
475 |  |
          */
476 |  |
         static class ConfigData
477 |  |
         {
478 |  |
             /** Stores a reference to the configuration. */
479 |  |
             private AbstractConfiguration configuration;
480 |  |
481 |  |
             /** Stores the name under which the configuration is stored. */
482 |  |
             private String name;
483 |  |
484 |  |
             /** Stores the at information as path of nodes. */
485 |  |
             private Collection atPath;
486 |  |
487 |  |
             /** Stores the at string.*/
488 |  |
             private String at;
489 |  |
490 |  |
             /**
491 |  |
              * Creates a new instance of <code>ConfigData</code> and initializes
492 |  |
              * it.
493 |  |
              *
494 |  |
              * @param config the configuration
495 |  |
              * @param n the name
496 |  |
              * @param at the at position
497 |  |
              */
498 |  |
             public ConfigData(AbstractConfiguration config, String n, String at)
499 | 78 |
             {
500 | 78 |
                 configuration = config;
501 | 78 |
                 name = n;
502 | 78 |
                 atPath = parseAt(at);
503 | 78 |
                 this.at = at;
504 | 78 |
             }
505 |  |
506 |  |
             /**
507 |  |
              * Returns the stored configuration.
508 |  |
              *
509 |  |
              * @return the configuration
510 |  |
              */
511 |  |
             public AbstractConfiguration getConfiguration()
512 |  |
             {
513 | 127 |
                 return configuration;
514 |  |
             }
515 |  |
516 |  |
             /**
517 |  |
              * Returns the configuration's name.
518 |  |
              *
519 |  |
              * @return the name
520 |  |
              */
521 |  |
             public String getName()
522 |  |
             {
523 | 14 |
                 return name;
524 |  |
             }
525 |  |
526 |  |
             /**
527 |  |
              * Returns the at position of this configuration.
528 |  |
              *
529 |  |
              * @return the at position
530 |  |
              */
531 |  |
             public String getAt()
532 |  |
             {
533 | 4 |
                 return at;
534 |  |
             }
535 |  |
536 |  |
             /**
537 |  |
              * Returns the transformed root node of the stored configuration. The
538 |  |
              * term &quot;transformed&quot; means that an eventually defined at path
539 |  |
              * has been applied.
540 |  |
              *
541 |  |
              * @return the transformed root node
542 |  |
              */
543 |  |
             public ConfigurationNode getTransformedRoot()
544 |  |
             {
545 | 70 |
                 ViewNode result = new ViewNode();
546 | 70 |
                 ViewNode atParent = result;
547 |  |
548 | 70 |
                 if (atPath != null)
549 |  |
                 {
550 |  |
                     // Build the complete path
551 | 32 |
                     for (Iterator it = atPath.iterator(); it.hasNext();)
552 |  |
                     {
553 | 12 |
                         ViewNode node = new ViewNode();
554 | 12 |
                         node.setName((String) it.next());
555 | 12 |
                         atParent.addChild(node);
556 | 12 |
                         atParent = node;
557 |  |
                     }
558 |  |
                 }
559 |  |
560 |  |
                 // Copy data of the root node to the new path
561 | 70 |
                 HierarchicalConfiguration hc = ConfigurationUtils
562 |  |
                         .convertToHierarchical(getConfiguration());
563 | 70 |
                 atParent.appendChildren(hc.getRootNode());
564 | 70 |
                 atParent.appendAttributes(hc.getRootNode());
565 |  |
566 | 70 |
                 return result;
567 |  |
             }
568 |  |
569 |  |
             /**
570 |  |
              * Splits the at path into its components.
571 |  |
              *
572 |  |
              * @param at the at string
573 |  |
              * @return a collection with the names of the single components
574 |  |
              */
575 |  |
             private Collection parseAt(String at)
576 |  |
             {
577 | 78 |
                 if (at == null)
578 |  |
                 {
579 | 67 |
                     return null;
580 |  |
                 }
581 |  |
582 | 11 |
                 Collection result = new ArrayList();
583 | 11 |
                 DefaultConfigurationKey.KeyIterator it = new DefaultConfigurationKey(
584 |  |
                         AT_ENGINE, at).iterator();
585 | 35 |
                 while (it.hasNext())
586 |  |
                 {
587 | 13 |
                     result.add(it.nextKey());
588 |  |
                 }
589 | 11 |
                 return result;
590 |  |
             }
591 |  |
         }
592 |  |
     }