commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ohe...@apache.org
Subject svn commit: r833705 - in /commons/proper/configuration/branches/configuration2_experimental/src: main/java/org/apache/commons/configuration2/base/ main/java/org/apache/commons/configuration2/base/impl/ test/java/org/apache/commons/configuration2/base/i...
Date Sat, 07 Nov 2009 16:10:40 GMT
Author: oheger
Date: Sat Nov  7 16:10:40 2009
New Revision: 833705

URL: http://svn.apache.org/viewvc?rev=833705&view=rev
Log:
Added a copy constructor to XMLConfigurationSource.

Modified:
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/InMemoryConfigurationSource.java
    commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/impl/XMLConfigurationSource.java
    commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/impl/TestXMLConfigurationSource.java

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/InMemoryConfigurationSource.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/InMemoryConfigurationSource.java?rev=833705&r1=833704&r2=833705&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/InMemoryConfigurationSource.java
(original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/InMemoryConfigurationSource.java
Sat Nov  7 16:10:40 2009
@@ -78,10 +78,7 @@
         this();
         if (c != null)
         {
-            CloneVisitor visitor = new CloneVisitor();
-            NodeVisitorAdapter
-                    .visit(visitor, c.getRootNode(), getNodeHandler());
-            setRootNode(visitor.getClone());
+            setRootNode(copyNodes(c.getRootNode(), NODE_HANDLER));
         }
     }
 
@@ -133,24 +130,71 @@
     }
 
     /**
+     * Copies the node structure below the specified root node. This method
+     * traverses the node structure with a specialized visitor that can create a
+     * deep clone of all nodes.
+     *
+     * @param <N> the type of the nodes
+     * @param node the root node of the hierarchy which is to be copied
+     * @param handler the {@code NodeHandler} to be used
+     * @return the root node of the copied structure
+     */
+    protected static <N extends ConfigurationNode> N copyNodes(N node,
+            NodeHandler<N> handler)
+    {
+        CloneVisitor<N> visitor = new CloneVisitor<N>();
+        NodeVisitorAdapter.visit(visitor, node, handler);
+        return visitor.getClone();
+    }
+
+    /**
+     * Clears all reference fields in a node structure. A configuration node can
+     * store a so-called &quot;reference&quot;. The meaning of this data is
+     * determined by a concrete sub class. Typically such references are
+     * specific for a configuration instance. If this instance is cloned or
+     * copied, they must be cleared. This can be done using this method.
+     *
+     * @param <N> the type of the nodes
+     * @param node the root node of the node hierarchy, in which the references
+     *        are to be cleared
+     * @param handler the {@code NodeHandler} to be used
+     */
+    protected static <N extends ConfigurationNode> void clearReferences(N node,
+            NodeHandler<N> handler)
+    {
+        NodeVisitorAdapter.visit(new NodeVisitorAdapter<N>()
+        {
+            @Override
+            public void visitBeforeChildren(N node, NodeHandler<N> handler)
+            {
+                node.setReference(null);
+                for (ConfigurationNode attr : node.getAttributes())
+                {
+                    attr.setReference(null);
+                }
+            }
+        }, node, handler);
+    }
+
+    /**
      * A specialized visitor that is able to create a deep copy of a node
      * hierarchy.
      */
