oheger 2004/11/19 11:26:48 Modified: configuration/xdocs changes.xml configuration/src/java/org/apache/commons/configuration HierarchicalXMLConfiguration.java ConfigurationKey.java configuration/src/test/org/apache/commons/configuration TestHierarchicalXMLConfiguration.java Log: Implementation of save() method for HierarchicalXMLConfiguration Revision Changes Path 1.72 +5 -2 jakarta-commons/configuration/xdocs/changes.xml Index: changes.xml =================================================================== RCS file: /home/cvs/jakarta-commons/configuration/xdocs/changes.xml,v retrieving revision 1.71 retrieving revision 1.72 diff -u -r1.71 -r1.72 --- changes.xml 19 Nov 2004 13:19:50 -0000 1.71 +++ changes.xml 19 Nov 2004 19:26:47 -0000 1.72 @@ -8,6 +8,9 @@ <body> <release version="1.1-dev" date="in CVS"> + <action dev="oheger" type="add" issue="31130"> + Added implementation of a save() method for HierarchicalXMLConfiguration. + </action> <action dev="ebourg" type="update"> Constructing a file based configuration with a File no longer throws an exception when the file doesn't exist. @@ -25,12 +28,12 @@ the configuration descriptor is in a JAR file (reported by Grant Ingersoll). </action> <action dev="oheger" type="fix" issue="32236"> - Fixed NPE that where caused in the constructors of file based + Fixed NPE that were caused in the constructors of file based configurations if an invalid file name was specified. </action> <action dev="oheger" type="add" issue="31797"> Added support for optional configuration sources in definition files for - ConfigurationFactory. A new required attribute allows to specify whether a + ConfigurationFactory. A new optional attribute allows to specify whether a configuration source is mandatory or optional. </action> <action dev="ebourg" type="fix"> 1.6 +124 -6 jakarta-commons/configuration/src/java/org/apache/commons/configuration/HierarchicalXMLConfiguration.java Index: HierarchicalXMLConfiguration.java =================================================================== RCS file: /home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/HierarchicalXMLConfiguration.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- HierarchicalXMLConfiguration.java 18 Oct 2004 15:45:10 -0000 1.5 +++ HierarchicalXMLConfiguration.java 19 Nov 2004 19:26:48 -0000 1.6 @@ -22,10 +22,22 @@ import java.io.Reader; import java.io.Writer; import java.net.URL; +import java.util.Iterator; + import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -50,7 +62,32 @@ */ public class HierarchicalXMLConfiguration extends HierarchicalConfiguration implements FileConfiguration { + /** Constant for the default root element name.*/ + private static final String DEFAULT_ROOT_NAME = "configuration"; + private FileConfiguration delegate = new FileConfigurationDelegate(); + + /** Stores the name of the root element.*/ + private String rootElementName; + + /** + * Returns the name of the root element. + * @return the name of the root element + */ + public String getRootElementName() + { + return (rootElementName == null) ? DEFAULT_ROOT_NAME : rootElementName; + } + + /** + * Sets the name of the root element. This name is used when this + * configuration object is stored in an XML file. + * @param name the name of the root element + */ + public void setRootElementName(String name) + { + rootElementName = name; + } /** * Initializes this configuration from an XML document. @@ -121,7 +158,69 @@ } } } - + + /** + * Creates a DOM document from the internal tree of configuration nodes. + * @return the new document + * @throws ConfigurationException if an error occurs + */ + protected Document createDocument() throws ConfigurationException + { + try + { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document document = builder.newDocument(); + Element rootElem = document.createElement(getRootElementName()); + document.appendChild(rootElem); + constructDOM(document, getRoot(), rootElem); + return document; + } /* try */ + catch(DOMException domEx) + { + throw new ConfigurationException(domEx); + } + catch(ParserConfigurationException pex) + { + throw new ConfigurationException(pex); + } + } + + /** + * Creates a DOM from the tree of configuration nodes. + * @param document the document + * @param node the actual node + * @param element the actual XML element + * @throws DOMException if an error occurs + */ + private void constructDOM(Document document, Node node, Element element) + throws DOMException + { + for(Iterator it = node.getChildren().iterator(); it.hasNext();) + { + Node child = (Node) it.next(); + if(ConfigurationKey.isAttributeKey(child.getName())) + { + if (child.getValue() != null) + { + element.setAttribute(ConfigurationKey.removeAttributeMarkers( + child.getName()), child.getValue().toString()); + } + } + else + { + Element childElem = document.createElement(child.getName()); + if(child.getValue() != null) + { + Text text = document.createTextNode(child.getValue().toString()); + childElem.appendChild(text); + + } + constructDOM(document, child, childElem); + element.appendChild(childElem); + } + } + } + public void load() throws ConfigurationException { delegate.load(); @@ -195,10 +294,29 @@ delegate.save(out, encoding); } - public void save(Writer out) throws ConfigurationException - { - throw new UnsupportedOperationException("Can't save HierarchicalXMLConfigurations"); - } + /** + * Saves the configuration to the specified writer. + * + * @param writer + * the writer used to save the configuration + * @throws ConfigurationException if an error occurs + */ + public void save(Writer writer) throws ConfigurationException + { + try + { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + Source source = new DOMSource(createDocument()); + Result result = new StreamResult(writer); + + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.transform(source, result); + } + catch (TransformerException e) + { + throw new ConfigurationException(e.getMessage(), e); + } + } public String getFileName() { 1.6 +2 -2 jakarta-commons/configuration/src/java/org/apache/commons/configuration/ConfigurationKey.java Index: ConfigurationKey.java =================================================================== RCS file: /home/cvs/jakarta-commons/configuration/src/java/org/apache/commons/configuration/ConfigurationKey.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- ConfigurationKey.java 14 Aug 2004 11:23:14 -0000 1.5 +++ ConfigurationKey.java 19 Nov 2004 19:26:48 -0000 1.6 @@ -172,7 +172,7 @@ * @param key the key * @return the key with removed attribute markers */ - private static String removeAttributeMarkers(String key) + static String removeAttributeMarkers(String key) { return key.substring(ATTRIBUTE_START.length(), key.length() - ATTRIBUTE_END.length()); } 1.3 +30 -2 jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestHierarchicalXMLConfiguration.java Index: TestHierarchicalXMLConfiguration.java =================================================================== RCS file: /home/cvs/jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestHierarchicalXMLConfiguration.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- TestHierarchicalXMLConfiguration.java 6 Sep 2004 13:12:04 -0000 1.2 +++ TestHierarchicalXMLConfiguration.java 19 Nov 2004 19:26:48 -0000 1.3 @@ -45,6 +45,15 @@ /** Test file path #2 **/ private static final String TEST_FILE2 = TEST_DIR + File.separator + TEST_FILENAME2; + + /** Test file path #3.*/ + private static final String TEST_FILE3 = TEST_DIR + File.separator + "test.xml"; + + /** File name for saving.*/ + private static final String TEST_SAVENAME = "testhierarchicalsave.xml"; + + /** File path for saving.*/ + private static final String TEST_SAVE = TEST_DIR + File.separator + TEST_SAVENAME; /** Instance config used for tests. */ private HierarchicalXMLConfiguration config; @@ -144,5 +153,24 @@ } assertEquals("Config must contain only " + KEY_COUNT + " keys.", KEY_COUNT, count); } - + + public void testSave() throws Exception + { + config.setFileName(TEST_FILE3); + config.load(); + File saveFile = new File(TEST_SAVE); + config.setRootElementName("myconfig"); + config.save(saveFile); + + config = new HierarchicalXMLConfiguration(); + config.load(saveFile.toURL()); + assertEquals("value", config.getProperty("element")); + assertEquals("I'm complex!", config.getProperty("element2.subelement.subsubelement")); + assertEquals(8, config.getInt("test.short")); + assertEquals("one", config.getString("list(0).item(0)[EMAIL PROTECTED]")); + assertEquals("two", config.getString("list(0).item(1)")); + assertEquals("six", config.getString("list(1).sublist.item(1)")); + + assertTrue(saveFile.delete()); + } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]