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

Classes in this File | Line Coverage | Branch Coverage | Complexity
HierarchicalConfigurationConverter |
98% | 40/41
100% | 9/9
| 2.2857142857142856;2,286

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.Collections;
23 |  |
     import java.util.HashSet;
24 |  |
     import java.util.Iterator;
25 |  |
     import java.util.List;
26 |  |
     import java.util.Set;
27 |  |
28 |  |
     /**
29 |  |
      * <p>A base class for converters that transform a normal configuration
30 |  |
      * object into a hierarchical configuration.</p>
31 |  |
      * <p>This class provides a default mechanism for iterating over the keys in a
32 |  |
      * configuration and to throw corresponding element start and end events. By
33 |  |
      * handling these events a hierarchy can be constructed that is equivalent to
34 |  |
      * the keys in the original configuration.</p>
35 |  |
      * <p>Concrete sub classes will implement event handlers that generate SAX
36 |  |
      * events for XML processing or construct a
37 |  |
      * <code>HierarchicalConfiguration</code> root node. All in all with this class
38 |  |
      * it is possible to treat a default configuration as if it was a hierarchical
39 |  |
      * configuration, which can be sometimes useful.</p>
40 |  |
      * @see HierarchicalConfiguration
41 |  |
      *
42 |  |
      * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
43 |  |
      * @version $Id: HierarchicalConfigurationConverter.java 439648 2006-09-02 20:42:10Z oheger $
44 |  |
      */
45 | 3 |
     abstract class HierarchicalConfigurationConverter
