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 2009/03/28 21:27:11 UTC

svn commit: r759578 - in /commons/proper/configuration/trunk: conf/ src/java/org/apache/commons/configuration/ src/test/org/apache/commons/configuration/

Author: oheger
Date: Sat Mar 28 20:27:10 2009
New Revision: 759578

URL: http://svn.apache.org/viewvc?rev=759578&view=rev
Log:
CONFIGURATION-371: The separators for the properties are now stored by PropertiesConfigurationLayout. When saving the configuration they are restored.

Modified:
    commons/proper/configuration/trunk/conf/test.properties
    commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java
    commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java
    commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java
    commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfigurationLayout.java

Modified: commons/proper/configuration/trunk/conf/test.properties
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/conf/test.properties?rev=759578&r1=759577&r2=759578&view=diff
==============================================================================
--- commons/proper/configuration/trunk/conf/test.properties (original)
+++ commons/proper/configuration/trunk/conf/test.properties Sat Mar 28 20:27:10 2009
@@ -100,3 +100,5 @@
 test.separator.tab	foo
 test.separator.formfeedfoo
 test.separator.whitespace foo
+test.separator.no.space=foo
+

Modified: commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java?rev=759578&r1=759577&r2=759578&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java Sat Mar 28 20:27:10 2009
@@ -177,6 +177,9 @@
     /** Constant for the supported comment characters.*/
     static final String COMMENT_CHARS = "#!";
 
+    /** Constant for the default properties separator.*/
+    static final String DEFAULT_SEPARATOR = " = ";
+
     /**
      * Constant for the default <code>IOFactory</code>. This instance is used
      * when no specific factory was set.
@@ -602,6 +605,9 @@
         /** Stores the value of the last read property.*/
         private String propertyValue;
 
+        /** Stores the property separator of the last read property.*/
+        private String propertySeparator = DEFAULT_SEPARATOR;
+
         /** Stores the list delimiter character.*/
         private char delimiter;
 