-    private static class CloneVisitor extends
-            NodeVisitorAdapter<ConfigurationNode>
+    private static class CloneVisitor<N extends ConfigurationNode> extends
+            NodeVisitorAdapter<N>
     {
         /** A stack with the actual object to be copied. */
-        private Stack<ConfigurationNode> copyStack;
+        private Stack<N> copyStack;
 
         /** Stores the result of the clone process. */
-        private ConfigurationNode result;
+        private N result;
 
         /**
          * Creates a new instance of {@code CloneVisitor}.
          */
         public CloneVisitor()
         {
-            copyStack = new Stack<ConfigurationNode>();
+            copyStack = new Stack<N>();
         }
 
         /**
@@ -159,10 +203,10 @@
          * @param node the node
          */
         @Override
-        public void visitAfterChildren(ConfigurationNode node,
-                NodeHandler<ConfigurationNode> handler)
+        public void visitAfterChildren(N node,
+                NodeHandler<N> handler)
         {
-            ConfigurationNode copy = copyStack.pop();
+            N copy = copyStack.pop();
             if (copyStack.isEmpty())
             {
                 result = copy;
@@ -175,10 +219,11 @@
          * @param node the node
          */
         @Override
-        public void visitBeforeChildren(ConfigurationNode node,
-                NodeHandler<ConfigurationNode> handler)
+        public void visitBeforeChildren(N node,
+                NodeHandler<N> handler)
         {
-            ConfigurationNode copy = (ConfigurationNode) node.clone();
+            @SuppressWarnings("unchecked")
+            N copy = (N) node.clone();
             copy.setParentNode(null);
 
             for (ConfigurationNode attr : node.getAttributes())
@@ -199,7 +244,7 @@
          *
          * @return the cloned root node
          */
-        public ConfigurationNode getClone()
+        public N getClone()
         {
             return result;
         }

Modified: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/impl/XMLConfigurationSource.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/impl/XMLConfigurationSource.java?rev=833705&r1=833704&r2=833705&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/impl/XMLConfigurationSource.java
(original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/base/impl/XMLConfigurationSource.java
Sat Nov  7 16:10:40 2009
@@ -43,6 +43,7 @@
 import org.apache.commons.configuration2.ConfigurationException;
 import org.apache.commons.configuration2.base.Capability;
 import org.apache.commons.configuration2.base.DefaultLocatorSupport;
+import org.apache.commons.configuration2.base.HierarchicalConfigurationSource;
 import org.apache.commons.configuration2.base.InMemoryConfigurationSource;
 import org.apache.commons.configuration2.base.LocatorSupport;
 import org.apache.commons.configuration2.base.StreamBasedSource;
@@ -173,30 +174,28 @@
     public XMLConfigurationSource()
     {
         xmlNodeHandler = new XMLNodeHandler();
-        locatorSupport = new DefaultLocatorSupport(this)
+        locatorSupport = initLocatorSupport();
+    }
+
+    /**
+     * Creates a new instance of {@code XMLConfigurationSource} and initializes
+     * its data from the content of the specified {@code
+     * HierarchicalConfigurationSource}. This is a typical copy constructor.
+     *
+     * @param c the {@code HierarchicalConfigurationSource} to be copied (can be
+     *        <b>null</b>)
+     * @see InMemoryConfigurationSource#InMemoryConfigurationSource(HierarchicalConfigurationSource)
+     */
+    public XMLConfigurationSource(
+            HierarchicalConfigurationSource<? extends ConfigurationNode> c)
+    {
+        this();
+        if (c != null)
         {
-            /**
-             * Loads data from the specified {@code InputStream}. This
-             * implementation directly delegates to the {@code
-             * load(InputStream)} method of the owning {@code
-             * XMLConfigurationSource}.
-             *
-             * @param in the {@code InputStream}
-             * @throws ConfigurationException if an error occurs
-             */
-            @Override
-            public void load(InputStream in) throws ConfigurationException
-            {
-                try
-                {
-                    XMLConfigurationSource.this.load(in);
-                }
-                catch (IOException ioex)
-                {
-                    throw new ConfigurationException(ioex);
-                }
-            }
-        };
+            setRootNode(copyNodes(c.getRootNode(), xmlNodeHandler));
+            clearReferences(getRootNode(), xmlNodeHandler);
+        }
+        setRootElementName(getRootNode().getName());
     }
 
     /**
@@ -868,6 +867,42 @@
     }
 
     /**
+     * Initializes the {@code LocatorSupport} object used by this configuration
+     * source. This implementation returns a special {@code LocatorSupport}
+     * implementation whose {@code load(InputStream)} method delegates to the
+     * corresponding {@code load()} method of this instance.
+     *
+     * @return the {@code LocatorSupport} object
+     */
+    private LocatorSupport initLocatorSupport()
+    {
+        return new DefaultLocatorSupport(this)
+        {
+            /**
+             * Loads data from the specified {@code InputStream}. This
+             * implementation directly delegates to the {@code
+             * load(InputStream)} method of the owning {@code
+             * XMLConfigurationSource}.
+             *
+             * @param in the {@code InputStream}
+             * @throws ConfigurationException if an error occurs
+             */
+            @Override
+            public void load(InputStream in) throws ConfigurationException
+            {
+                try
+                {
+                    XMLConfigurationSource.this.load(in);
+                }
+                catch (IOException ioex)
+                {
+                    throw new ConfigurationException(ioex);
+                }
+            }
+        };
+    }
+
+    /**
      * Tests whether the specified node has some child elements.
      *
      * @param node the node to check

Modified: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/impl/TestXMLConfigurationSource.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/impl/TestXMLConfigurationSource.java?rev=833705&r1=833704&r2=833705&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/impl/TestXMLConfigurationSource.java
(original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/base/impl/TestXMLConfigurationSource.java
Sat Nov  7 16:10:40 2009
@@ -996,4 +996,132 @@
         assertEquals("Invalid not trimmed", "Some other text", conf
                 .getString("space.testInvalid"));
     }
+
+    /**
+     * Tests the copy constructor.
+     */
+    @Test
+    public void testInitCopy() throws ConfigurationException
+    {
+        XMLConfigurationSource src2 = new XMLConfigurationSource(source);
+        ConfigurationAssert.assertEquals(source, src2);
+    }
+
+    /**
+     * Tests that the XML document is reset by the copy constructor.
+     */
+    @Test
+    public void testInitCopyDocument()
+    {
+        XMLConfigurationSource copy = new XMLConfigurationSource(source);
+        assertNull("Document was copied, too", copy.getDocument());
+    }
+
+    /**
+     * Tests whether element references were cleared by the copy constructor.
+     */
+    @Test
+    public void testInitCopyClearReferences()
+    {
+        XMLConfigurationSource copy = new XMLConfigurationSource(source);
+        ConfigurationNode root = copy.getRootNode();
+        for (ConfigurationNode node : root.getChildren())
+        {
+            assertNull("Reference was not cleared", node.getReference());
+        }
+    }
+
+    /**
+     * Tests whether a configuration source created by the copy constructor can
+     * be correctly saved and reloaded.
+     */
+    @Test
+    public void testInitCopySave() throws ConfigurationException
+    {
+        XMLConfigurationSource copy = new XMLConfigurationSource(source);
+        conf = new ConfigurationImpl<ConfigurationNode>(copy);
+        Configuration<ConfigurationNode> conf2 = reload();
+        // Known issue: For elements with the xml:space="preserve" attribute
+        // that have child elements the number of line feeds is changed.
+        // Therefore the space property has a different value after reloading.
+        conf.clearProperty("space");
+        conf2.clearProperty("space");
+        ConfigurationAssert.assertEquals(conf, conf2);
+    }
+
+    /**
+     * Tests saving a configuration that was created from a hierarchical sub
+     * configuration.
+     */
+    @Test
+    public void testInitCopySaveAfterCreateWithCopyConstructorSub()
+            throws ConfigurationException
+    {
+        Configuration<ConfigurationNode> hc = conf.configurationAt("element2");
+        XMLConfigurationSource copy = new XMLConfigurationSource(hc
+                .getConfigurationSource());
+        conf = new ConfigurationImpl<ConfigurationNode>(copy);
+        Configuration<ConfigurationNode> conf2 = reload();
+        ConfigurationAssert.assertEquals(conf, conf2);
+        XMLConfigurationSource src = (XMLConfigurationSource) conf2
+                .getConfigurationSource();
+        assertEquals("Wrong name of root element", "element2", src
+                .getRootElementName());
+    }
+
+    /**
+     * Tests whether the name of the root element is copied when a configuration
+     * is created using the copy constructor.
+     */
+    @Test
+    public void testInitCopyRootName() throws ConfigurationException,
+            IOException
+    {
+        final String rootName = "rootElement";
+        final String xml = "<" + rootName + "><test>true</test></" +
rootName
+                + ">";
+        source.clear();
+        source.load(new StringReader(xml));
+        XMLConfigurationSource copy = new XMLConfigurationSource(source);
+        assertEquals("Wrong name of root element", rootName, copy
+                .getRootElementName());
+        copy.getCapability(LocatorSupport.class).save(testOutLocator);
+        copy = new XMLConfigurationSource();
+        copy.getCapability(LocatorSupport.class).load(testOutLocator);
+        assertEquals("Wrong name of root element after save", rootName, copy
+                .getRootElementName());
+    }
+
+    /**
+     * Tests whether the name of the root element is copied for a configuration
+     * for which not yet a document exists.
+     */
+    @Test
+    public void testInitCopyRootNameNoDocument() throws ConfigurationException
+    {
+        final String rootName = "rootElement";
+        source = new XMLConfigurationSource();
+        source.setRootElementName(rootName);
+        conf = new ConfigurationImpl<ConfigurationNode>(source);
+        conf.setProperty("test", Boolean.TRUE);
+        XMLConfigurationSource copy = new XMLConfigurationSource(source);
+        assertEquals("Wrong name of root element", rootName, copy
+                .getRootElementName());
+        copy.getCapability(LocatorSupport.class).save(testOutLocator);
+        copy = new XMLConfigurationSource();
+        copy.getCapability(LocatorSupport.class).load(testOutLocator);
+        assertEquals("Wrong name of root element after save", rootName, copy
+                .getRootElementName());
+    }
+
+    /**
+     * Tests the copy constructor if null is passed in.
+     */
+    @Test
+    public void testInitCopyNull()
+    {
+        source = new XMLConfigurationSource(null);
+        conf = new ConfigurationImpl<ConfigurationNode>(source);
+        assertTrue("Not empty", conf.isEmpty());
+    }
 }



Mime
View raw message