diff options
author | bvosburgh | 2009-06-25 15:15:37 +0000 |
---|---|---|
committer | bvosburgh | 2009-06-25 15:15:37 +0000 |
commit | 87e44c59bce702324121b6d9a250259a4861b488 (patch) | |
tree | 60df41c68ab871d99ada9e811713a6c8318d6637 | |
parent | 06f6b5a525c1494031a0faa8b38d573c9143aff3 (diff) | |
download | webtools.dali-87e44c59bce702324121b6d9a250259a4861b488.tar.gz webtools.dali-87e44c59bce702324121b6d9a250259a4861b488.tar.xz webtools.dali-87e44c59bce702324121b6d9a250259a4861b488.zip |
Iterator work
14 files changed, 1009 insertions, 70 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java index 9e6aa342c4..7fffe95d0f 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayIterator.java @@ -23,8 +23,8 @@ public class ArrayIterator<E> implements Iterator<E> { final E[] array; // private-protected - int nextIndex; // private-protected - private final int maxIndex; + int cursor; // private-protected + private final int max; /** @@ -48,17 +48,17 @@ public class ArrayIterator<E> throw new IllegalArgumentException("length: " + length); //$NON-NLS-1$ } this.array = array; - this.nextIndex = start; - this.maxIndex = start + length; + this.cursor = start; + this.max = start + length; } public boolean hasNext() { - return this.nextIndex < this.maxIndex; + return this.cursor != this.max; } public E next() { if (this.hasNext()) { - return this.array[this.nextIndex++]; + return this.array[this.cursor++]; } throw new NoSuchElementException(); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java index 5ed13629d3..8a38965fcb 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/ArrayListIterator.java @@ -24,7 +24,7 @@ public class ArrayListIterator<E> extends ArrayIterator<E> implements ListIterator<E> { - private final int minIndex; + private final int min; /** @@ -41,24 +41,24 @@ public class ArrayListIterator<E> */ public ArrayListIterator(E[] array, int start, int length) { super(array, start, length); - this.minIndex = start; + this.min = start; } public int nextIndex() { - return this.nextIndex; + return this.cursor; } public int previousIndex() { - return this.nextIndex - 1; + return this.cursor - 1; } public boolean hasPrevious() { - return this.nextIndex > this.minIndex; + return this.cursor != this.min; } public E previous() { if (this.hasPrevious()) { - return this.array[--this.nextIndex]; + return this.array[--this.cursor]; } throw new NoSuchElementException(); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java index 3dfbd73226..81424d7ab1 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/CloneIterator.java @@ -24,8 +24,8 @@ import org.eclipse.jpt.utility.internal.StringTools; * By default, a <code>CloneIterator</code> does not support the * <code>#remove()</code> operation; this is because it does not have * access to the original collection. But if the <code>CloneIterator</code> - * is supplied with an <code>Mutator</code> it will delegate the - * <code>#remove()</code> operation to the <code>Mutator</code>. + * is supplied with an <code>Remover</code> it will delegate the + * <code>#remove()</code> operation to the <code>Remover</code>. * Alternatively, a subclass can override the <code>#remove(Object)</code> * method. */ @@ -34,7 +34,7 @@ public class CloneIterator<E> { private final Iterator<Object> iterator; private E current; - private final Mutator<E> mutator; + private final Remover<E> remover; private boolean removeAllowed; @@ -46,7 +46,7 @@ public class CloneIterator<E> * unless a subclass overrides the <code>#remove(Object)</code>. */ public CloneIterator(Collection<? extends E> collection) { - this(collection, Mutator.ReadOnly.<E>instance()); + this(collection, Remover.ReadOnly.<E>instance()); } /** @@ -55,25 +55,25 @@ public class CloneIterator<E> * unless a subclass overrides the <code>#remove(Object)</code>. */ public CloneIterator(E[] array) { - this(array, Mutator.ReadOnly.<E>instance()); + this(array, Remover.ReadOnly.<E>instance()); } /** * Construct an iterator on a copy of the specified collection. - * Use the specified mutator to remove objects from the + * Use the specified remover to remove objects from the * original collection. */ - public CloneIterator(Collection<? extends E> collection, Mutator<E> mutator) { - this(mutator, collection.toArray()); + public CloneIterator(Collection<? extends E> collection, Remover<E> remover) { + this(remover, collection.toArray()); } /** * Construct an iterator on a copy of the specified array. - * Use the specified mutator to remove objects from the + * Use the specified remover to remove objects from the * original array. */ - public CloneIterator(E[] array, Mutator<E> mutator) { - this(mutator, array.clone()); + public CloneIterator(E[] array, Remover<E> remover) { + this(remover, array.clone()); } /** @@ -81,11 +81,11 @@ public class CloneIterator<E> * Swap order of arguments to prevent collision with other constructor. * The passed in array will *not* be cloned. */ - protected CloneIterator(Mutator<E> mutator, Object... array) { + protected CloneIterator(Remover<E> remover, Object... array) { super(); this.iterator = new ArrayIterator<Object>(array); this.current = null; - this.mutator = mutator; + this.remover = remover; this.removeAllowed = false; } @@ -128,10 +128,10 @@ public class CloneIterator<E> * Remove the specified element from the original collection. * <p> * This method can be overridden by a subclass as an - * alternative to building an <code>Mutator</code>. + * alternative to building a <code>Remover</code>. */ protected void remove(E e) { - this.mutator.remove(e); + this.remover.remove(e); } @Override @@ -147,19 +147,19 @@ public class CloneIterator<E> * elements from the original collection; since the iterator * does not have direct access to the original collection. */ - public interface Mutator<T> { + public interface Remover<T> { /** * Remove the specified object from the original collection. */ - void remove(T current); + void remove(T element); - final class ReadOnly<S> implements Mutator<S> { + final class ReadOnly<S> implements Remover<S> { @SuppressWarnings("unchecked") - public static final Mutator INSTANCE = new ReadOnly(); + public static final Remover INSTANCE = new ReadOnly(); @SuppressWarnings("unchecked") - public static <R> Mutator<R> instance() { + public static <R> Remover<R> instance() { return INSTANCE; } // ensure single instance @@ -167,12 +167,12 @@ public class CloneIterator<E> super(); } // remove is not supported - public void remove(Object current) { + public void remove(Object element) { throw new UnsupportedOperationException(); } @Override public String toString() { - return "CloneIterator.Mutator.ReadOnly"; //$NON-NLS-1$ + return "CloneIterator.Remover.ReadOnly"; //$NON-NLS-1$ } } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java index 9b28f19117..c852b1f847 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/GraphIterator.java @@ -52,8 +52,9 @@ import org.eclipse.jpt.utility.internal.StringTools; public class GraphIterator<E> implements Iterator<E> { - private final LinkedList<Iterator<? extends E>> iterators; - private final HashSet<E> visitedNeighbors; + // use a LinkedList since we will be pulling off the front and adding to the end + private final LinkedList<Iterator<? extends E>> iterators = new LinkedList<Iterator<? extends E>>(); + private final HashSet<E> visitedNeighbors = new HashSet<E>(); private final MisterRogers<E> misterRogers; private Iterator<? extends E> currentIterator; @@ -141,10 +142,7 @@ public class GraphIterator<E> public GraphIterator(Iterator<? extends E> roots, MisterRogers<E> misterRogers) { super(); this.currentIterator = roots; - // use a LinkedList since we will be pulling off the front and adding to the end - this.iterators = new LinkedList<Iterator<? extends E>>(); this.misterRogers = misterRogers; - this.visitedNeighbors = new HashSet<E>(); this.loadNextNeighbor(); } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SynchronizedIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SynchronizedIterator.java new file mode 100644 index 0000000000..8b8721bed4 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SynchronizedIterator.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2009 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.iterators; + +import java.util.Iterator; + +import org.eclipse.jpt.utility.internal.StringTools; + +/** + * Wrap an iterator and synchronize all its methods so it can be safely shared + * among multiple threads. + */ +public class SynchronizedIterator<E> + implements Iterator<E> +{ + private final Iterator<? extends E> iterator; + + + public SynchronizedIterator(Iterable<? extends E> iterable) { + this(iterable.iterator()); + } + + public SynchronizedIterator(Iterator<? extends E> iterator) { + super(); + this.iterator = iterator; + } + + public synchronized boolean hasNext() { + return this.iterator.hasNext(); + } + + public synchronized E next() { + return this.iterator.next(); + } + + public synchronized void remove() { + this.iterator.remove(); + } + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.iterator); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SynchronizedListIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SynchronizedListIterator.java new file mode 100644 index 0000000000..1a52f50617 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/SynchronizedListIterator.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2009 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.internal.iterators; + +import java.util.List; +import java.util.ListIterator; + +import org.eclipse.jpt.utility.internal.StringTools; + +/** + * Wrap a list iterator and synchronize all its methods so it can be safely shared + * among multiple threads. + */ +public class SynchronizedListIterator<E> + implements ListIterator<E> +{ + private final ListIterator<E> listIterator; + + + public SynchronizedListIterator(List<E> list) { + this(list.listIterator()); + } + + public SynchronizedListIterator(ListIterator<E> listIterator) { + super(); + this.listIterator = listIterator; + } + + public synchronized boolean hasNext() { + return this.listIterator.hasNext(); + } + + public synchronized E next() { + return this.listIterator.next(); + } + + public synchronized int nextIndex() { + return this.listIterator.nextIndex(); + } + + public synchronized boolean hasPrevious() { + return this.listIterator.hasPrevious(); + } + + public synchronized E previous() { + return this.listIterator.previous(); + } + + public synchronized int previousIndex() { + return this.listIterator.previousIndex(); + } + + public synchronized void remove() { + this.listIterator.remove(); + } + + public synchronized void add(E e) { + this.listIterator.add(e); + } + + public synchronized void set(E e) { + this.listIterator.set(e); + } + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.listIterator); + } + +} diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayIteratorTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayIteratorTests.java index 4e2e53d84b..a99d88d3fe 100644 --- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayIteratorTests.java +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayIteratorTests.java @@ -23,7 +23,7 @@ public class ArrayIteratorTests extends TestCase { public void testHasNext() { int i = 0; - for (Iterator<String> stream = this.buildIterator(); stream.hasNext();) { + for (Iterator<String> stream = this.buildIterator(); stream.hasNext(); ) { stream.next(); i++; } @@ -31,9 +31,9 @@ public class ArrayIteratorTests extends TestCase { } public void testNext() { - int i = 0; - for (Iterator<String> stream = this.buildIterator(); stream.hasNext();) { - assertEquals("bogus element", ++i, Integer.parseInt(stream.next())); + int i = 1; + for (Iterator<String> stream = this.buildIterator(); stream.hasNext(); ) { + assertEquals("bogus element", i++, Integer.parseInt(stream.next())); } } @@ -54,7 +54,7 @@ public class ArrayIteratorTests extends TestCase { public void testUnsupportedOperationException() { boolean exCaught = false; - for (Iterator<String> stream = this.buildIterator(); stream.hasNext();) { + for (Iterator<String> stream = this.buildIterator(); stream.hasNext(); ) { if (stream.next().equals("3")) { try { stream.remove(); @@ -79,21 +79,29 @@ public class ArrayIteratorTests extends TestCase { integers[1] = new Integer(1); integers[2] = new Integer(2); int i = 0; - for (Iterator<Number> stream = new ArrayIterator<Number>(integers); stream.hasNext();) { + for (Iterator<Number> stream = this.buildGenericIterator(integers); stream.hasNext();) { assertEquals(i++, stream.next().intValue()); } assertEquals(integers.length, i); } + Iterator<Number> buildGenericIterator(Integer[] integers) { + return new ArrayIterator<Number>(integers); + } + public void testVarargs() { int i = 0; - for (Iterator<Number> stream = new ArrayIterator<Number>(new Integer(0), new Integer(1), new Integer(2)); stream.hasNext();) { + for (Iterator<Number> stream = this.buildVarArgIterator(); stream.hasNext();) { assertEquals(i++, stream.next().intValue()); } assertEquals(3, i); } - public void triggerIllegalArgumentException(int start, int length) { + Iterator<Number> buildVarArgIterator() { + return new ArrayIterator<Number>(new Integer(0), new Integer(1), new Integer(2)); + } + + void triggerIllegalArgumentException(int start, int length) { boolean exCaught = false; Iterator<String> stream = null; try { diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayListIteratorTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayListIteratorTests.java index d0a5ad1992..9685b6ff60 100644 --- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayListIteratorTests.java +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/ArrayListIteratorTests.java @@ -12,6 +12,7 @@ package org.eclipse.jpt.utility.tests.internal.iterators; import java.util.Iterator; import java.util.ListIterator; import java.util.NoSuchElementException; + import org.eclipse.jpt.utility.internal.iterators.ArrayListIterator; @SuppressWarnings("nls") @@ -109,25 +110,13 @@ public class ArrayListIteratorTests extends ArrayIteratorTests { } @Override - public void testGenerics() { - Integer[] integers = new Integer[3]; - integers[0] = new Integer(0); - integers[1] = new Integer(1); - integers[2] = new Integer(2); - int i = 0; - for (Iterator<Number> stream = new ArrayListIterator<Number>(integers); stream.hasNext();) { - assertEquals(i++, stream.next().intValue()); - } - assertEquals(integers.length, i); + Iterator<Number> buildGenericIterator(Integer[] integers) { + return new ArrayListIterator<Number>(integers); } @Override - public void testVarargs() { - int i = 0; - for (Iterator<Number> stream = new ArrayListIterator<Number>(new Integer(0), new Integer(1), new Integer(2)); stream.hasNext();) { - assertEquals(i++, stream.next().intValue()); - } - assertEquals(3, i); + Iterator<Number> buildVarArgIterator() { + return new ArrayListIterator<Number>(new Integer(0), new Integer(1), new Integer(2)); } private ListIterator<String> buildListIterator() { diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneIteratorTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneIteratorTests.java index b35cf0a3a0..952df8b02f 100644 --- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneIteratorTests.java +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneIteratorTests.java @@ -91,9 +91,9 @@ public class CloneIteratorTests extends TestCase { } public void testRemoveEliminator() { - CloneIterator.Mutator<String> eliminator = new CloneIterator.Mutator<String>() { - public void remove(String current) { - CloneIteratorTests.this.originalCollection.remove(current); + CloneIterator.Remover<String> eliminator = new CloneIterator.Remover<String>() { + public void remove(String element) { + CloneIteratorTests.this.originalCollection.remove(element); } }; this.verifyRemove(new CloneIterator<String>(this.originalCollection, eliminator)); diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneListIteratorTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneListIteratorTests.java index 0d43074560..44652f3819 100644 --- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneListIteratorTests.java +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/CloneListIteratorTests.java @@ -250,7 +250,7 @@ public class CloneListIteratorTests extends TestCase { } catch (IllegalStateException ex) { exCaught = true; } - assertTrue("IllegalStateException not thrown", exCaught); + assertTrue(exCaught); while (iterator.hasNext()) { String next = iterator.next(); if (next.equals(addedAfter)) { @@ -265,7 +265,7 @@ public class CloneListIteratorTests extends TestCase { } catch (IllegalStateException ex) { exCaught = true; } - assertTrue("IllegalStateException not thrown", exCaught); + assertTrue(exCaught); } if (next.equals(replaced)) { iterator.set(replacement); diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/GraphIteratorTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/GraphIteratorTests.java index 4e4c80d0ef..b0e7ebd428 100644 --- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/GraphIteratorTests.java +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/GraphIteratorTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * Copyright (c) 2005, 2009 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0, which accompanies this distribution * and is available at http://www.eclipse.org/legal/epl-v10.html. @@ -162,7 +162,7 @@ public class GraphIteratorTests extends TestCase { return ncNode; } - private class GraphNode { + public class GraphNode { private String name; private Collection<GraphNode> neighbors = new ArrayList<GraphNode>(); diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/JptUtilityIteratorsTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/JptUtilityIteratorsTests.java index 132b2c7d63..8a660b0ff4 100644 --- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/JptUtilityIteratorsTests.java +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/JptUtilityIteratorsTests.java @@ -38,6 +38,8 @@ public class JptUtilityIteratorsTests { suite.addTestSuite(ReadOnlyListIteratorTests.class); suite.addTestSuite(SingleElementIteratorTests.class); suite.addTestSuite(SingleElementListIteratorTests.class); + suite.addTestSuite(SynchronizedIteratorTests.class); + suite.addTestSuite(SynchronizedListIteratorTests.class); suite.addTestSuite(TransformationIteratorTests.class); suite.addTestSuite(TransformationListIteratorTests.class); suite.addTestSuite(TreeIteratorTests.class); diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/SynchronizedIteratorTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/SynchronizedIteratorTests.java new file mode 100644 index 0000000000..cd527b228e --- /dev/null +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/SynchronizedIteratorTests.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2009 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.tests.internal.iterators; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import junit.framework.TestCase; + +import org.eclipse.jpt.utility.internal.CollectionTools; +import org.eclipse.jpt.utility.internal.iterators.SynchronizedIterator; + +@SuppressWarnings("nls") +public class SynchronizedIteratorTests extends TestCase { + + public SynchronizedIteratorTests(String name) { + super(name); + } + + /** + * test that an unsynchronized iterator will produce corrupt output; + * thread 1 will read the first element from the iterator + * and then sleep for a bit, allowing thread 2 to sneak in and + * read the same element from the iterator + */ + public void testUnsynchronizedNext() throws Exception { + TestIterator<String> iterator = this.buildNestedIterator(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + NextTestThread<String> thread2 = new NextTestThread<String>(iterator); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // both threads should have read the same element from the iterator :-( + assertEquals("foo", thread1.next); + assertEquals("foo", thread2.next); + } + + /** + * test that a synchronized iterator will produce valid output; + * thread 1 will read the first element from the iterator + * and then sleep for a bit, but thread 2 will be locked out and + * wait to read the second element from the iterator + */ + public void testSynchronizedNext() throws Exception { + TestIterator<String> nestedIterator = this.buildNestedIterator(); + Iterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + NextTestThread<String> thread2 = new NextTestThread<String>(iterator); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the threads should have read the correct elements from the iterator :-) + assertEquals("foo", thread1.next); + assertEquals("bar", thread2.next); + } + + public void testUnsynchronizedHasNext() throws Exception { + TestIterator<String> iterator = this.buildNestedIterator(); + iterator.next(); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + HasNextTestThread<String> thread2 = new HasNextTestThread<String>(iterator); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the last element, + // but thread 2 will think there are more elements on the iterator :-( + assertEquals("baz", thread1.next); + assertEquals(true, thread2.hasNext); + } + + public void testSynchronizedHasNext() throws Exception { + TestIterator<String> nestedIterator = this.buildNestedIterator(); + Iterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + iterator.next(); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + HasNextTestThread<String> thread2 = new HasNextTestThread<String>(iterator); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the last element, + // and thread 2 will think there are no more elements on the iterator :-) + assertEquals("baz", thread1.next); + assertEquals(false, thread2.hasNext); + } + + public void testUnsynchronizedRemove() throws Exception { + TestIterator<String> iterator = this.buildNestedIterator(); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + RemoveTestThread<String> thread2 = new RemoveTestThread<String>(iterator); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the wrong element was removed :-( + assertEquals("bar", thread1.next); + assertFalse(iterator.list.contains("foo")); + assertTrue(iterator.list.contains("bar")); + assertTrue(iterator.list.contains("baz")); + } + + public void testSynchronizedRemove() throws Exception { + TestIterator<String> nestedIterator = this.buildNestedIterator(); + Iterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + RemoveTestThread<String> thread2 = new RemoveTestThread<String>(iterator); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the wrong element was removed :-( + assertEquals("bar", thread1.next); + assertTrue(nestedIterator.list.contains("foo")); + assertFalse(nestedIterator.list.contains("bar")); + assertTrue(nestedIterator.list.contains("baz")); + } + + TestIterator<String> buildNestedIterator() { + return new TestIterator<String>(this.buildArray()); + } + + String[] buildArray() { + return new String[] {"foo", "bar", "baz"}; + } + + Iterator<String> buildSynchronizedIterator(Iterator<String> nestedIterator) { + return new SynchronizedIterator<String>(nestedIterator); + } + + + /** + * next thread + */ + class NextTestThread<E> extends Thread { + final Iterator<E> iterator; + E next; + + NextTestThread(Iterator<E> iterator) { + super(); + this.iterator = iterator; + } + + @Override + public void run() { + this.next = this.iterator.next(); + } + + } + + /** + * has next thread + */ + class HasNextTestThread<E> extends Thread { + final Iterator<E> iterator; + boolean hasNext; + + HasNextTestThread(Iterator<E> iterator) { + super(); + this.iterator = iterator; + } + + @Override + public void run() { + this.hasNext = this.iterator.hasNext(); + } + + } + + /** + * remove thread + */ + class RemoveTestThread<E> extends Thread { + final Iterator<E> iterator; + + RemoveTestThread(Iterator<E> iterator) { + super(); + this.iterator = iterator; + } + + @Override + public void run() { + this.iterator.remove(); + } + + } + + /** + * test iterator + */ + class TestIterator<E> implements Iterator<E> { + final ArrayList<E> list; + int nextIndex; + int lastIndex = -1; + Thread slowThread; + + TestIterator(E... array) { + super(); + this.list = new ArrayList<E>(); + CollectionTools.addAll(this.list, array); + this.nextIndex = 0; + } + + public boolean hasNext() { + return this.nextIndex != this.list.size(); + } + + public E next() { + if (this.hasNext()) { + E next = this.list.get(this.nextIndex); + this.sleep(); + this.lastIndex = this.nextIndex++; + return next; + } + throw new NoSuchElementException(); + } + + public void remove() { + if (this.lastIndex == -1) { + throw new IllegalStateException(); + } + this.list.remove(this.lastIndex); + if (this.lastIndex < this.nextIndex) { // check necessary for ListIterator + this.nextIndex--; + } + this.lastIndex = -1; + } + + void sleep() { + if (Thread.currentThread() == this.slowThread) { + SynchronizedIteratorTests.sleep(200); + } + } + + } + + static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/SynchronizedListIteratorTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/SynchronizedListIteratorTests.java new file mode 100644 index 0000000000..de5f53dc8d --- /dev/null +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/iterators/SynchronizedListIteratorTests.java @@ -0,0 +1,500 @@ +/******************************************************************************* + * Copyright (c) 2009 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.utility.tests.internal.iterators; + +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.eclipse.jpt.utility.internal.iterators.SynchronizedListIterator; + +@SuppressWarnings("nls") +public class SynchronizedListIteratorTests extends SynchronizedIteratorTests { + + public SynchronizedListIteratorTests(String name) { + super(name); + } + + public void testUnsynchronizedPrevious() throws Exception { + TestListIterator<String> iterator = this.buildNestedIterator(); + iterator.next(); + iterator.next(); + + PreviousTestThread<String> thread1 = new PreviousTestThread<String>(iterator); + PreviousTestThread<String> thread2 = new PreviousTestThread<String>(iterator); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // both threads should have read the same element from the iterator :-( + assertEquals("bar", thread1.previous); + assertEquals("bar", thread2.previous); + } + + public void testSynchronizedPrevious() throws Exception { + TestListIterator<String> nestedIterator = this.buildNestedIterator(); + ListIterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + iterator.next(); + iterator.next(); + + PreviousTestThread<String> thread1 = new PreviousTestThread<String>(iterator); + PreviousTestThread<String> thread2 = new PreviousTestThread<String>(iterator); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the threads should have read the correct elements from the iterator :-) + assertEquals("bar", thread1.previous); + assertEquals("foo", thread2.previous); + } + + public void testUnsynchronizedHasPrevious() throws Exception { + TestListIterator<String> iterator = this.buildNestedIterator(); + iterator.next(); + + PreviousTestThread<String> thread1 = new PreviousTestThread<String>(iterator); + HasPreviousTestThread<String> thread2 = new HasPreviousTestThread<String>(iterator); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the first element, + // but thread 2 will think there are more "previous" elements on the iterator :-( + assertEquals("foo", thread1.previous); + assertEquals(true, thread2.hasPrevious); + } + + public void testSynchronizedHasPrevious() throws Exception { + TestListIterator<String> nestedIterator = this.buildNestedIterator(); + ListIterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + iterator.next(); + + PreviousTestThread<String> thread1 = new PreviousTestThread<String>(iterator); + HasPreviousTestThread<String> thread2 = new HasPreviousTestThread<String>(iterator); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the first element, + // and thread 2 will think there are no more "previous" elements on the iterator :-) + assertEquals("foo", thread1.previous); + assertEquals(false, thread2.hasPrevious); + } + + public void testUnsynchronizedNextIndex() throws Exception { + TestListIterator<String> iterator = this.buildNestedIterator(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + NextIndexTestThread<String> thread2 = new NextIndexTestThread<String>(iterator); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the first element, + // but thread 2 will think the next index is still 0 :-( + assertEquals("foo", thread1.next); + assertEquals(0, thread2.nextIndex); + } + + public void testSynchronizedNextIndex() throws Exception { + TestListIterator<String> nestedIterator = this.buildNestedIterator(); + ListIterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + NextIndexTestThread<String> thread2 = new NextIndexTestThread<String>(iterator); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the first element, + // and thread 2 will think the next index is 1 :-) + assertEquals("foo", thread1.next); + assertEquals(1, thread2.nextIndex); + } + + public void testUnsynchronizedPreviousIndex() throws Exception { + TestListIterator<String> iterator = this.buildNestedIterator(); + iterator.next(); + + PreviousTestThread<String> thread1 = new PreviousTestThread<String>(iterator); + PreviousIndexTestThread<String> thread2 = new PreviousIndexTestThread<String>(iterator); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the first element, + // but thread 2 will think the next index is still 0 :-( + assertEquals("foo", thread1.previous); + assertEquals(0, thread2.previousIndex); + } + + public void testSynchronizedPreviousIndex() throws Exception { + TestListIterator<String> nestedIterator = this.buildNestedIterator(); + ListIterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + iterator.next(); + + PreviousTestThread<String> thread1 = new PreviousTestThread<String>(iterator); + PreviousIndexTestThread<String> thread2 = new PreviousIndexTestThread<String>(iterator); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // thread 1 will have the first element, + // and thread 2 will think the next index is -1 :-) + assertEquals("foo", thread1.previous); + assertEquals(-1, thread2.previousIndex); + } + + public void testUnsynchronizedSet() throws Exception { + TestListIterator<String> iterator = this.buildNestedIterator(); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + SetTestThread<String> thread2 = new SetTestThread<String>(iterator, "xxx"); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the wrong element was set :-( + assertEquals("bar", thread1.next); + assertFalse(iterator.list.contains("foo")); + assertTrue(iterator.list.contains("xxx")); + assertTrue(iterator.list.contains("bar")); + assertTrue(iterator.list.contains("baz")); + } + + public void testSynchronizedSet() throws Exception { + TestListIterator<String> nestedIterator = this.buildNestedIterator(); + ListIterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + SetTestThread<String> thread2 = new SetTestThread<String>(iterator, "xxx"); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the right element was set :-) + assertEquals("bar", thread1.next); + assertTrue(nestedIterator.list.contains("foo")); + assertFalse(nestedIterator.list.contains("bar")); + assertTrue(nestedIterator.list.contains("xxx")); + assertTrue(nestedIterator.list.contains("baz")); + } + + public void testUnsynchronizedAdd() throws Exception { + TestListIterator<String> iterator = this.buildNestedIterator(); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + AddTestThread<String> thread2 = new AddTestThread<String>(iterator, "xxx"); + iterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the element was added at the wrong index :-( + assertEquals("bar", thread1.next); + assertTrue(iterator.list.contains("foo")); + assertEquals(0, iterator.list.indexOf("xxx")); + assertTrue(iterator.list.contains("xxx")); + assertTrue(iterator.list.contains("bar")); + assertTrue(iterator.list.contains("baz")); + } + + public void testSynchronizedAdd() throws Exception { + TestListIterator<String> nestedIterator = this.buildNestedIterator(); + ListIterator<String> iterator = this.buildSynchronizedIterator(nestedIterator); + iterator.next(); + + NextTestThread<String> thread1 = new NextTestThread<String>(iterator); + AddTestThread<String> thread2 = new AddTestThread<String>(iterator, "xxx"); + nestedIterator.slowThread = thread1; + + thread1.start(); + + // allow thread 1 to read the first element and get bogged down + sleep(100); + thread2.start(); + + // wait for the threads to finish + thread1.join(); + thread2.join(); + + // the element was added at the correct index :-) + assertEquals("bar", thread1.next); + assertTrue(nestedIterator.list.contains("foo")); + assertEquals(1, nestedIterator.list.indexOf("xxx")); + assertTrue(nestedIterator.list.contains("xxx")); + assertTrue(nestedIterator.list.contains("bar")); + assertTrue(nestedIterator.list.contains("baz")); + } + + @Override + ListIterator<String> buildSynchronizedIterator(Iterator<String> nestedIterator) { + return new SynchronizedListIterator<String>((ListIterator<String>) nestedIterator); + } + + @Override + TestListIterator<String> buildNestedIterator() { + return new TestListIterator<String>(this.buildArray()); + } + + /** + * previous thread + */ + class PreviousTestThread<E> extends Thread { + final ListIterator<E> iterator; + E previous; + + PreviousTestThread(ListIterator<E> iterator) { + super(); + this.iterator = iterator; + } + + @Override + public void run() { + this.previous = this.iterator.previous(); + } + + } + + /** + * has previous thread + */ + class HasPreviousTestThread<E> extends Thread { + final ListIterator<E> iterator; + boolean hasPrevious; + + HasPreviousTestThread(ListIterator<E> iterator) { + super(); + this.iterator = iterator; + } + + @Override + public void run() { + this.hasPrevious = this.iterator.hasPrevious(); + } + + } + + /** + * next index thread + */ + class NextIndexTestThread<E> extends Thread { + final ListIterator<E> iterator; + int nextIndex; + + NextIndexTestThread(ListIterator<E> iterator) { + super(); + this.iterator = iterator; + } + + @Override + public void run() { + this.nextIndex = this.iterator.nextIndex(); + } + + } + + /** + * previous index thread + */ + class PreviousIndexTestThread<E> extends Thread { + final ListIterator<E> iterator; + int previousIndex; + + PreviousIndexTestThread(ListIterator<E> iterator) { + super(); + this.iterator = iterator; + } + + @Override + public void run() { + this.previousIndex = this.iterator.previousIndex(); + } + + } + + /** + * set thread + */ + class SetTestThread<E> extends Thread { + final ListIterator<E> iterator; + final E element; + + SetTestThread(ListIterator<E> iterator, E element) { + super(); + this.iterator = iterator; + this.element = element; + } + + @Override + public void run() { + this.iterator.set(this.element); + } + + } + + /** + * add thread + */ + class AddTestThread<E> extends Thread { + final ListIterator<E> iterator; + final E element; + + AddTestThread(ListIterator<E> iterator, E element) { + super(); + this.iterator = iterator; + this.element = element; + } + + @Override + public void run() { + this.iterator.add(this.element); + } + + } + + /** + * test list iterator + */ + class TestListIterator<E> extends TestIterator<E> implements ListIterator<E> { + + TestListIterator(E... array) { + super(array); + } + + public int nextIndex() { + return this.nextIndex; + } + + public boolean hasPrevious() { + return this.nextIndex != 0; + } + + public E previous() { + if (this.hasPrevious()) { + E previous = this.list.get(this.previousIndex()); + sleep(); + this.nextIndex--; + this.lastIndex = this.nextIndex; + return previous; + } + throw new NoSuchElementException(); + } + + public int previousIndex() { + return this.nextIndex - 1; + } + + public void set(E e) { + if (this.lastIndex == -1) { + throw new IllegalStateException(); + } + this.list.set(this.lastIndex, e); + } + + public void add(E e) { + this.list.add(this.lastIndex, e); + this.lastIndex++; + this.lastIndex = -1; + } + + } + +} |