~ubuntu-branches/ubuntu/saucy/commons-configuration/saucy

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/commons/configuration/XMLPropertiesConfiguration.java

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg
  • Date: 2013-07-01 16:29:44 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130701162944-98waq5gogha5gpn1
Tags: 1.9-1
* New upstream release
* debian/control:
  - Updated Standards-Version to 3.9.4 (no changes)
  - Use canonical URLs for the Vcs-* fields
  - Added new build dependencies (libjavacc-maven-plugin-java, junit4)
  - Upgraded the dependency on the Servlet API (2.5 -> 3.0)
  - Removed the dependency on the Activation Framework (glassfish-activation)
  - Replaced the dependency on glassfish-mail with libgnumail-java
  - Removed the unused dependencies:
    liblog4j1.2-java-doc, libmaven-assembly-plugin-java
  - Replaced the dependency on libcommons-jexl-java by libcommons-jexl2-java
* debian/watch: Changed to point the official Apache distribution server
* Removed the obsolete file debian/ant.properties
* Installed the upstream changelog in the binary packages
* Added the report plugins to maven.ignoreRules
* Added the classpath attribute to the jar manifest

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
28
import javax.xml.parsers.SAXParser;
 
29
import javax.xml.parsers.SAXParserFactory;
 
30
 
 
31
import org.apache.commons.lang.StringEscapeUtils;
 
32
import org.apache.commons.lang.StringUtils;
 
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 XMLPropertiesConfiguration}
 
58
 * does not support includes.
 
59
 *
 
60
 * <em>Note:</em>Configuration objects of this type can be read concurrently
 
61
 * by multiple threads. However if one of these threads modifies the object,
 
62
 * synchronization has to be performed manually.
 
63
 *
 
64
 * @author Emmanuel Bourg
 
65
 * @author Alistair Young
 
66
 * @version $Id: XMLPropertiesConfiguration.java 1210207 2011-12-04 20:43:50Z oheger $
 
67
 * @since 1.1
 
68
 */
 
69
public class XMLPropertiesConfiguration extends PropertiesConfiguration
 