46 |  |
     {
47 |  |
         /**
48 |  |
          * Processes the specified configuration object. This method implements
49 |  |
          * the iteration over the configuration's keys. All defined keys are
50 |  |
          * translated into a set of element start and end events represented by
51 |  |
          * calls to the <code>elementStart()</code> and
52 |  |
          * <code>elementEnd()</code> methods.
53 |  |
          *
54 |  |
          * @param config the configuration to be processed
55 |  |
          */
56 |  |
         public void process(Configuration config)
57 |  |
         {
58 | 3 |
             if (config != null)
59 |  |
             {
60 | 3 |
                 ConfigurationKey keyEmpty = new ConfigurationKey();
61 | 3 |
                 ConfigurationKey keyLast = keyEmpty;
62 | 3 |
                 Set keySet = new HashSet();
63 |  |
64 | 36 |
                 for (Iterator it = config.getKeys(); it.hasNext();)
65 |  |
                 {
66 | 30 |
                     String key = (String) it.next();
67 | 30 |
                     if (keySet.contains(key))
68 |  |
                     {
69 |  |
                         // this key has already been processed by openElements
70 | 0 |
                         continue;
71 |  |
                     }
72 | 30 |
                     ConfigurationKey keyAct = new ConfigurationKey(key);
73 | 30 |
                     closeElements(keyLast, keyAct);
74 | 30 |
                     String elem = openElements(keyLast, keyAct, config, keySet);
75 | 30 |
                     fireValue(elem, config.getProperty(key));
76 | 30 |
                     keyLast = keyAct;
77 |  |
                 }
78 |  |
79 |  |
                 // close all open
80 | 3 |
                 closeElements(keyLast, keyEmpty);
81 |  |
             }
82 | 3 |
         }
83 |  |
84 |  |
         /**
85 |  |
          * An event handler method that is called when an element starts.
86 |  |
          * Concrete sub classes must implement it to perform a proper event
87 |  |
          * handling.
88 |  |
          *
89 |  |
          * @param name the name of the new element
90 |  |
          * @param value the element's value; can be <b>null</b> if the element
91 |  |
          * does not have any value
92 |  |
          */
93 |  |
         protected abstract void elementStart(String name, Object value);
94 |  |
95 |  |
         /**
96 |  |
          * An event handler method that is called when an element ends. For each
97 |  |
          * call of <code>elementStart()</code> there will be a corresponding call
98 |  |
          * of this method. Concrete sub classes must implement it to perform a
99 |  |
          * proper event handling.
100 |  |
          *
101 |  |
          * @param name the name of the ending element
102 |  |
          */
103 |  |
         protected abstract void elementEnd(String name);
104 |  |
105 |  |
         /**
106 |  |
          * Fires all necessary element end events for the specified keys. This
107 |  |
          * method is called for each key obtained from the configuration to be
108 |  |
          * converted. It calculates the common part of the actual and the last
109 |  |
          * processed key and thus determines how many elements must be
110 |  |
          * closed.
111 |  |
          *
112 |  |
          * @param keyLast the last processed key
113 |  |
          * @param keyAct the actual key
114 |  |
          */
115 |  |
         protected void closeElements(ConfigurationKey keyLast, ConfigurationKey keyAct)
116 |  |
         {
117 | 33 |
             ConfigurationKey keyDiff = keyAct.differenceKey(keyLast);
118 | 33 |
             Iterator it = reverseIterator(keyDiff);
119 | 33 |
             if (it.hasNext())
120 |  |
             {
121 |  |
                 // Skip first because it has already been closed by fireValue()
122 | 30 |
                 it.next();
123 |  |
             }
124 |  |
125 | 48 |
             while (it.hasNext())
126 |  |
             {
127 | 15 |
                 elementEnd((String) it.next());
128 |  |
             }
129 | 33 |
         }
130 |  |
131 |  |
         /**
132 |  |
          * Helper method for determining a reverse iterator for the specified key.
133 |  |
          * This implementation returns an iterator that returns the parts of the
134 |  |
          * given key in reverse order, ignoring indices.
135 |  |
          *
136 |  |
          * @param key the key
137 |  |
          * @return a reverse iterator for the parts of this key
138 |  |
          */
139 |  |
         protected Iterator reverseIterator(ConfigurationKey key)
140 |  |
         {
141 | 33 |
             List list = new ArrayList();
142 | 111 |
             for (ConfigurationKey.KeyIterator it = key.iterator(); it.hasNext();)
143 |  |
             {
144 | 45 |
                 list.add(it.nextKey());
145 |  |
             }
146 |  |
147 | 33 |
             Collections.reverse(list);
148 | 33 |
             return list.iterator();
149 |  |
         }
150 |  |
151 |  |
         /**
152 |  |
          * Fires all necessary element start events for the specified key. This
153 |  |
          * method is called for each key obtained from the configuration to be
154 |  |
          * converted. It ensures that all elements "between" the last key and the
155 |  |
          * actual key are opened and their values are set.
156 |  |
          *
157 |  |
          * @param keyLast the last processed key
158 |  |
          * @param keyAct the actual key
159 |  |
          * @param config the configuration to process
160 |  |
          * @param keySet the set with the processed keys
161 |  |
          * @return the name of the last element on the path
162 |  |
          */
163 |  |
         protected String openElements(ConfigurationKey keyLast, ConfigurationKey keyAct, Configuration config, Set keySet)
164 |  |
         {
165 | 30 |
             ConfigurationKey.KeyIterator it = keyLast.differenceKey(keyAct).iterator();
166 | 30 |
             ConfigurationKey k = keyLast.commonKey(keyAct);
167 | 45 |
             for (it.nextKey(); it.hasNext(); it.nextKey())
168 |  |
             {
169 | 15 |
                 k.append(it.currentKey(true));
170 | 15 |
                 elementStart(it.currentKey(true), config.getProperty(k.toString()));
171 | 15 |
                 keySet.add(k.toString());
172 |  |
             }
173 | 30 |
             return it.currentKey(true);
174 |  |
         }
175 |  |
176 |  |
         /**
177 |  |
          * Fires all necessary element start events with the actual element values.
178 |  |
          * This method is called for each key obtained from the configuration to be
179 |  |
          * processed with the last part of the key as argument. The value can be
180 |  |
          * either a single value or a collection.
181 |  |
          *
182 |  |
          * @param name the name of the actual element
183 |  |
          * @param value the element's value
184 |  |
          */
185 |  |
         protected void fireValue(String name, Object value)
186 |  |
         {
187 | 51 |
             if (value != null && value instanceof Collection)
188 |  |
             {
189 | 33 |
                 for (Iterator it = ((Collection) value).iterator(); it.hasNext();)
190 |  |
                 {
191 | 21 |
                     fireValue(name, it.next());
192 |  |
                 }
193 |  |
             }
194 |  |
             else
195 |  |
             {
196 | 45 |
                 elementStart(name, value);
197 | 45 |
                 elementEnd(name);
198 |  |
             }
199 | 51 |
         }
200 |  |
     }