[jsword-devel] Close All bug

DM Smith jsword-devel@crosswire.org
Thu, 18 Mar 2004 11:36:05 -0500


This is a multi-part message in MIME format.

------=_NextPart_000_4ff7_a35_6ef4
Content-Type: text/plain; format=flowed

When doing a "Close All" it creates a ConcurrentModificationException 
because the "views" array list is modified while it is being iterated over 
by two different iterators.

This really was two bugs: The first was in the loop that removed the view 
and the second was in the setting up of an initial view to replace the last 
one that was removed.

The solution is simple, since the only access to the views list is via the 
Desktop class (that's what information hiding is good for). I merely changed 
the call that got the iterator to create a copy of the list and return that.

I also found a call in Desktop to next() on an iterator without first 
calling hasNext. According to the documentation for iterators they are 
always to be paired. By way of an example, I saw an iterator in Xerces that 
used the call to hasNext to set up the variable to be returned by next.

I have attached a patch that fixes the bug.

_________________________________________________________________
Free up your inbox with MSN Hotmail Extra Storage. Multiple plans available. 
http://click.atdmt.com/AVE/go/onm00200362ave/direct/01/

------=_NextPart_000_4ff7_a35_6ef4
Content-Type: text/plain; name="patchclose.txt"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="patchclose.txt"

Index: Desktop.java
===================================================================
retrieving revision 1.42
diff -u -r1.42 Desktop.java
--- Desktop.java	18 Mar 2004 09:29:11 -0000	1.42
+++ Desktop.java	18 Mar 2004 16:38:19 -0000
@@ -11,6 +11,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.List;

@@ -200,7 +201,10 @@

         // And setup the initial display area, by getting the first
         // BibleViewPane and asking it for a PassagePane.
-        last = ((BibleViewPane) 
iterateBibleViewPanes().next()).getPassagePane();
+        // According to the iterator contract hasNext has to be called 
before next
+        Iterator iter = iterateBibleViewPanes();
+        iter.hasNext();
+        last = ((BibleViewPane) iter.next()).getPassagePane();

         // Preload the PassageInnerPane for faster initial view
         InnerDisplayPane.preload();
@@ -430,11 +434,12 @@
     }

     /**
-     * Iterate through the list of views
+     * Iterate through a copied list of views
      */
     public Iterator iterateBibleViewPanes()
     {
-        return views.iterator();
+        Collection copy = new ArrayList(views);
+        return copy.iterator();
     }

     /**


------=_NextPart_000_4ff7_a35_6ef4--