Author: desruisseaux
Date: Mon Feb 23 20:33:19 2015
New Revision: 1661768
URL: http://svn.apache.org/r1661768
Log:
Adjustement to the workaround for java.util.ServiceLoader bug.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/LazySet.java
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/LazySetTest.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1661768&r1=1661767&r2=1661768&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
[UTF-8] Mon Feb 23 20:33:19 2015
@@ -228,16 +228,16 @@ public class DefaultMathTransformFactory
*/
public DefaultMathTransformFactory() {
/*
- * WORKAROUND for a JDK bug: ServiceLoader do not support usage of two
Iterator.
- * Steps to reproduce:
+ * WORKAROUND for a JDK bug: ServiceLoader does not support usage of
two Iterator instances
+ * before the first iteration is finished. Steps to reproduce:
*
- * ServiceLoader<ServiceLoaderTest> loader =
ServiceLoader.load(ServiceLoaderTest.class);
+ * ServiceLoader<?> loader =
ServiceLoader.load(OperationMethod.class);
*
- * Iterator<ServiceLoaderTest> it1 = loader.iterator();
+ * Iterator<?> it1 = loader.iterator();
* assertTrue ( it1.hasNext() );
* assertNotNull( it1.next()) );
*
- * Iterator<ServiceLoaderTest> it2 = loader.iterator();
+ * Iterator<?> it2 = loader.iterator();
* assertTrue ( it1.hasNext()) );
* assertTrue ( it2.hasNext()) );
* assertNotNull( it1.next()) );
@@ -897,8 +897,13 @@ public class DefaultMathTransformFactory
public void reload() {
synchronized (methods) {
methodsByName.clear();
- if (methods instanceof ServiceLoader<?>) {
- ((ServiceLoader<?>) methods).reload();
+ Iterable<? extends OperationMethod> m = methods;
+ if (m instanceof LazySet<?>) { // Workaround for JDK bug. See
DefaultMathTransformFactory() constructor.
+ ((LazySet<?>) m).reload();
+ m = ((LazySet<? extends OperationMethod>) m).source;
+ }
+ if (m instanceof ServiceLoader<?>) {
+ ((ServiceLoader<?>) m).reload();
}
synchronized (methodsByType) {
for (final OperationMethodSet c : methodsByType.values()) {
Modified:
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/LazySet.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/LazySet.java?rev=1661768&r1=1661767&r2=1661768&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/LazySet.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/LazySet.java
[UTF-8] Mon Feb 23 20:33:19 2015
@@ -20,12 +20,20 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.AbstractSet;
import java.util.NoSuchElementException;
+import org.apache.sis.util.Workaround;
/**
* An immutable set built from an iterator, which will be filled only when
needed.
- * This implementation do <strong>not</strong> check if all elements in the
iterator
- * are really unique; we assume that it was already verified by the caller.
+ * This implementation does <strong>not</strong> check if all elements in the
iterator
+ * are really unique; we assume that this condition was already verified by
the caller.
+ *
+ * <p>One usage of {@code LazySet} is to workaround a {@link
java.util.ServiceLoader} bug which block usage of two
+ * {@link Iterator} instances together: the first iteration must be fully
completed or abandoned before we can start
+ * a new iteration. See
+ * {@link
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#DefaultMathTransformFactory()}.</p>
+ *
+ * <p>This class is not thread-safe. Synchronization, if desired, shall be
done by the caller.</p>
*
* @param <E> The type of elements in the set.
*
@@ -34,14 +42,23 @@ import java.util.NoSuchElementException;
* @version 0.6
* @module
*/
+@Workaround(library="JDK", version="1.8.0_31-b13")
public final class LazySet<E> extends AbstractSet<E> {
/**
- * The iterator to use for filling this set, or {@code null} if the
iteration is over.
+ * The original source of elements, or {@code null} if unknown.
+ */
+ public final Iterable<? extends E> source;
+
+ /**
+ * The iterator to use for filling this set, or {@code null} if the
iteration did not started yet
+ * or is finished. Those two cases can be distinguished by looking whether
the {@link #elements}
+ * array is null or not.
*/
private Iterator<? extends E> iterator;
/**
- * The elements in this set. This array will grown as needed.
+ * The elements in this set, or {@code null} if the iteration did not
started yet.
+ * After the iteration started, this array will grow as needed.
*/
private E[] elements;
@@ -52,6 +69,18 @@ public final class LazySet<E> extends Ab
private int position;
/**
+ * Constructs a set to be filled by the elements from the specified
source. Iteration will starts
+ * only when first needed, and at most one iteration will be performed
(unless {@link #reload()}
+ * is invoked).
+ *
+ * @param source The source of elements to use for filling the set.
+ */
+ @SuppressWarnings("unchecked")
+ public LazySet(final Iterable<? extends E> source) {
+ this.source = source;
+ }
+
+ /**
* Constructs a set to be filled using the specified iterator.
* Iteration in the given iterator will occurs only when needed.
*
@@ -59,16 +88,41 @@ public final class LazySet<E> extends Ab
*/
@SuppressWarnings("unchecked")
public LazySet(final Iterator<? extends E> iterator) {
+ source = null;
this.iterator = iterator;
elements = (E[]) new Object[4];
}
/**
+ * Notify this {@code LazySet} that it should re-fetch the elements from
the {@linkplain #source}.
+ */
+ public void reload() {
+ if (source != null) {
+ iterator = null;
+ elements = null;
+ position = 0;
+ }
+ }
+
+ /**
+ * Returns the iterator over the source elements, or {@code null} if the
iteration is finished.
+ */
+ @SuppressWarnings("unchecked")
+ private Iterator<? extends E> sourceElements() {
+ if (iterator == null && elements == null && source != null) {
+ iterator = source.iterator();
+ elements = (E[]) new Object[4];
+ }
+ return iterator;
+ }
+
+ /**
* Returns {@code true} if the {@link #iterator} is non-null and have more
elements to return.
*/
private boolean hasNext() {
- if (iterator != null) {
- if (iterator.hasNext()) {
+ final Iterator<? extends E> it = sourceElements();
+ if (it != null) {
+ if (it.hasNext()) {
return true;
}
iterator = null;
@@ -94,9 +148,10 @@ public final class LazySet<E> extends Ab
*/
@Override
public int size() {
- if (iterator != null) {
- while (iterator.hasNext()) {
- addNext();
+ final Iterator<? extends E> it = sourceElements();
+ if (it != null) {
+ while (it.hasNext()) {
+ cache(it.next());
}
iterator = null;
}
@@ -104,14 +159,13 @@ public final class LazySet<E> extends Ab
}
/**
- * Adds the next element from the iterator to this set. This method does
not check if more
- * element were available; the check must have been done before to invoke
this method.
+ * Adds the given element to the {@link #elements} array.
*/
- private void addNext() {
+ private void cache(final E element) {
if (position >= elements.length) {
elements = Arrays.copyOf(elements, position*2);
}
- elements[position++] = iterator.next();
+ elements[position++] = element;
}
/**
@@ -135,7 +189,7 @@ public final class LazySet<E> extends Ab
final E get(final int index) {
if (index >= position) {
if (hasNext()) {
- addNext();
+ cache(iterator.next());
} else {
throw new NoSuchElementException();
}
Modified:
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/LazySetTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/LazySetTest.java?rev=1661768&r1=1661767&r2=1661768&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/LazySetTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/LazySetTest.java
[UTF-8] Mon Feb 23 20:33:19 2015
@@ -17,6 +17,7 @@
package org.apache.sis.internal.util;
import java.util.Arrays;
+import java.util.Iterator;
import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -42,7 +43,7 @@ public final strictfp class LazySetTest
* Creates the set to use for testing purpose.
*/
private static LazySet<String> create() {
- return new LazySet<>(Arrays.asList(LABELS).iterator());
+ return new LazySet<>(Arrays.asList(LABELS));
}
/**
@@ -77,4 +78,36 @@ public final strictfp class LazySetTest
assertArrayEquals(LABELS, set.toArray());
assertEquals(LABELS.length, set.size());
}
+
+ /**
+ * Tests iteration using two iterators with interleaved calls to {@link
Iterator#next()}.
+ */
+ @Test
+ @DependsOnMethod("testIteration")
+ public void testInterleavedIteration() {
+ final LazySet<String> set = create();
+
+ final Iterator<String> it1 = set.iterator();
+ assertTrue(it1.hasNext());
+ assertEquals("one", it1.next());
+
+ final Iterator<String> it2 = set.iterator();
+ assertTrue (it2.hasNext());
+ assertEquals("one", it2.next());
+
+ assertTrue (it1.hasNext());
+ assertTrue (it2.hasNext());
+ assertEquals("two", it1.next());
+ assertEquals("two", it2.next());
+ assertEquals("three", it2.next());
+ assertEquals("four", it2.next());
+ assertFalse (it2.hasNext());
+ assertTrue (it1.hasNext());
+ assertEquals("three", it1.next());
+ assertEquals("four", it1.next());
+ assertFalse (it2.hasNext());
+ assertFalse (it1.hasNext());
+
+ assertEquals(LABELS.length, set.size());
+ }
}