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.