You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2013/07/07 18:50:29 UTC

svn commit: r1500481 - in /commons/proper/configuration/trunk/src: main/java/org/apache/commons/configuration/ test/java/org/apache/commons/configuration/

Author: oheger
Date: Sun Jul  7 16:50:29 2013
New Revision: 1500481

URL: http://svn.apache.org/r1500481
Log:
PropertiesConfiguration now uses its ListDelimiterHandler when saving its data.

The original code for saving properties file was moved into
LegacyListDelimiterHandler. The new code just delegates to the list delimiter
handler for the correct escaping of properties. Note that it was necessary to
slightly adapt the IOFactory interface.

Modified:
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/LegacyListDelimiterHandler.java
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfiguration.java
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java
    commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/LegacyListDelimiterHandler.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/LegacyListDelimiterHandler.java?rev=1500481&r1=1500480&r2=1500481&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/LegacyListDelimiterHandler.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/LegacyListDelimiterHandler.java Sun Jul  7 16:50:29 2013
@@ -241,7 +241,7 @@ public class LegacyListDelimiterHandler 
             strValue = StringUtils.replace(strValue, DOUBLE_ESC, QUAD_ESC);
         }
 
-        return StringUtils.replace(strValue, ESCAPE, DOUBLE_ESC);
+        return strValue;
     }
 
     /**

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfiguration.java?rev=1500481&r1=1500480&r2=1500481&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfiguration.java Sun Jul  7 16:50:29 2013
@@ -24,7 +24,6 @@ import java.io.Reader;
 import java.io.Writer;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -223,12 +222,6 @@ public class PropertiesConfiguration ext
     /** Constant for the platform specific line separator.*/
     private static final String LINE_SEPARATOR = System.getProperty("line.separator");
 
-    /** Constant for the escaping character.*/
-    private static final String ESCAPE = "\\";
-
-    /** Constant for the escaped escaping character.*/
-    private static final String DOUBLE_ESC = ESCAPE + ESCAPE;
-
     /** Constant for the radix of hex numbers.*/
     private static final int HEX_RADIX = 16;
 
@@ -639,7 +632,7 @@ public class PropertiesConfiguration ext
         private static final int IDX_SEPARATOR = 3;
 
         /** Stores the comment lines for the currently processed property.*/
-        private List<String> commentLines;
+        private final List<String> commentLines;
 
         /** Stores the name of the last read property.*/
         private String propertyName;
@@ -650,9 +643,6 @@ public class PropertiesConfiguration ext
         /** Stores the property separator of the last read property.*/
         private String propertySeparator = DEFAULT_SEPARATOR;
 
-        /** Stores the list delimiter character.*/
-        private char delimiter;
-
         /**
          * Constructor.
          *
@@ -660,22 +650,8 @@ public class PropertiesConfiguration ext
          */
         public PropertiesReader(Reader reader)
         {
-            this(reader, AbstractConfiguration.getDefaultListDelimiter());
-        }
-
-        /**
-         * Creates a new instance of {@code PropertiesReader} and sets
-         * the underlying reader and the list delimiter.
-         *
-         * @param reader the reader
-         * @param listDelimiter the list delimiter character
-         * @since 1.3
-         */
-        public PropertiesReader(Reader reader, char listDelimiter)
-        {
             super(reader);
             commentLines = new ArrayList<String>();
-            delimiter = listDelimiter;
         }
 
         /**
@@ -844,7 +820,7 @@ public class PropertiesConfiguration ext
          */
         protected void initPropertyValue(String value)
         {
-            propertyValue = unescapeJava(value, delimiter);
+            propertyValue = unescapeJava(value);
         }
 
         /**
@@ -914,11 +890,23 @@ public class PropertiesConfiguration ext
                         new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()),
                         UnicodeEscaper.outsideOf(32, 0x7f));
 
-        /** Constant for the initial size when creating a string buffer. */
-        private static final int BUF_SIZE = 8;
+        /**
+         * A {@code ValueTransformer} implementation used to escape property
+         * values. This implementation applies the transformation defined by the
+         * {@link #ESCAPE_PROPERTIES} translator.
+         */
+        private static final ValueTransformer TRANSFORMER =
+                new ValueTransformer()
+                {
+                    public Object transformValue(Object value)
+                    {
+                        String strVal = String.valueOf(value);
+                        return ESCAPE_PROPERTIES.translate(strVal);
+                    }
+                };
 