70
{
 
71
    /**
 
72
     * The default encoding (UTF-8 as specified by http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html)
 
73
     */
 
74
    private static final String DEFAULT_ENCODING = "UTF-8";
 
75
 
 
76
    // initialization block to set the encoding before loading the file in the constructors
 
77
    {
 
78
        setEncoding(DEFAULT_ENCODING);
 
79
    }
 
80
 
 
81
    /**
 
82
     * Creates an empty XMLPropertyConfiguration object which can be
 
83
     * used to synthesize a new Properties file by adding values and
 
84
     * then saving(). An object constructed by this C'tor can not be
 
85
     * tickled into loading included files because it cannot supply a
 
86
     * base for relative includes.
 
87
     */
 
88
    public XMLPropertiesConfiguration()
 
89
    {
 
90
        super();
 
91
    }
 
92
 
 
93
    /**
 
94
     * Creates and loads the xml properties from the specified file.
 
95
     * The specified file can contain "include" properties which then
 
96
     * are loaded and merged into the properties.
 
97
     *
 
98
     * @param fileName The name of the properties file to load.
 
99
     * @throws ConfigurationException Error while loading the properties file
 
100
     */
 
101
    public XMLPropertiesConfiguration(String fileName) throws ConfigurationException
 
102
    {
 
103
        super(fileName);
 
104
    }
 
105
 
 
106
    /**
 
107
     * Creates and loads the xml properties from the specified file.
 
108
     * The specified file can contain "include" properties which then
 
109
     * are loaded and merged into the properties.
 
110
     *
 
111
     * @param file The properties file to load.
 
112
     * @throws ConfigurationException Error while loading the properties file
 
113
     */
 
114
    public XMLPropertiesConfiguration(File file) throws ConfigurationException
 
115
    {
 
116
        super(file);
 
117
    }
 
118
 
 
119
    /**
 
120
     * Creates and loads the xml properties from the specified URL.
 
121
     * The specified file can contain "include" properties which then
 
122
     * are loaded and merged into the properties.
 
123
     *
 
124
     * @param url The location of the properties file to load.
 
125
     * @throws ConfigurationException Error while loading the properties file
 
126
     */
 
127
    public XMLPropertiesConfiguration(URL url) throws ConfigurationException
 
128
    {
 
129
        super(url);
 
130
    }
 
131
 
 
132
    @Override
 
133
    public void load(Reader in) throws ConfigurationException
 
134
    {
 
135
        SAXParserFactory factory = SAXParserFactory.newInstance();
 
136
        factory.setNamespaceAware(false);
 
137
        factory.setValidating(true);
 
138
 
 
139
        try
 
140
        {
 
141
            SAXParser parser = factory.newSAXParser();
 
142
 
 
143
            XMLReader xmlReader = parser.getXMLReader();
 
144
            xmlReader.setEntityResolver(new EntityResolver()
 
145
            {
 
146
                public InputSource resolveEntity(String publicId, String systemId)
 
147
                {
 
148
                    return new InputSource(getClass().getClassLoader().getResourceAsStream("properties.dtd"));
 
149
                }
 
150
            });
 
151
            xmlReader.setContentHandler(new XMLPropertiesHandler());
 
152
            xmlReader.parse(new InputSource(in));
 
153
        }
 
154
        catch (Exception e)
 
155
        {
 
156
            throw new ConfigurationException("Unable to parse the configuration file", e);
 
157
        }
 
158
 
 
159
        // todo: support included properties ?
 
160
    }
 
161
 
 
162
    @Override
 
163
    public void save(Writer out) throws ConfigurationException
 
164
    {
 
165
        PrintWriter writer = new PrintWriter(out);
 
166
 
 
167
        String encoding = getEncoding() != null ? getEncoding() : DEFAULT_ENCODING;
 
168
        writer.println("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>");
 
169
        writer.println("<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">");
 
170
        writer.println("<properties>");
 
171
 
 
172
        if (getHeader() != null)
 
173
        {
 
174
            writer.println("  <comment>" + StringEscapeUtils.escapeXml(getHeader()) + "</comment>");
 
175
        }
 
176
 
 
177
        Iterator<String> keys = getKeys();
 
178
        while (keys.hasNext())
 
179
        {
 
180
            String key = keys.next();
 
181
            Object value = getProperty(key);
 
182
 
 
183
            if (value instanceof List)
 
184
            {
 
185
                writeProperty(writer, key, (List<?>) value);
 
186
            }
 
187
            else
 
188
            {
 
189
                writeProperty(writer, key, value);
 
190
            }
 
191
        }
 
192
 
 
193
        writer.println("</properties>");
 
194
        writer.flush();
 
195
    }
 
196
 
 
197
    /**
 
198
     * Write a property.
 
199
     *
 
200
     * @param out the output stream
 
201
     * @param key the key of the property
 
202
     * @param value the value of the property
 
203
     */
 
204
    private void writeProperty(PrintWriter out, String key, Object value)
 
205
    {
 
206
        // escape the key
 
207
        String k = StringEscapeUtils.escapeXml(key);
 
208
 
 
209
        if (value != null)
 
210
        {
 
211
            // escape the value
 
212
            String v = StringEscapeUtils.escapeXml(String.valueOf(value));
 
213
            v = StringUtils.replace(v, String.valueOf(getListDelimiter()), "\\" + getListDelimiter());
 
214
 
 
215
            out.println("  <entry key=\"" + k + "\">" + v + "</entry>");
 
216
        }
 
217
        else
 
218
        {
 
219
            out.println("  <entry key=\"" + k + "\"/>");
 
220
        }
 
221
    }
 
222
 
 
223
    /**
 
224
     * Write a list property.
 
225
     *
 
226
     * @param out the output stream
 
227
     * @param key the key of the property
 
228
     * @param values a list with all property values
 
229
     */
 
230
    private void writeProperty(PrintWriter out, String key, List<?> values)
 
231
    {
 
232
        for (Object value : values)
 
233
        {
 
234
            writeProperty(out, key, value);
 
235
        }
 
236
    }
 
237
 
 
238
    /**
 
239
     * SAX Handler to parse a XML properties file.
 
240
     *
 
241
     * @author Alistair Young
 
242
     * @since 1.2
 
243
     */
 
244
    private class XMLPropertiesHandler extends DefaultHandler
 
245
    {
 
246
        /** The key of the current entry being parsed. */
 
247
        private String key;
 
248
 
 
249
        /** The value of the current entry being parsed. */
 
250
        private StringBuilder value = new StringBuilder();
 
251
 
 
252
        /** Indicates that a comment is being parsed. */
 
253
        private boolean inCommentElement;
 
254
 
 
255
        /** Indicates that an entry is being parsed. */
 
256
        private boolean inEntryElement;
 
257
 
 
258
        @Override
 
259
        public void startElement(String uri, String localName, String qName, Attributes attrs)
 
260
        {
 
261
            if ("comment".equals(qName))
 
262
            {
 
263
                inCommentElement = true;
 
264
            }
 
265
 
 
266
            if ("entry".equals(qName))
 
267
            {
 
268
                key = attrs.getValue("key");
 
269
                inEntryElement = true;
 
270
            }
 
271
        }
 
272
 
 
273
        @Override
 
274
        public void endElement(String uri, String localName, String qName)
 
275
        {
 
276
            if (inCommentElement)
 
277
            {
 
278
                // We've just finished a <comment> element so set the header
 
279
                setHeader(value.toString());
 
280
                inCommentElement = false;
 
281
            }
 
282
 
 
283
            if (inEntryElement)
 
284
            {
 
285
                // We've just finished an <entry> element, so add the key/value pair
 
286
                addProperty(key, value.toString());
 
287
                inEntryElement = false;
 
288
            }
 
289
 
 
290
            // Clear the element value buffer
 
291
            value = new StringBuilder();
 
292
        }
 
293
 
 
294
        @Override
 
295
        public void characters(char[] chars, int start, int length)
 
296
        {
 
297
            /**
 
298
             * We're currently processing an element. All character data from now until
 
299
             * the next endElement() call will be the data for this  element.
 
300
             */
 
301
            value.append(chars, start, length);
 
302
        }
 
303
    }
 
304
}