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