Return-Path: Delivered-To: apmail-jakarta-commons-dev-archive@www.apache.org Received: (qmail 63253 invoked from network); 8 May 2007 20:56:07 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 8 May 2007 20:56:07 -0000 Received: (qmail 82848 invoked by uid 500); 8 May 2007 20:56:12 -0000 Delivered-To: apmail-jakarta-commons-dev-archive@jakarta.apache.org Received: (qmail 82613 invoked by uid 500); 8 May 2007 20:56:11 -0000 Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "Jakarta Commons Developers List" Reply-To: "Jakarta Commons Developers List" Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 82602 invoked by uid 500); 8 May 2007 20:56:11 -0000 Received: (qmail 82599 invoked by uid 99); 8 May 2007 20:56:11 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 08 May 2007 13:56:11 -0700 X-ASF-Spam-Status: No, hits=-99.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 08 May 2007 13:56:03 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id C1BF71A983E; Tue, 8 May 2007 13:55:43 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r536326 - in /jakarta/commons/proper/configuration/trunk: conf/test.xml src/java/org/apache/commons/configuration/XMLConfiguration.java src/test/org/apache/commons/configuration/TestXMLConfiguration.java xdocs/changes.xml Date: Tue, 08 May 2007 20:55:43 -0000 To: commons-cvs@jakarta.apache.org From: oheger@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070508205543.C1BF71A983E@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: oheger Date: Tue May 8 13:55:42 2007 New Revision: 536326 URL: http://svn.apache.org/viewvc?view=rev&rev=536326 Log: CONFIGURATION-268: Perform correct splitting and escaping when delimiter parsing is disabled for XMLConfiguration Modified: jakarta/commons/proper/configuration/trunk/conf/test.xml jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/XMLConfiguration.java jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Modified: jakarta/commons/proper/configuration/trunk/conf/test.xml URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/conf/test.xml?view=diff&rev=536326&r1=536325&r2=536326 ============================================================================== --- jakarta/commons/proper/configuration/trunk/conf/test.xml (original) +++ jakarta/commons/proper/configuration/trunk/conf/test.xml Tue May 8 13:55:42 2007 @@ -85,4 +85,9 @@ 1,2,3 value1,value2 + + + Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/XMLConfiguration.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/XMLConfiguration.java?view=diff&rev=536326&r1=536325&r2=536326 ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/XMLConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/XMLConfiguration.java Tue May 8 13:55:42 2007 @@ -40,7 +40,6 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.apache.commons.collections.iterators.SingletonIterator; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.DOMException; @@ -93,6 +92,35 @@ * cite element the comma is escaped, so that no splitting is * performed.

* + *

The configuration API allows setting multiple values for a single attribute, + * e.g. something like the following is legal (assuming that the default + * expression engine is used): + *

+ * XMLConfiguration config = new XMLConfiguration();
+ * config.addProperty("test.dir[@name]", "C:\\Temp\\");
+ * config.addProperty("test.dir[@name]", "D:\\Data\\");
+ * 

+ * + *