-        /** The delimiter for multi-valued properties.*/
-        private final char delimiter;
+        /** The list delimiter handler.*/
+        private final ListDelimiterHandler delimiterHandler;
 
         /** The separator to be used for the current property. */
         private String currentSeparator;
@@ -930,28 +918,29 @@ public class PropertiesConfiguration ext
         private String lineSeparator;
 
         /**
-         * Constructor.
+         * Creates a new instance of {@code PropertiesWriter}.
          *
          * @param writer a Writer object providing the underlying stream
-         * @param delimiter the delimiter character for multi-valued properties
+         * @param delHandler the delimiter handler for dealing with properties
+         *        with multiple values
          */
-        public PropertiesWriter(Writer writer, char delimiter)
+        public PropertiesWriter(Writer writer, ListDelimiterHandler delHandler)
         {
             super(writer);
-            this.delimiter = delimiter;
+            delimiterHandler = delHandler;
         }
 
         /**
-         * Returns the delimiter for properties with multiple values. This is
-         * the list delimiter character. A value of '\0' means that no delimiter
-         * is defined.
+         * Returns the delimiter handler for properties with multiple values.
+         * This object is used to escape property values so that they can be
+         * read in correctly the next time they are loaded.
          *
-         * @return the delimiter for properties with multiple values
+         * @return the delimiter handler for properties with multiple values
          * @since 2.0
          */
