Author: rwhitcomb Date: Thu Feb 21 17:50:04 2013 New Revision: 1448743 URL: http://svn.apache.org/r1448743 Log: PIVOT-861: More changes -- using java.util.ArrayList to implement ListenerList was causing many ConcurrentModificationExceptions to be thrown at various times and various places. So, reverting to my homegrown implementation, which at least doesn't complain about this. Maybe investigate further later to see why this was happening and make a general solution with locks or something.
Modified: pivot/branches/2.0.x/core/src/org/apache/pivot/util/ListenerList.java Modified: pivot/branches/2.0.x/core/src/org/apache/pivot/util/ListenerList.java URL: http://svn.apache.org/viewvc/pivot/branches/2.0.x/core/src/org/apache/pivot/util/ListenerList.java?rev=1448743&r1=1448742&r2=1448743&view=diff ============================================================================== --- pivot/branches/2.0.x/core/src/org/apache/pivot/util/ListenerList.java (original) +++ pivot/branches/2.0.x/core/src/org/apache/pivot/util/ListenerList.java Thu Feb 21 17:50:04 2013 @@ -16,8 +16,9 @@ */ package org.apache.pivot.util; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; +import java.util.NoSuchElementException; /** * Abstract base class for listener lists. @@ -29,9 +30,43 @@ import java.util.Iterator; */ public abstract class ListenerList<T> implements Iterable<T> { + // Iterator through the current array of elements + private class NodeIterator implements Iterator<T> { + private int index; + + public NodeIterator() { + this.index = 0; + } + + @Override + public boolean hasNext() { + return (index < last); + } + + @Override + public T next() { + if (index >= last) { + throw new NoSuchElementException(); + } + + return list[index++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + private static final int DEFAULT_SIZE = 5; - private ArrayList<T> list = new ArrayList<T>(DEFAULT_SIZE); + // The current array of items (some of which are null) + // All non-null objects are at the beginning of the array + // and the array is reorganized on "remove" + @SuppressWarnings({"unchecked"}) + private T[] list = (T[])new Object[DEFAULT_SIZE]; + // The current length of the active list + private int last = 0; /** * Adds a listener to the list, if it has not previously been added. @@ -44,7 +79,12 @@ public abstract class ListenerList<T> im return; } - list.add(listener); + // If no slot is available, increase the size of the array + if (last >= list.length) { + list = Arrays.copyOf(list, list.length + DEFAULT_SIZE); + } + + list[last++] = listener; } /** @@ -60,18 +100,25 @@ public abstract class ListenerList<T> im return; } - list.remove(index); + // Once we find the entry in the list, copy the rest of the + // existing entries down by one position + if (index < last - 1) { + System.arraycopy(list, index + 1, list, index, last - 1 - index); + } + + list[--last] = null; } - /** - * Returns the position of the given listener in the list, - * or -1 if the listener is not in the list. - */ private int indexOf(T listener) { if (listener == null) { throw new IllegalArgumentException("listener is null."); } - return list.indexOf(listener); + for (int i = 0; i < last; i++) { + if (list[i] == listener) { + return i; + } + } + return -1; } /** @@ -95,15 +142,12 @@ public abstract class ListenerList<T> im * otherwise. */ public boolean isEmpty() { - return list.isEmpty(); + return last == 0; } - /** - * Returns an iterator over the elements of the list. - */ @Override public Iterator<T> iterator() { - return list.iterator(); + return new NodeIterator(); } }