@@ -741,6 +747,19 @@
         }
 
         /**
+         * Returns the separator that was used for the last read property. The
+         * separator can be stored so that it can later be restored when saving
+         * the configuration.
+         *
+         * @return the separator for the last read property
+         * @since 1.7
+         */
+        public String getPropertySeparator()
+        {
+            return propertySeparator;
+        }
+
+        /**
          * Parses a line read from the properties file. This method is called
          * for each non-comment line read from the source file. Its task is to
          * split the passed in line into the property key and its value. The
@@ -755,6 +774,7 @@
             String[] property = doParseProperty(line);
             initPropertyName(property[0]);
             initPropertyValue(property[1]);
+            initPropertySeparator(property[2]);
         }
 
         /**
@@ -786,6 +806,20 @@
         }
 
         /**
+         * Sets the separator of the current property. This method can be called
+         * by <code>parseProperty()</code>. It allows the associated layout
+         * object to keep track of the property separators. When saving the
+         * configuration the separators can be restored.
+         *
+         * @param value the separator used for the current property
+         * @since 1.7
+         */
+        protected void initPropertySeparator(String value)
+        {
+            propertySeparator = value;
+        }
+
+        /**
          * Checks if the passed in line should be combined with the following.
          * This is true, if the line ends with an odd number of backslashes.
          *
@@ -804,19 +838,20 @@
         }
 
         /**
-         * Parse a property line and return the key and the value in an array.
+         * Parse a property line and return the key, the value, and the separator in an array.
          *
          * @param line the line to parse
-         * @return an array with the property's key and value
+         * @return an array with the property's key, value, and separator
          */
         private static String[] doParseProperty(String line)
         {
             // sorry for this spaghetti code, please replace it as soon as
             // possible with a regexp when the Java 1.3 requirement is dropped
 
-            String[] result = new String[2];
+            String[] result = new String[3];
             StringBuffer key = new StringBuffer();
             StringBuffer value = new StringBuffer();
+            StringBuffer separator = new StringBuffer();
 
             // state of the automaton:
             // 0: key parsing
@@ -839,11 +874,13 @@
                         else if (ArrayUtils.contains(WHITE_SPACE, c))
                         {
                             // switch to the separator crossing state
+                            separator.append(c);
                             state = 2;
                         }
                         else if (ArrayUtils.contains(SEPARATORS, c))
                         {
                             // switch to the value parsing state
+                            separator.append(c);
                             state = 3;
                         }
                         else
@@ -872,19 +909,14 @@
                         break;
 
                     case 2:
-                        if (ArrayUtils.contains(WHITE_SPACE, c))
+                        if (ArrayUtils.contains(WHITE_SPACE, c) || ArrayUtils.contains(SEPARATORS, c))
                         {
-                            // do nothing, eat all white spaces
-                            state = 2;
-                        }
-                        else if (ArrayUtils.contains(SEPARATORS, c))
-                        {
-                            // switch to the value parsing state
-                            state = 3;
+                            // record the separator
+                            separator.append(c);
                         }
                         else
                         {
-                            // any other character indicates we encoutered the beginning of the value
+                            // any other character indicates we encountered the beginning of the value
                             value.append(c);
 
                             // switch to the value parsing state
@@ -901,19 +933,25 @@
 
             result[0] = key.toString().trim();
             result[1] = value.toString().trim();
+            result[2] = separator.toString();
 
             return result;
         }
     } // class PropertiesReader
 
     /**
-     * This class is used to write properties lines.
+     * This class is used to write properties lines. The most important method
+     * is <code>writeProperty(String, Object, boolean)</code>, which is called
+     * during a save operation for each property found in the configuration.
      */
     public static class PropertiesWriter extends FilterWriter
     {
         /** The delimiter for multi-valued properties.*/
         private char delimiter;
 
+        /** The separator to be used for the current property. */
+        private String currentSeparator;
+
         /**
          * Constructor.
          *
@@ -927,6 +965,29 @@
         }
 
         /**
+         * Returns the current property separator.
+         *
+         * @return the current property separator
+         * @since 1.7
+         */
+        public String getCurrentSeparator()
+        {
+            return currentSeparator;
+        }
+
+        /**
+         * Sets the current property separator. This separator is used when
+         * writing the next property.
+         *
+         * @param currentSeparator the current property separator
+         * @since 1.7
+         */
+        public void setCurrentSeparator(String currentSeparator)
+        {
+            this.currentSeparator = currentSeparator;
+        }
+
+        /**
          * Write a property.
          *
          * @param key the key of the property
@@ -991,7 +1052,7 @@
             }
 
             write(escapeKey(key));
-            write(" = ");
+            write(fetchSeparator(key, value));
             write(v);
 
             writeln(null);
@@ -1108,6 +1169,24 @@
             write(LINE_SEPARATOR);
         }
 
+        /**
+         * Returns the separator to be used for the given property. This method
+         * is called by <code>writeProperty()</code>. The string returned here
+         * is used as separator between the property key and its value. Per
+         * default the separator returned by <code>getCurrentSeparator()</code>
+         * is returned, which was set by the associated layout object. Derived
+         * classes may implement a different strategy for defining the
+         * separator.
+         *
+         * @param key the property key
+         * @param value the value
+         * @return the separator to be used
+         * @since 1.7
+         */
+        protected String fetchSeparator(String key, Object value)
+        {
+            return getCurrentSeparator();
+        }
     } // class PropertiesWriter
 
     /**

Modified: commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java?rev=759578&r1=759577&r2=759578&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java (original)
+++ commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfigurationLayout.java Sat Mar 28 20:27:10 2009
@@ -359,6 +359,39 @@
     }
 
     /**
+     * Returns the separator for the property with the given key.
+     *
+     * @param key the property key
+     * @return the property separator for this property
+     * @since 1.7
+     */
+    public String getSeparator(String key)
+    {
+        return fetchLayoutData(key).getSeparator();
+    }
+
+    /**
+     * Sets the separator to be used for the property with the given key. The
+     * separator is the string between the property key and its value. For new
+     * properties &quot; = &quot; is used. When a properties file is read, the
+     * layout tries to determine the separator for each property. With this
+     * method the separator can be changed. To be compatible with the properties
+     * format only the characters <code>=</code> and <code>:</code> (with or
+     * without whitespace) should be used, but this method does not enforce this
+     * - it accepts arbitrary strings. If the key refers to a property with
+     * multiple values that are written on multiple lines, this separator will
+     * be used on all lines.
+     *
+     * @param key the key for the property
+     * @param sep the separator to be used for this property
+     * @since 1.7
+     */
+    public void setSeparator(String key, String sep)
+    {
+        fetchLayoutData(key).setSeparator(sep);
+    }
+
+    /**
      * Returns a set with all property keys managed by this object.
      *
      * @return a set with all contained property keys
@@ -416,6 +449,7 @@
                     {
                         data.setComment(comment);
                         data.setBlancLines(blancLines);
+                        data.setSeparator(reader.getPropertySeparator());
                     }
                 }
             }
@@ -475,6 +509,7 @@
                     // Output the property and its value
                     boolean singleLine = (isForceSingleLine() || isSingleLine(key))
                             && !getConfiguration().isDelimiterParsingDisabled();
+                    writer.setCurrentSeparator(getSeparator(key));
                     writer.writeProperty(key, getConfiguration().getProperty(
                             key), singleLine);
                 }
@@ -738,6 +773,9 @@
         /** Stores the comment for the property. */
         private StringBuffer comment;
 
+        /** The separator to be used for this property. */
+        private String separator;
+
         /** Stores the number of blanc lines before this property. */
         private int blancLines;
 