-        public char getDelimiter()
+        public ListDelimiterHandler getDelimiterHandler()
         {
-            return delimiter;
+            return delimiterHandler;
         }
 
         /**
@@ -1075,12 +1064,22 @@ public class PropertiesConfiguration ext
 
             if (value instanceof List)
             {
+                v = null;
                 List<?> values = (List<?>) value;
                 if (forceSingleLine)
                 {
-                    v = makeSingleLineValue(values);
+                    try
+                    {
+                        v = String.valueOf(getDelimiterHandler()
+                                        .escapeList(values, TRANSFORMER));
+                    }
+                    catch (UnsupportedOperationException uoex)
+                    {
+                        // the handler may not support escaping lists,
+                        // then the list is written in multiple lines
+                    }
                 }
-                else
+                if (v == null)
                 {
                     writeProperty(key, values);
                     return;
@@ -1088,7 +1087,7 @@ public class PropertiesConfiguration ext
             }
             else
             {
-                v = escapeValue(value, false);
+                v = String.valueOf(getDelimiterHandler().escape(value, TRANSFORMER));
             }
 
             write(escapeKey(key));
@@ -1143,108 +1142,6 @@ public class PropertiesConfiguration ext
         }
 
         /**
-         * Escapes the given property value. This method is called on saving the
-         * configuration for each property value. It ensures a correct handling
-         * of backslash characters and also takes care that list delimiter
-         * characters in the value are escaped.
-         *
-         * @param value the property value
-         * @param inList a flag whether the value is part of a list
-         * @return the escaped property value
-         * @since 2.0
-         */
-        protected String escapeValue(Object value, boolean inList)
-        {
-            String escapedValue =
-                    ESCAPE_PROPERTIES
-                            .translate(escapeBackslashs(value, inList));
-            if (getDelimiter() != 0)
-            {
-                escapedValue =
-                        StringUtils.replace(escapedValue,
-                                String.valueOf(getDelimiter()), ESCAPE
-                                        + getDelimiter());
-            }
-            return escapedValue;
-        }
-
-        /**
-         * Performs the escaping of backslashes in the specified properties
-         * value. Because a double backslash is used to escape the escape
-         * character of a list delimiter, double backslashes also have to be
-         * escaped if the property is part of a (single line) list. Then, in all
-         * cases each backslash has to be doubled in order to produce a valid
-         * properties file. This method is called by {@code escapeValue()}.
-         *
-         * @param value the value to be escaped
-         * @param inList a flag whether the value is part of a list
-         * @return the value with escaped backslashes as string
-         * @since 2.0
-         */
-        protected String escapeBackslashs(Object value, boolean inList)
-        {
-            String strValue = String.valueOf(value);
-
-            if (inList && strValue.indexOf(DOUBLE_ESC) >= 0)
-            {
-                char esc = ESCAPE.charAt(0);
-                StringBuilder buf = new StringBuilder(strValue.length() + BUF_SIZE);
-                for (int i = 0; i < strValue.length(); i++)
-                {
-                    if (strValue.charAt(i) == esc && i < strValue.length() - 1
-                            && strValue.charAt(i + 1) == esc)
-                    {
-                        buf.append(DOUBLE_ESC).append(DOUBLE_ESC);
-                        i++;
-                    }
-                    else
-                    {
-                        buf.append(strValue.charAt(i));
-                    }
-                }
-
-                strValue = buf.toString();
-            }
-
-            return strValue;
-        }
-
-        /**
-         * Transforms a list of values into a single line value.
-         *
-         * @param values the list with the values
-         * @return a string with the single line value (can be <b>null</b>)
-         * @since 1.3
-         */
-        private String makeSingleLineValue(List<?> values)
-        {
-            if (!values.isEmpty())
-            {
-                Iterator<?> it = values.iterator();
-                String lastValue = escapeValue(it.next(), true);
-                StringBuilder buf = new StringBuilder(lastValue);
-                while (it.hasNext())
-                {
-                    // if the last value ended with an escape character, it has
-                    // to be escaped itself; otherwise the list delimiter will
-                    // be escaped
-                    if (lastValue.endsWith(ESCAPE) && (countTrailingBS(lastValue) / 2) % 2 != 0)
-                    {
-                        buf.append(ESCAPE).append(ESCAPE);
-                    }
-                    buf.append(getDelimiter());
-                    lastValue = escapeValue(it.next(), true);
-                    buf.append(lastValue);
-                }
-                return buf.toString();
-            }
-            else
-            {
-                return null;
-            }
-        }
-
-        /**
          * Helper method for writing a line with the platform specific line
          * ending.
          *
@@ -1312,11 +1209,10 @@ public class PropertiesConfiguration ext
          * by this method is then used for parsing the properties file.
          *
          * @param in the underlying reader (of the properties file)
-         * @param delimiter the delimiter character for list parsing
          * @return the {@code PropertiesReader} for loading the
          *         configuration
          */
-        PropertiesReader createPropertiesReader(Reader in, char delimiter);
+        PropertiesReader createPropertiesReader(Reader in);
 
         /**
          * Creates a {@code PropertiesWriter} for writing a properties
@@ -1325,11 +1221,12 @@ public class PropertiesConfiguration ext
          * this method is then used for writing the properties file.
          *
          * @param out the underlying writer (to the properties file)
-         * @param delimiter the delimiter character for list parsing
+         * @param handler the list delimiter delimiter for list parsing
          * @return the {@code PropertiesWriter} for saving the
          *         configuration
          */
-        PropertiesWriter createPropertiesWriter(Writer out, char delimiter);
+        PropertiesWriter createPropertiesWriter(Writer out,
+                ListDelimiterHandler handler);
     }
 
     /**
@@ -1349,15 +1246,15 @@ public class PropertiesConfiguration ext
      */
     public static class DefaultIOFactory implements IOFactory
     {
-        public PropertiesReader createPropertiesReader(Reader in, char delimiter)
+        public PropertiesReader createPropertiesReader(Reader in)
         {
-            return new PropertiesReader(in, delimiter);
+            return new PropertiesReader(in);
         }
 
         public PropertiesWriter createPropertiesWriter(Writer out,
-                char delimiter)
+                ListDelimiterHandler handler)
         {
-            return new PropertiesWriter(out, delimiter);
+            return new PropertiesWriter(out, handler);
         }
     }
 
