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

Classes in this File | Line Coverage | Branch Coverage | Complexity

XMLPropertiesConfiguration

83% | 39/47

83% | 5/6

1.9166666666666667;1,917

XMLPropertiesConfiguration$1

100% | 2/2

N/A | N/A

1.9166666666666667;1,917

XMLPropertiesConfiguration$XMLPropertiesHandler

100% | 18/18

100% | 4/4

1.9166666666666667;1,917

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.io.File;

21

     import java.io.PrintWriter;

22

     import java.io.Reader;

23

     import java.io.Writer;

24

     import java.net.URL;

25

     import java.util.Iterator;

26

     import java.util.List;

27

     import javax.xml.parsers.SAXParser;

28

     import javax.xml.parsers.SAXParserFactory;

29

30

     import org.apache.commons.lang.StringEscapeUtils;

31

     import org.apache.commons.lang.StringUtils;

32

33

     import org.xml.sax.Attributes;

34

     import org.xml.sax.EntityResolver;

35

     import org.xml.sax.InputSource;

36

     import org.xml.sax.XMLReader;

37

     import org.xml.sax.helpers.DefaultHandler;

38

39

     /**

40

      * This configuration implements the XML properties format introduced in Java

41

      * 5.0, see http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html.

42

      * An XML properties file looks like this:

43

      *

44

      * <pre>

45

      * &lt;?xml version="1.0"?>

46

      * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

47

      * &lt;properties>

48

      *   &lt;comment>Description of the property list&lt;/comment>

49

      *   &lt;entry key="key1">value1&lt;/entry>

50

      *   &lt;entry key="key2">value2&lt;/entry>

51

      *   &lt;entry key="key3">value3&lt;/entry>

52

      * &lt;/properties>

53

      * </pre>

54

      *

55

      * The Java 5.0 runtime is not required to use this class. The default encoding

56

      * for this configuration format is UTF-8. Note that unlike

57

      * <code>PropertiesConfiguration</code>, <code>XMLPropertiesConfiguration</code>

58

      * does not support includes.

59

      *

60

      * @author Emmanuel Bourg

61

      * @author Alistair Young

62

      * @version $Revision: 439648 $, $Date: 2006-09-02 22:42:10 +0200 (Sa, 02 Sep 2006) $

63

      * @since 1.1

64

      */

65

     public class XMLPropertiesConfiguration extends PropertiesConfiguration

