Author: henning Date: Mon Oct 21 22:25:03 2013 New Revision: 1534399 URL: http://svn.apache.org/r1534399 Log: Backport CONFIGURATION-526 from r1449399.
Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/XMLPropertiesConfiguration.java commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestXMLPropertiesConfiguration.java Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt?rev=1534399&r1=1534398&r2=1534399&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/RELEASE-NOTES.txt Mon Oct 21 22:25:03 2013 @@ -80,6 +80,11 @@ IMPROVEMENTS AND NEW FEATURES IN 1.10 The includesAllowed property of PropertyConfiguration is now independent from the existence of a base path. +* [CONFIGURATION-526] Support loading from and saving to DOM nodes + + XMLPropertiesConfiguration now supports loading from and saving to DOM + nodes. + * [CONFIGURATION-550] Missing conversion to char Conversion to Character is now supported. Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml?rev=1534399&r1=1534398&r2=1534399&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/changes/changes.xml Mon Oct 21 22:25:03 2013 @@ -31,6 +31,10 @@ XMLConfiguration now adds attributes of elements defining a list to all list nodes. </action> + <action dev="oheger" type="update" issue="CONFIGURATION-526" due-to="Oliver Kopp"> + XMLPropertiesConfiguration now supports loading from and saving to DOM + nodes. + </action> <action dev="oheger" type="update" issue="CONFIGURATION-534"> The includesAllowed property of PropertyConfiguration is now independent from the existence of a base path. Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/XMLPropertiesConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/XMLPropertiesConfiguration.java?rev=1534399&r1=1534398&r2=1534399&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/XMLPropertiesConfiguration.java (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/main/java/org/apache/commons/configuration/XMLPropertiesConfiguration.java Mon Oct 21 22:25:03 2013 @@ -30,6 +30,10 @@ import javax.xml.parsers.SAXParserFactor import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; @@ -73,6 +77,11 @@ public class XMLPropertiesConfiguration */ private static final String DEFAULT_ENCODING = "UTF-8"; + /** + * Default string used when the XML is malformed + */ + private static final String MALFORMED_XML_EXCEPTION = "Malformed XML"; + // initialization block to set the encoding before loading the file in the constructors { setEncoding(DEFAULT_ENCODING); @@ -129,6 +138,19 @@ public class XMLPropertiesConfiguration super(url); } + /** + * Creates and loads the xml properties from the specified DOM node. + * + * @param element The DOM element + * @throws ConfigurationException Error while loading the properties file + * @since 2.0 + */ + public XMLPropertiesConfiguration(Element element) throws ConfigurationException + { + super(); + this.load(element); + } + @Override public void load(Reader in) throws ConfigurationException { @@ -159,6 +181,44 @@ public class XMLPropertiesConfiguration // todo: support included properties ? } + /** + * Parses a DOM element containing the properties. The DOM element has to follow + * the XML properties format introduced in Java 5.0, + * see http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html + * + * @param element The DOM element + * @throws ConfigurationException Error while interpreting the DOM + * @since 2.0 + */ + public void load(Element element) throws ConfigurationException + { + if (!element.getNodeName().equals("properties")) + { + throw new ConfigurationException(MALFORMED_XML_EXCEPTION); + } + NodeList childNodes = element.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) + { + Node item = childNodes.item(i); + if (item instanceof Element) + { + if (item.getNodeName().equals("comment")) + { + setHeader(item.getTextContent()); + } + else if (item.getNodeName().equals("entry")) + { + String key = ((Element) item).getAttribute("key"); + addProperty(key, item.getTextContent()); + } + else + { + throw new ConfigurationException(MALFORMED_XML_EXCEPTION); + } + } + } + } + @Override public void save(Writer out) throws ConfigurationException { @@ -236,6 +296,67 @@ public class XMLPropertiesConfiguration } /** + * Writes the configuration as child to the given DOM node + * + * @param document The DOM document to add the configuration to + * @param parent The DOM parent node + * @since 2.0 + */ + public void save(Document document, Node parent) + { + Element properties = document.createElement("properties"); + parent.appendChild(properties); + if (getHeader() != null) + { + Element comment = document.createElement("comment"); + properties.appendChild(comment); + comment.setTextContent(StringEscapeUtils.escapeXml(getHeader())); + } + + Iterator<String> keys = getKeys(); + while (keys.hasNext()) + { + String key = keys.next(); + Object value = getProperty(key); + + if (value instanceof List) + { + writeProperty(document, properties, key, (List<?>) value); + } + else + { + writeProperty(document, properties, key, value); + } + } + } + + private void writeProperty(Document document, Node properties, String key, Object value) + { + Element entry = document.createElement("entry"); + properties.appendChild(entry); + + // escape the key + String k = StringEscapeUtils.escapeXml(key); + entry.setAttribute("key", k); + + if (value != null) + { + // escape the value + String v = StringEscapeUtils.escapeXml(String.valueOf(value)); + v = StringUtils.replace(v, String.valueOf(getListDelimiter()), "\\" + getListDelimiter()); + entry.setTextContent(v); + } + } + + private void writeProperty(Document document, Node properties, String key, List<?> values) + { + for (Object value : values) + { + writeProperty(document, properties, key, value); + } + } + + /** * SAX Handler to parse a XML properties file. * * @author Alistair Young Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java?rev=1534399&r1=1534398&r2=1534399&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java Mon Oct 21 22:25:03 2013 @@ -68,6 +68,9 @@ public class TestPropertiesConfiguration /** Constant for a test property value.*/ private static final String PROP_VALUE = "value"; + /** Constant for the line break character. */ + private static final String CR = System.getProperty("line.separator"); + /** The configuration to be tested.*/ private PropertiesConfiguration conf; @@ -165,7 +168,7 @@ public class TestPropertiesConfiguration new StringReader(PropertiesConfiguration.getInclude() + " = " + ConfigurationAssert.getTestURL("include.properties")); conf = new PropertiesConfiguration(); - conf.read(in); + conf.load(in); assertEquals("Include file not loaded", "true", conf.getString("include.loaded")); } @@ -184,7 +187,7 @@ public class TestPropertiesConfiguration StringReader in = new StringReader(content); conf = new PropertiesConfiguration(); conf.setIncludesAllowed(false); - conf.read(in); + conf.load(in); assertEquals("Data not loaded", PROP_VALUE, conf.getString(PROP_NAME)); } Modified: commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestXMLPropertiesConfiguration.java URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestXMLPropertiesConfiguration.java?rev=1534399&r1=1534398&r2=1534399&view=diff ============================================================================== --- commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestXMLPropertiesConfiguration.java (original) +++ commons/proper/configuration/branches/CONFIGURATION_1_X_MAINTENANCE/src/test/java/org/apache/commons/configuration/TestXMLPropertiesConfiguration.java Mon Oct 21 22:25:03 2013 @@ -22,8 +22,18 @@ import static org.junit.Assert.assertFal import static org.junit.Assert.assertTrue; import java.io.File; +import java.net.URL; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Result; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import org.junit.Test; +import org.w3c.dom.Document; /** * @author Emmanuel Bourg @@ -45,6 +55,24 @@ public class TestXMLPropertiesConfigurat } @Test + public void testDOMLoad() throws Exception + { + URL location = ConfigurationUtils.locate(FileSystem.getDefaultFileSystem(), null, "test.properties.xml"); + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + File file = new File(location.toURI()); + Document doc = dBuilder.parse(file); + XMLPropertiesConfiguration conf = new XMLPropertiesConfiguration(doc.getDocumentElement()); + + assertEquals("header", "Description of the property list", conf.getHeader()); + + assertFalse("The configuration is empty", conf.isEmpty()); + assertEquals("'key1' property", "value1", conf.getProperty("key1")); + assertEquals("'key2' property", "value2", conf.getProperty("key2")); + assertEquals("'key3' property", "value3", conf.getProperty("key3")); + } + + @Test public void testSave() throws Exception { // load the configuration @@ -74,4 +102,45 @@ public class TestXMLPropertiesConfigurat assertEquals("'key3' property", "value3", conf2.getProperty("key3")); assertEquals("'key4' property", "value4", conf2.getProperty("key4")); } + + @Test + public void testDOMSave() throws Exception + { + // load the configuration + XMLPropertiesConfiguration conf = new XMLPropertiesConfiguration("test.properties.xml"); + + // update the configuration + conf.addProperty("key4", "value4"); + conf.clearProperty("key2"); + conf.setHeader("Description of the new property list"); + + // save the configuration + File saveFile = new File("target/test2.properties.xml"); + if (saveFile.exists()) + { + assertTrue(saveFile.delete()); + } + + // save as DOM into saveFile + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document document = dBuilder.newDocument(); + conf.save(document, document); + TransformerFactory tFactory = TransformerFactory.newInstance(); + Transformer transformer = tFactory.newTransformer(); + DOMSource source = new DOMSource(document); + Result result = new StreamResult(saveFile); + transformer.transform(source, result); + + // reload the configuration + XMLPropertiesConfiguration conf2 = new XMLPropertiesConfiguration(saveFile); + + // test the configuration + assertEquals("header", "Description of the new property list", conf2.getHeader()); + + assertFalse("The configuration is empty", conf2.isEmpty()); + assertEquals("'key1' property", "value1", conf2.getProperty("key1")); + assertEquals("'key3' property", "value3", conf2.getProperty("key3")); + assertEquals("'key4' property", "value4", conf2.getProperty("key4")); + } }