@@ -750,6 +788,7 @@
         public PropertyLayoutData()
         {
             singleLine = true;
+            separator = PropertiesConfiguration.DEFAULT_SEPARATOR;
         }
 
         /**
@@ -842,6 +881,26 @@
         }
 
         /**
+         * Returns the separator that was used for this property.
+         *
+         * @return the property separator
+         */
+        public String getSeparator()
+        {
+            return separator;
+        }
+
+        /**
+         * Sets the separator to be used for the represented property.
+         *
+         * @param separator the property separator
+         */
+        public void setSeparator(String separator)
+        {
+            this.separator = separator;
+        }
+
+        /**
          * Creates a copy of this object.
          *
          * @return the copy

Modified: commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java?rev=759578&r1=759577&r2=759578&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfiguration.java Sat Mar 28 20:27:10 2009
@@ -17,8 +17,10 @@
 
 package org.apache.commons.configuration;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,8 +35,10 @@
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import junit.framework.TestCase;
 
@@ -916,8 +920,9 @@
     /**
      * Tests setting an IOFactory that uses a specialized writer.
      */
-    public void testSetIOFactoryWriter() throws ConfigurationException
+    public void testSetIOFactoryWriter() throws ConfigurationException, IOException
     {
+        final PropertiesWriterTestImpl testWriter = new PropertiesWriterTestImpl(',');
         conf.setIOFactory(new PropertiesConfiguration.IOFactory()
         {
             public PropertiesConfiguration.PropertiesReader createPropertiesReader(
@@ -929,22 +934,52 @@
             public PropertiesConfiguration.PropertiesWriter createPropertiesWriter(
                     Writer out, char delimiter)
             {
-                try
-                {
-                    return new PropertiesWriterTestImpl(out, delimiter);
-                }
-                catch (IOException ioex)
-                {
-                    fail("Unexpected exception: " + ioex);
-                    return null;
-                }
+                return testWriter;
             }
         });
         conf.save(new StringWriter());
+        testWriter.close();
         checkSavedConfig();
     }
 
     /**
+     * Tests that the property separators are retained when saving the
+     * configuration.
+     */
+    public void testKeepSeparators() throws ConfigurationException, IOException
+    {
+        conf.save(testSavePropertiesFile);
+        final String[] separatorTests = {
+                "test.separator.equal = foo", "test.separator.colon : foo",
+                "test.separator.tab\tfoo", "test.separator.whitespace foo",
+                "test.separator.no.space=foo"
+        };
+        Set foundLines = new HashSet();
+        BufferedReader in = new BufferedReader(new FileReader(
+                testSavePropertiesFile));
+        try
+        {
+            String s;
+            while ((s = in.readLine()) != null)
+            {
+                for (int i = 0; i < separatorTests.length; i++)
+                {
+                    if (separatorTests[i].equals(s))
+                    {
+                        foundLines.add(s);
+                    }
+                }
+            }
+        }
+        finally
+        {
+            in.close();
+        }
+        assertEquals("No all separators were found: " + foundLines,
+                separatorTests.length, foundLines.size());
+    }
+
+    /**
      * Creates a configuration that can be used for testing copy operations.
      *
      * @return the configuration to be copied
@@ -1123,8 +1158,7 @@
     private static class PropertiesWriterTestImpl extends
             PropertiesConfiguration.PropertiesWriter
     {
-        public PropertiesWriterTestImpl(Writer writer, char delimiter)
-                throws IOException
+        public PropertiesWriterTestImpl(char delimiter) throws IOException
         {
             super(new FileWriter(testSavePropertiesFile), delimiter);
         }

Modified: commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfigurationLayout.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfigurationLayout.java?rev=759578&r1=759577&r2=759578&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfigurationLayout.java (original)
+++ commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertiesConfigurationLayout.java Sat Mar 28 20:27:10 2009
@@ -21,10 +21,10 @@
 import java.io.StringWriter;
 import java.util.Iterator;
 
-import org.apache.commons.configuration.event.ConfigurationEvent;
-
 import junit.framework.TestCase;
 
+import org.apache.commons.configuration.event.ConfigurationEvent;
+
 /**
  * Test class for PropertiesConfigurationLayout.
  *
@@ -257,6 +257,7 @@
         assertEquals("Blanc lines before new property", 0, layout
                 .getBlancLinesBefore(TEST_KEY));
         assertTrue("No single line property", layout.isSingleLine(TEST_KEY));
+        assertEquals("Wrong separator", " = ", layout.getSeparator(TEST_KEY));
     }
 
     /**
@@ -578,7 +579,7 @@
     }
 
     /**
-     * Tests if the copy and the original are independend from each other.
+     * Tests if the copy and the original are independent from each other.
      */
     public void testInitCopyModify()
     {
@@ -597,6 +598,16 @@
     }
 
     /**
+     * Tests changing the separator for a property.
+     */
+    public void testSetSeparator() throws ConfigurationException
+    {
+        config.addProperty(TEST_KEY, TEST_VALUE);
+        layout.setSeparator(TEST_KEY, ":");
+        checkLayoutString(TEST_KEY + ":" + TEST_VALUE + CR);
+    }
+
+    /**
      * Helper method for filling the layout object with some properties.
      */
     private void fillLayout()