66

     {

67

         /**

68

          * The default encoding (UTF-8 as specified by http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html)

69

          */

70

         private static final String DEFAULT_ENCODING = "UTF-8";

71

72

         // initialization block to set the encoding before loading the file in the constructors

73

         {

74

11

             setEncoding(DEFAULT_ENCODING);

75

         }

76

77

         /**

78

          * Creates an empty XMLPropertyConfiguration object which can be

79

          * used to synthesize a new Properties file by adding values and

80

          * then saving(). An object constructed by this C'tor can not be

81

          * tickled into loading included files because it cannot supply a

82

          * base for relative includes.

83

          */

84

         public XMLPropertiesConfiguration()

85

         {

86

8

             super();

87

8

         }

88

89

         /**

90

          * Creates and loads the xml properties from the specified file.

91

          * The specified file can contain "include" properties which then

92

          * are loaded and merged into the properties.

93

          *

94

          * @param fileName The name of the properties file to load.

95

          * @throws ConfigurationException Error while loading the properties file

96

          */

97

         public XMLPropertiesConfiguration(String fileName) throws ConfigurationException

98

         {

99

2

             super(fileName);

100

2

         }

101

102

         /**

103

          * Creates and loads the xml properties from the specified file.

104

          * The specified file can contain "include" properties which then

105

          * are loaded and merged into the properties.

106

          *

107

          * @param file The properties file to load.

108

          * @throws ConfigurationException Error while loading the properties file

109

          */

110

         public XMLPropertiesConfiguration(File file) throws ConfigurationException

111

         {

112

1

             super(file);

113

1

         }

114

115

         /**

116

          * Creates and loads the xml properties from the specified URL.

117

          * The specified file can contain "include" properties which then

118

          * are loaded and merged into the properties.

119

          *

120

          * @param url The location of the properties file to load.

121

          * @throws ConfigurationException Error while loading the properties file

122

          */

123

         public XMLPropertiesConfiguration(URL url) throws ConfigurationException

124

         {

125

0

             super(url);

126

0

         }

127

128

         public void load(Reader in) throws ConfigurationException

129

         {

130

11

             SAXParserFactory factory = SAXParserFactory.newInstance();

131

11

             factory.setNamespaceAware(false);

132

11

             factory.setValidating(true);

133

134

             try

135

             {

136

11

                 SAXParser parser = factory.newSAXParser();

137

138

11

                 XMLReader xmlReader = parser.getXMLReader();

139

11

                 xmlReader.setEntityResolver(new EntityResolver()

140

                 {

141

11

                     public InputSource resolveEntity(String publicId, String systemId)

142

                     {

143

11

                         return new InputSource(getClass().getClassLoader().getResourceAsStream("properties.dtd"));

144

                     }

145

                 });

146

11

                 xmlReader.setContentHandler(new XMLPropertiesHandler());

147

11

                 xmlReader.parse(new InputSource(in));

148

11

             }

149

             catch (Exception e)

150

             {

151

0

                 throw new ConfigurationException("Unable to parse the configuration file", e);

152

             }

153

154

             // todo: support included properties ?

155

11

         }

156

157

         public void save(Writer out) throws ConfigurationException

158

         {

159

1

             PrintWriter writer = new PrintWriter(out);

160

161

1

             String encoding = getEncoding() != null ? getEncoding() : DEFAULT_ENCODING;

162

1

             writer.println("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>");

163

1

             writer.println("<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">");

164

1

             writer.println("<properties>");

165

166

1

             if (getHeader() != null)

167

             {

168

1

                 writer.println("  <comment>" + StringEscapeUtils.escapeXml(getHeader()) + "</comment>");

169

             }

170

171

1

             Iterator keys = getKeys();

172

5

             while (keys.hasNext())

173

             {

174

3

                 String key = (String) keys.next();

175

3

                 Object value = getProperty(key);

176

177

3

                 if (value instanceof List)

178

                 {

179

0

                     writeProperty(writer, key, (List) value);

180

                 }

181

                 else

182

                 {

183

3

                     writeProperty(writer, key, value);

184

                 }

185

             }

186

187

1

             writer.println("</properties>");

188

1

             writer.flush();

189

1

         }

190

191

         /**

192

          * Write a property.

193

          *

194

          * @param out the output stream

195

          * @param key the key of the property

196

          * @param value the value of the property

197

          */

198

         private void writeProperty(PrintWriter out, String key, Object value)

199

         {

200

             // escape the key

201

3

             String k = StringEscapeUtils.escapeXml(key);

202

203

3

             if (value != null)

204

             {

205

                 // escape the value

206

3

                 String v = StringEscapeUtils.escapeXml(String.valueOf(value));

207

3

                 v = StringUtils.replace(v, String.valueOf(getListDelimiter()), "\\" + getListDelimiter());

208

209

3

                 out.println("  <entry key=\"" + k + "\">" + v + "</entry>");

210

             }

211

             else

212

             {

213

0

                 out.println("  <entry key=\"" + k + "\"/>");

214

             }

215

3

         }

216

217

         /**

218

          * Write a list property.

219

          *

220

          * @param out the output stream

221

          * @param key the key of the property

222

          * @param values a list with all property values

223

          */

224

         private void writeProperty(PrintWriter out, String key, List values)

225

         {

226

0

             for (int i = 0; i < values.size(); i++)

227

             {

228

0

                 writeProperty(out, key, values.get(i));

229

             }

230

0

         }

231

232

         /**

233

          * SAX Handler to parse a XML properties file.

234

          *

235

          * @author Alistair Young

236

          * @since 1.2

237

          */

238

33

         private class XMLPropertiesHandler extends DefaultHandler

239

         {

240

             /** The key of the current entry being parsed. */

241

             private String key;

242

243

             /** The value of the current entry being parsed. */

244

11

             private StringBuffer value = new StringBuffer();

245

246

             /** Indicates that a comment is being parsed. */

247

             private boolean inCommentElement;

248

249

             /** Indicates that an entry is being parsed. */

250

             private boolean inEntryElement;

251

252

             public void startElement(String uri, String localName, String qName, Attributes attrs)

253

             {

254

55

                 if ("comment".equals(qName))

255

                 {

256

11

                     inCommentElement = true;

257

                 }

258

259

55

                 if ("entry".equals(qName))

260

                 {

261

33

                     key = attrs.getValue("key");

262

33

                     inEntryElement = true;

263

                 }

264

55

             }

265

266

             public void endElement(String uri, String localName, String qName)

267

             {

268

55

                 if (inCommentElement)

269

                 {

270

                     // We've just finished a <comment> element so set the header

271

11

                     setHeader(value.toString());

272

11

                     inCommentElement = false;

273

                 }

274

275

55

                 if (inEntryElement)

276

                 {

277

                     // We've just finished an <entry> element, so add the key/value pair

278

33

                     addProperty(key, value.toString());

279

33

                     inEntryElement = false;

280

                 }

281

282

                 // Clear the element value buffer

283

55

                 value = new StringBuffer();

284

55

             }

285

286

             public void characters(char[] chars, int start, int length)

287

             {

288

                 /**

289

                  * We're currently processing an element. All character data from now until

290

                  * the next endElement() call will be the data for this  element.

291

                  */

292

44

                 value.append(chars, start, length);

293

44

             }

294

         }

295

     }