Because in XML such a constellation is not directly supported (an attribute + * can appear only once for a single element), the values are concatenated to a + * single value. If delimiter parsing is enabled (refer to the + * {@link #setDelimiterParsingDisabled(boolean)} method), the + * current list delimiter character will be used as separator. Otherwise the + * pipe symbol ("|") will be used for this purpose. No matter which character is + * used as delimiter, it can always be escaped with a backslash. A backslash + * itself can also be escaped with another backslash. Consider the following + * example fragment from a configuration file: + *

+ * <directories names="C:\Temp\\|D:\Data\"/>
+ * 
+ * Here the backslash after Temp is escaped. This is necessary because it + * would escape the list delimiter (the pipe symbol assuming that list delimiter + * parsing is disabled) otherwise. So this attribute would have two values.

+ * + *

Note: You should ensure that the delimiter parsing disabled + * property is always consistent when you load and save a configuration file. + * Otherwise the values of properties can become corrupted.

+ * *

XMLConfiguration implements the {@link FileConfiguration} * interface and thus provides full support for loading XML documents from * different sources like files, URLs, or streams. A full description of these @@ -102,7 +130,7 @@ * @since commons-configuration 1.0 * * @author Jörg Schaible - * @author Oliver Heger + * @author Oliver Heger * @version $Revision$, $Date$ */ public class XMLConfiguration extends AbstractHierarchicalFileConfiguration @@ -115,6 +143,9 @@ /** Constant for the default root element name. */ private static final String DEFAULT_ROOT_NAME = "configuration"; + /** Constant for the delimiter for multiple attribute values.*/ + private static final char ATTR_VALUE_DELIMITER = '|'; + /** The document from this configuration's data source. */ private Document document; @@ -432,15 +463,10 @@ if (w3cNode instanceof Attr) { Attr attr = (Attr) w3cNode; - Iterator it; - if (isDelimiterParsingDisabled()) - { - it = new SingletonIterator(attr.getValue()); - } - else - { - it = PropertyConverter.split(attr.getValue(), getListDelimiter()).iterator(); - } + Iterator it = PropertyConverter.split( + attr.getValue(), + isDelimiterParsingDisabled() ? ATTR_VALUE_DELIMITER + : getListDelimiter()).iterator(); while (it.hasNext()) { Node child = new XMLNode(attr.getName(), @@ -570,7 +596,8 @@ document = newDocument; } - XMLBuilderVisitor builder = new XMLBuilderVisitor(document, getListDelimiter()); + XMLBuilderVisitor builder = new XMLBuilderVisitor(document, + isDelimiterParsingDisabled() ? (char) 0 : getListDelimiter()); builder.processDocument(getRoot()); return document; } /* try */ @@ -966,8 +993,12 @@ Element elem = document.createElement(newNode.getName()); if (newNode.getValue() != null) { - elem.appendChild(document.createTextNode( - PropertyConverter.escapeDelimiters(newNode.getValue().toString(), listDelimiter))); + String txt = newNode.getValue().toString(); + if (listDelimiter != 0) + { + txt = PropertyConverter.escapeDelimiters(txt, listDelimiter); + } + elem.appendChild(document.createTextNode(txt)); } if (sibling2 == null) { @@ -992,7 +1023,7 @@ * @param node the affected node * @param elem the element that is associated with this node * @param name the name of the affected attribute - * @param listDelimiter the delimiter vor attributes with multiple values + * @param listDelimiter the delimiter for attributes with multiple values */ private static void updateAttribute(Node node, Element elem, String name, char listDelimiter) { @@ -1000,6 +1031,7 @@ { List attrs = node.getAttributes(name); StringBuffer buf = new StringBuffer(); + char delimiter = (listDelimiter != 0) ? listDelimiter : ATTR_VALUE_DELIMITER; for (Iterator it = attrs.iterator(); it.hasNext();) { Node attr = (Node) it.next(); @@ -1007,10 +1039,10 @@ { if (buf.length() > 0) { - buf.append(listDelimiter); + buf.append(delimiter); } buf.append(PropertyConverter.escapeDelimiters(attr - .getValue().toString(), getDefaultListDelimiter())); + .getValue().toString(), delimiter)); } attr.setReference(elem); } Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java?view=diff&rev=536326&r1=536325&r2=536326 ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java Tue May 8 13:55:42 2007 @@ -1062,6 +1062,76 @@ } /** + * Tests saving and loading a configuration when delimiter parsing is + * disabled. + */ + public void testSaveDelimiterParsingDisabled() + throws ConfigurationException + { + checkSaveDelimiterParsingDisabled("list.delimiter.test"); + } + + /** + * Tests saving and loading a configuration when delimiter parsing is + * disabled and attributes are involved. + */ + public void testSaveDelimiterParsingDisabledAttrs() + throws ConfigurationException + { + checkSaveDelimiterParsingDisabled("list.delimiter.test[@attr]"); + } + + /** + * Helper method for testing saving and loading a configuration when + * delimiter parsing is disabled. + * + * @param key the key to be checked + * @throws ConfigurationException if an error occurs + */ + private void checkSaveDelimiterParsingDisabled(String key) + throws ConfigurationException + { + conf.clear(); + conf.setDelimiterParsingDisabled(true); + conf.load(); + conf.setProperty(key, "C:\\Temp\\,C:\\Data\\"); + conf.addProperty(key, "a,b,c"); + conf.save(testSaveConf); + XMLConfiguration checkConf = new XMLConfiguration(); + checkConf.setDelimiterParsingDisabled(true); + checkConf.setFile(testSaveConf); + checkSavedConfig(checkConf); + } + + /** + * Tests multiple attribute values in delimiter parsing disabled mode. + */ + public void testDelimiterParsingDisabledMultiAttrValues() throws ConfigurationException + { + conf.clear(); + conf.setDelimiterParsingDisabled(true); + conf.load(); + List expr = conf.getList("expressions[@value]"); + assertEquals("Wrong list size", 2, expr.size()); + assertEquals("Wrong element 1", "a || (b && c)", expr.get(0)); + assertEquals("Wrong element 2", "!d", expr.get(1)); + } + + /** + * Tests using multiple attribute values, which are partly escaped when + * delimiter parsing is not disabled. + */ + public void testMultipleAttrValuesEscaped() throws ConfigurationException + { + conf.addProperty("test.dir[@name]", "C:\\Temp\\"); + conf.addProperty("test.dir[@name]", "C:\\Data\\"); + conf.save(testSaveConf); + XMLConfiguration checkConf = new XMLConfiguration(); + checkConf.setFile(testSaveConf); + checkSavedConfig(checkConf); + } + + /** * Prepares a configuration object for testing a reload operation. * * @return the initialized configuration Modified: jakarta/commons/proper/configuration/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/changes.xml?view=diff&rev=536326&r1=536325&r2=536326 ============================================================================== --- jakarta/commons/proper/configuration/trunk/xdocs/changes.xml (original) +++ jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Tue May 8 13:55:42 2007 @@ -23,6 +23,12 @@ + + When delimiter parsing was disabled for XMLConfiguration, saving and + loading the configuration accidently added escape characters to properties + containing the list delimiter character. This has been fixed. It is now + also possible to escape the escape character itself. + The return value of FileConfiguration.getFile() is now always consistent with the result of getURL(). --------------------------------------------------------------------- To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: commons-dev-help@jakarta.apache.org