@@ -1368,11 +1265,10 @@ public class PropertiesConfiguration ext
      * drop escaped separators (i.e '\,').
      *
      * @param str  the {@code String} to unescape, may be null
-     * @param delimiter the delimiter for multi-valued properties
      * @return the processed string
      * @throws IllegalArgumentException if the Writer is {@code null}
      */
-    protected static String unescapeJava(String str, char delimiter)
+    protected static String unescapeJava(String str)
     {
         if (str == null)
         {
@@ -1448,11 +1344,6 @@ public class PropertiesConfiguration ext
                 {
                     out.append('\b');
                 }
-                else if (ch == delimiter)
-                {
-                    out.append('\\');
-                    out.append(delimiter);
-                }
                 else if (ch == 'u')
                 {
                     // uh-oh, we're in unicode country....
@@ -1460,6 +1351,7 @@ public class PropertiesConfiguration ext
                 }
                 else
                 {
+                    out.append('\\');
                     out.append(ch);
                 }
 

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java?rev=1500481&r1=1500480&r2=1500481&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java Sun Jul  7 16:50:29 2013
@@ -486,8 +486,7 @@ public class PropertiesConfigurationLayo
             config.removeConfigurationListener(this);
         }
         PropertiesConfiguration.PropertiesReader reader =
-                config.getIOFactory().createPropertiesReader(in,
-                        config.getListDelimiter());
+                config.getIOFactory().createPropertiesReader(in);
 
         try
         {
@@ -552,10 +551,9 @@ public class PropertiesConfigurationLayo
     {
         try
         {
-            char delimiter = config.isDelimiterParsingDisabled() ? 0
-                    : config.getListDelimiter();
-            PropertiesConfiguration.PropertiesWriter writer = config
-                    .getIOFactory().createPropertiesWriter(out, delimiter);
+            PropertiesConfiguration.PropertiesWriter writer =
+                    config.getIOFactory().createPropertiesWriter(out,
+                            config.getListDelimiterHandler());
             writer.setGlobalSeparator(getGlobalSeparator());
             if (getLineSeparator() != null)
             {

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java?rev=1500481&r1=1500480&r2=1500481&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.java Sun Jul  7 16:50:29 2013
@@ -52,6 +52,7 @@ import org.apache.commons.configuration.
 import org.apache.commons.configuration.builder.FileBasedBuilderParametersImpl;
 import org.apache.commons.configuration.builder.combined.CombinedConfigurationBuilder;
 import org.apache.commons.configuration.io.FileHandler;
+import org.apache.commons.lang3.mutable.MutableObject;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -296,19 +297,35 @@ public class TestPropertiesConfiguration
     }
 
     /**
-     * Tests saving a configuration when delimiter parsing is disabled.
+     * Tests saving a configuration if delimiter parsing is disabled.
      */
     @Test
     public void testSaveWithDelimiterParsingDisabled() throws ConfigurationException
     {
         conf.clear();
-        conf.setDelimiterParsingDisabled(true);
+        conf.setListDelimiterHandler(new DisabledListDelimiterHandler());
         conf.addProperty("test.list", "a,b,c");
         conf.addProperty("test.dirs", "C:\\Temp\\,D:\\Data\\");
         saveTestConfig();
 
         PropertiesConfiguration checkConfig = new PropertiesConfiguration();
-        checkConfig.setDelimiterParsingDisabled(true);
+        checkConfig.setListDelimiterHandler(new DisabledListDelimiterHandler());
+        new FileHandler(checkConfig).load(testSavePropertiesFile);
+        ConfigurationAssert.assertEquals(conf, checkConfig);
+    }
+
+    /**
+     * Tests whether saving works correctly with the default list delimiter
+     * handler implementation.
+     */
+    @Test
+    public void testSaveWithDefaultListDelimiterHandler() throws ConfigurationException
+    {
+        conf.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
+        saveTestConfig();
+
+        PropertiesConfiguration checkConfig = new PropertiesConfiguration();
+        checkConfig.setListDelimiterHandler(conf.getListDelimiterHandler());
         new FileHandler(checkConfig).load(testSavePropertiesFile);
         ConfigurationAssert.assertEquals(conf, checkConfig);
     }
@@ -426,7 +443,7 @@ public class TestPropertiesConfiguration
     @Test
     public void testUnescapeJava()
     {
-        assertEquals("test\\,test", PropertiesConfiguration.unescapeJava("test\\,test", ','));
+        assertEquals("test\\,test", PropertiesConfiguration.unescapeJava("test\\,test"));
     }
 
     @Test
@@ -834,14 +851,13 @@ public class TestPropertiesConfiguration
         conf.setIOFactory(new PropertiesConfiguration.IOFactory()
         {
             public PropertiesConfiguration.PropertiesReader createPropertiesReader(
-                    Reader in, char delimiter)
+                    Reader in)
             {
-                return new PropertiesReaderTestImpl(in, delimiter,
-                        propertyCount);
+                return new PropertiesReaderTestImpl(in, propertyCount);
             }
 
             public PropertiesConfiguration.PropertiesWriter createPropertiesWriter(
-                    Writer out, char delimiter)
+                    Writer out, ListDelimiterHandler handler)
             {
                 throw new UnsupportedOperationException("Unexpected call!");
             }
@@ -860,23 +876,32 @@ public class TestPropertiesConfiguration
     @Test
     public void testSetIOFactoryWriter() throws ConfigurationException, IOException
     {
-        final PropertiesWriterTestImpl testWriter = new PropertiesWriterTestImpl(',');
+        final MutableObject<Writer> propertiesWriter = new MutableObject<Writer>();
         conf.setIOFactory(new PropertiesConfiguration.IOFactory()
         {
             public PropertiesConfiguration.PropertiesReader createPropertiesReader(
-                    Reader in, char delimiter)
+                    Reader in)
             {
                 throw new UnsupportedOperationException("Unexpected call!");
             }
 
             public PropertiesConfiguration.PropertiesWriter createPropertiesWriter(
-                    Writer out, char delimiter)
+                    Writer out, ListDelimiterHandler handler)
             {
-                return testWriter;
+                try
+                {
+                    PropertiesWriterTestImpl propWriter = new PropertiesWriterTestImpl(handler);
+                    propertiesWriter.setValue(propWriter);
+                    return propWriter;
+                }
+                catch (IOException e)
+                {
+                    return null;
+                }
             }
         });
         new FileHandler(conf).save(new StringWriter());
-        testWriter.close();
+        propertiesWriter.getValue().close();
         checkSavedConfig();
     }
 
@@ -1248,11 +1273,9 @@ public class TestPropertiesConfiguration
         /** The current number of properties. */
         private int propertyCount;
 
-        public PropertiesReaderTestImpl(Reader reader, char listDelimiter,
-                int maxProps)
+        public PropertiesReaderTestImpl(Reader reader, int maxProps)
         {
-            super(reader, listDelimiter);
-            assertEquals("Wrong list delimiter", ',', listDelimiter);
+            super(reader);
             maxProperties = maxProps;
         }
 
@@ -1284,9 +1307,9 @@ public class TestPropertiesConfiguration
     private static class PropertiesWriterTestImpl extends
             PropertiesConfiguration.PropertiesWriter
     {
-        public PropertiesWriterTestImpl(char delimiter) throws IOException
+        public PropertiesWriterTestImpl(ListDelimiterHandler handler) throws IOException
         {
-            super(new FileWriter(testSavePropertiesFile), delimiter);
+            super(new FileWriter(testSavePropertiesFile), handler);
         }
     }
 }