Author: oheger
Date: Sat Jun  1 19:55:19 2013
New Revision: 1488572

URL: http://svn.apache.org/r1488572
Log:
Fixed a problem with BaseHierarchicalConfiguration.clone() related to 
SubnodeConfiguration management.

It must be ensured that the cloned configuration creates its own data
structures for managing SubnodeConfigurations.

Modified:
    
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
    
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseHierarchicalConfigurationSynchronization.java
    
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java
    
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java

Modified: 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java?rev=1488572&r1=1488571&r2=1488572&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
 (original)
+++ 
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
 Sat Jun  1 19:55:19 2013
@@ -882,9 +882,7 @@ public class BaseHierarchicalConfigurati
 
         if (changeListener == null)
         {
-            changeListener = createChangeListener();
-            subConfigs = new WeakHashMap<SubnodeConfiguration, Object>();
-            addConfigurationListener(changeListener);
+            setUpSubConfigManagementData();
         }
         sub.addConfigurationListener(changeListener);
         sub.initSubConfigManagementData(subConfigs, changeListener);
@@ -915,6 +913,17 @@ public class BaseHierarchicalConfigurati
     }
 
     /**
+     * Initializes internal data structures for managing associated
+     * {@code SubnodeConfiguration} objects.
+     */
+    private void setUpSubConfigManagementData()
+    {
+        changeListener = createChangeListener();
+        subConfigs = new WeakHashMap<SubnodeConfiguration, Object>();
+        addConfigurationListener(changeListener);
+    }
+
+    /**
      * Creates a listener which reacts on all changes on this configuration or
      * one of its {@code SubnodeConfiguration} instances. If such a change is
      * detected, some updates have to be performed.
@@ -1219,6 +1228,7 @@ public class BaseHierarchicalConfigurati
             getRootNode().visit(v);
             copy.setRootNode(v.getClone());
             copy.cloneInterpolator(this);
+            copy.setUpSubConfigManagementData();
             
copy.setSynchronizer(ConfigurationUtils.cloneSynchronizer(getSynchronizer()));
 
             return copy;

Modified: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseHierarchicalConfigurationSynchronization.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseHierarchicalConfigurationSynchronization.java?rev=1488572&r1=1488571&r2=1488572&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseHierarchicalConfigurationSynchronization.java
 (original)
+++ 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestBaseHierarchicalConfigurationSynchronization.java
 Sat Jun  1 19:55:19 2013
@@ -24,11 +24,14 @@ import static org.junit.Assert.assertNul
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.commons.configuration.SynchronizerTestImpl.Methods;
 import org.apache.commons.configuration.io.FileHandler;
+import org.apache.commons.configuration.tree.ConfigurationNode;
 import org.apache.commons.configuration.tree.DefaultConfigurationNode;
 import org.junit.Before;
 import org.junit.Test;
@@ -238,6 +241,57 @@ public class TestBaseHierarchicalConfigu
     }
 
     /**
+     * Tests whether a clone() operation also copies the data used to manage
+     * SubnodeConfiguration objects.
+     */
+    @Test
+    public void testCloneCopySubnodeData()
+    {
+        final Collection<SubnodeConfiguration> validatedConfigs =
+                new LinkedList<SubnodeConfiguration>();
+
+        // A special configuration class which creates SubConfigurations that
+        // record validation operations
+        BaseHierarchicalConfiguration conf2 =
+                new BaseHierarchicalConfiguration(config)
+                {
+                    private static final long serialVersionUID = 1L;
+
+                    @Override
+                    protected SubnodeConfiguration createSubnodeConfiguration(
+                            ConfigurationNode node, String subnodeKey)
+                    {
+                        return new SubnodeConfiguration(this, node, subnodeKey)
+                        {
+                            private static final long serialVersionUID = 1L;
+
+                            @Override
+                            void validateRootNode()
+                            {
+                                super.validateRootNode();
+                                validatedConfigs.add(this);
+                            }
+                        };
+                    }
+                };
+
+        SubnodeConfiguration sub =
+                conf2.configurationAt("element2.subelement", true);
+        HierarchicalConfiguration copy =
+                (HierarchicalConfiguration) conf2.clone();
+        SubnodeConfiguration sub2 =
+                copy.configurationAt("element2.subelement", true);
+        // This must not cause a validate operation on sub1, but on sub2
+        copy.clearTree("element2");
+        assertNull("Sub2 not detached", sub2.getSubnodeKey());
+        assertNotNull("Sub 1 was detached", sub.getSubnodeKey());
+        assertEquals("Wrong number of validated configs", 1,
+                validatedConfigs.size());
+        assertSame("Wrong validated config", sub2, validatedConfigs.iterator()
+                .next());
+    }
+
+    /**
      * Tests whether a SubnodeConfiguration's clearAndDetachFromParent() method
      * is correctly synchronized.
      */

Modified: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java?rev=1488572&r1=1488571&r2=1488572&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java
 (original)
+++ 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.java
 Sat Jun  1 19:55:19 2013
@@ -29,6 +29,7 @@ import java.io.StringReader;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
@@ -391,8 +392,8 @@ public class TestCombinedConfiguration
                 .getNodeCombiner());
         assertEquals("Wrong number of names", config.getConfigurationNames()
                 .size(), cc2.getConfigurationNames().size());
-        assertTrue("Event listeners were cloned", cc2
-                .getConfigurationListeners().isEmpty());
+        assertTrue("Found duplicate event listeners", Collections.disjoint(cc2
+                .getConfigurationListeners(), 
config.getConfigurationListeners()));
 
         StrictConfigurationComparator comp = new 
StrictConfigurationComparator();
         for (int i = 0; i < config.getNumberOfConfigurations(); i++)

Modified: 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java?rev=1488572&r1=1488571&r2=1488572&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
 (original)
+++ 
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
 Sat Jun  1 19:55:19 2013
@@ -726,17 +726,18 @@ public class TestHierarchicalConfigurati
     @Test
     public void testCloneWithEventListeners()
     {
-        config.addConfigurationListener(new ConfigurationListener()
+        ConfigurationListener l = new ConfigurationListener()
         {
             public void configurationChanged(ConfigurationEvent event)
             {
                 // just a dummy
             }
-        });
+        };
+        config.addConfigurationListener(l);
         BaseHierarchicalConfiguration copy = (BaseHierarchicalConfiguration) 
config
                 .clone();
-        assertTrue("Event listener registered at clone", copy
-                .getConfigurationListeners().isEmpty());
+        assertFalse("Event listener registered at clone", copy
+                .getConfigurationListeners().contains(l));
     }
 
     /**


Reply via email to