Author: oheger
Date: Wed Nov  5 23:23:41 2008
New Revision: 711782

URL: http://svn.apache.org/viewvc?rev=711782&view=rev
Log:
CONFIGURATION-347: The Iterator returned by AbstractConfiguration.getKeys() now 
points to a snapshot of the keys. This prevents 
ConcurrentModificationExceptions during iteration when a reload happens.

Modified:
    
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java
    
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestFileConfiguration.java
    commons/proper/configuration/trunk/xdocs/changes.xml

Modified: 
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java?rev=711782&r1=711781&r2=711782&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java
 (original)
+++ 
commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractFileConfiguration.java
 Wed Nov  5 23:23:41 2008
@@ -32,6 +32,8 @@
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 
 import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;
 import org.apache.commons.configuration.reloading.ReloadingStrategy;
@@ -40,7 +42,7 @@
 
 /**
  * <p>Partial implementation of the <code>FileConfiguration</code> interface.
- * Developpers of file based configuration may want to extend this class,
+ * Developers of file based configuration may want to extend this class,
  * the two methods left to implement are <code>[EMAIL PROTECTED] 
FileConfiguration#load(Reader)}</code>
  * and <code>[EMAIL PROTECTED] FileConfiguration#save(Writer)}</code>.</p>
  * <p>This base class already implements a couple of ways to specify the 
location
@@ -934,10 +936,39 @@
         return super.containsKey(key);
     }
 
+    /**
+     * Returns an <code>Iterator</code> with the keys contained in this
+     * configuration. This implementation performs a reload if necessary before
+     * obtaining the keys. The <code>Iterator</code> returned by this method
+     * points to a snapshot taken when this method was called. Later changes at
+     * the set of keys (including those caused by a reload) won't be visible.
+     * This is because a reload can happen at any time during iteration, and it
+     * is impossible to determine how this reload affects the current 
iteration.
+     * When using the iterator a client has to be aware that changes of the
+     * configuration are possible at any time. For instance, if after a reload
+     * operation some keys are no longer present, the iterator will still 
return
+     * those keys because they were found when it was created.
+     *
+     * @return an <code>Iterator</code> with the keys of this configuration
+     */
     public Iterator getKeys()
     {
         reload();
-        return super.getKeys();
+        List keyList = new LinkedList();
+        enterNoReload();
+        try
+        {
+            for (Iterator it = super.getKeys(); it.hasNext();)
+            {
+                keyList.add(it.next());
+            }
+
+            return keyList.iterator();
+        }
+        finally
+        {
+            exitNoReload();
+        }
     }
 
     /**

Modified: 
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestFileConfiguration.java
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestFileConfiguration.java?rev=711782&r1=711781&r2=711782&view=diff
==============================================================================
--- 
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestFileConfiguration.java
 (original)
+++ 
commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestFileConfiguration.java
 Wed Nov  5 23:23:41 2008
@@ -17,20 +17,21 @@
 
 package org.apache.commons.configuration;
 
-import java.net.URL;
-import java.util.Properties;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Properties;
+
+import junit.framework.TestCase;
 
 import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
 import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
 
-import junit.framework.TestCase;
-
 /**
  * @author Emmanuel Bourg
  * @version $Revision$, $Date$
@@ -426,7 +427,7 @@
     }
 
     /**
-     * Tests to invoke save() without explicitely setting a file name. This
+     * Tests to invoke save() without explicitly setting a file name. This
      * will cause an exception.
      */
     public void testSaveWithoutFileName() throws Exception
@@ -590,6 +591,44 @@
     }
 
     /**
+     * Tests iterating over the keys of a non hierarchical file-based
+     * configuration while a reload happens. This test is related to
+     * CONFIGURATION-347.
+     */
+    public void testIterationWithReloadFlat() throws ConfigurationException
+    {
+        PropertiesConfiguration config = new 
PropertiesConfiguration(TEST_FILE);
+        checkIterationWithReload(config);
+    }
+
+    /**
+     * Tests iterating over the keys of a hierarchical file-based configuration
+     * while a reload happens. This test is related to CONFIGURATION-347.
+     */
+    public void testIterationWithReloadHierarchical()
+            throws ConfigurationException
+    {
+        XMLConfiguration config = new XMLConfiguration("test.xml");
+        checkIterationWithReload(config);
+    }
+
+    /**
+     * Helper method for testing an iteration over the keys of a file-based
+     * configuration while a reload happens.
+     *
+     * @param config the configuration to test
+     */
+    private void checkIterationWithReload(FileConfiguration config)
+    {
+        config.setReloadingStrategy(new FileAlwaysReloadingStrategy());
+        for (Iterator it = config.getKeys(); it.hasNext();)
+        {
+            String key = (String) it.next();
+            assertNotNull("No value for key " + key, config.getProperty(key));
+        }
+    }
+
+    /**
      * Helper method for comparing the content of two configuration objects.
      *
      * @param config1 the first configuration

Modified: commons/proper/configuration/trunk/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/xdocs/changes.xml?rev=711782&r1=711781&r2=711782&view=diff
==============================================================================
--- commons/proper/configuration/trunk/xdocs/changes.xml (original)
+++ commons/proper/configuration/trunk/xdocs/changes.xml Wed Nov  5 23:23:41 
2008
@@ -23,6 +23,12 @@
 
   <body>
     <release version="1.6" date="in SVN" description="">
+      <action dev="oheger" type="fix" issue="CONFIGURATION-347">
+        AbstractFileConfiguration.getKeys() now returns an iterator that points
+        to a snapshot of the keys of the configuration. This prevents
+        ConcurrentModificationExceptions during iteration when a reload is
+        performed.
+      </action>
       <action dev="oheger" type="fix" issue="CONFIGURATION-346">
         ConfigurationUtils.convertToHierarchical() now creates multiple
         configuration nodes for properties with multiple values. This


Reply via email to