Author: oheger
Date: Mon Feb  8 21:03:02 2010
New Revision: 907793

URL: http://svn.apache.org/viewvc?rev=907793&view=rev
Log:
[CONFIGURATION-407] Synchronized access to nodes when constructing the global 
section configuration. Applied a fix to configuration2 branch.

Modified:
    
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/INIConfiguration.java
    
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestINIConfiguration.java
    
commons/proper/configuration/branches/configuration2_experimental/xdocs/changes.xml

Modified: 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/INIConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/INIConfiguration.java?rev=907793&r1=907792&r2=907793&view=diff
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/INIConfiguration.java
 (original)
+++ 
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/INIConfiguration.java
 Mon Feb  8 21:03:02 2010
@@ -32,7 +32,6 @@
 import org.apache.commons.configuration2.expr.ExpressionEngine;
 import org.apache.commons.configuration2.tree.ConfigurationNode;
 import org.apache.commons.configuration2.tree.DefaultConfigurationNode;
-import org.apache.commons.configuration2.tree.ViewNode;
 import org.apache.commons.lang.StringUtils;
 
 /**
@@ -690,7 +689,26 @@
      */
     private SubConfiguration<ConfigurationNode> getGlobalSection()
     {
-        ViewNode parent = new ViewNode();
+        ConfigurationNode parent = new DefaultConfigurationNode()
+        {
+            /**
+             * Adds the specified child node to this node. This implementation
+             * does not change the parent node of the child. So the child node
+             * remains in its original hierarchy.
+             *
+             * @param child the child node to be added
+             */
+            @Override
+            public void addChild(ConfigurationNode child)
+            {
+                synchronized (child)
+                {
+                    ConfigurationNode parent = child.getParentNode();
+                    super.addChild(child);
+                    child.setParentNode(parent);
+                }
+            }
+        };
 
         for (ConfigurationNode node : getRootNode().getChildren())
         {

Modified: 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestINIConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestINIConfiguration.java?rev=907793&r1=907792&r2=907793&view=diff
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestINIConfiguration.java
 (original)
+++ 
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/TestINIConfiguration.java
 Mon Feb  8 21:03:02 2010
@@ -27,6 +27,8 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import junit.framework.TestCase;
 
@@ -516,6 +518,72 @@
     }
 
     /**
+     * Tests concurrent access to the global section.
+     */
+    public void testGetSectionGloabalMultiThreaded()
+            throws ConfigurationException, InterruptedException
+    {
+        final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
+        final int threadCount = 12;
+        final int loopCount = 350;
+        final CountDownLatch syncLatch = new CountDownLatch(1);
+        final AtomicBoolean errorFlag = new AtomicBoolean();
+
+        Thread[] threads = new Thread[threadCount];
+        for (int i = 0; i < threadCount; i++)
+        {
+            threads[i] = new Thread()
+            {
+                /**
+                 * Accesses the global section of the test configuration in a
+                 * loop and checks whether this causes an exception.
+                 */
+                @Override
+                public void run()
+                {
+                    boolean error = false;
+
+                    try
+                    {
+                        // wait on the latch to increase parallelism
+                        syncLatch.await();
+                    }
+                    catch (InterruptedException iex)
+                    {
+                        error = true;
+                    }
+
+                    // access the configuration, check for errors
+                    for (int i = 0; i < loopCount && !error; i++)
+                    {
+                        try
+                        {
+                            config.getSection(null);
+                        }
+                        catch (IllegalStateException istex)
+                        {
+                            error = true;
+                        }
+                    }
+
+                    if (error)
+                    {
+                        errorFlag.set(true);
+                    }
+                };
+            };
+            threads[i].start();
+        }
+
+        syncLatch.countDown(); // start all test threads
+        for (int i = 0; i < threadCount; i++)
+        {
+            threads[i].join();
+        }
+        assertFalse("Exception occurred", errorFlag.get());
+    }
+
+    /**
      * Tests querying the content of the global section if there is none.
      */
     public void testGetSectionGlobalNonExisting() throws ConfigurationException

Modified: 
commons/proper/configuration/branches/configuration2_experimental/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/xdocs/changes.xml?rev=907793&r1=907792&r2=907793&view=diff
==============================================================================
--- 
commons/proper/configuration/branches/configuration2_experimental/xdocs/changes.xml
 (original)
+++ 
commons/proper/configuration/branches/configuration2_experimental/xdocs/changes.xml
 Mon Feb  8 21:03:02 2010
@@ -79,6 +79,10 @@
     </release>
 
     <release version="1.7" date="in SVN" description="">
+      <action dev="oheger" type="fix" issue="CONFIGURATION-407">
+        Fixed a potential IllegalStateException in HierarchicalINIConfiguration
+        that can be thrown when the global section is requested concurrently.
+      </action>
       <action dev="oheger" type="fix" issue="CONFIGURATION-405">
         XMLPropertyListConfiguration no longer throws a ConfigurationException
         if the file to be loaded does not have an outer dict element.


Reply via email to