##### 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

     }