This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit bbd71a4c2281e2feae6b4c2a456ef8d1d027dd2b
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sat Jun 10 17:42:00 2023 +0200

    Remove the use of internal `LazySet` as a workaround for JDK 8 bug in 
`java.util.ServiceLoader` since this workaround is no longer necessary.
    Remove usage of `ServiceLoader` in `LazySet` since it does not work anymore 
in JPMS context. Services shall be loaded in the caller class.
---
 .../apache/sis/internal/referencing/LazySet.java   | 93 +++++++---------------
 .../apache/sis/referencing/AuthorityFactories.java | 16 +++-
 .../transform/DefaultMathTransformFactory.java     | 25 +-----
 .../sis/internal/referencing/LazySetTest.java      |  8 +-
 .../referencing/provider/ProvidersTest.java        |  2 +-
 .../transform/DefaultMathTransformFactoryTest.java | 21 +++++
 .../org/apache/sis/internal/netcdf/Convention.java |  8 +-
 .../org/apache/sis/storage/DataStoreRegistry.java  | 60 +++++++-------
 .../java/org/apache/sis/storage/DataStores.java    | 54 ++-----------
 .../org/apache/sis/storage/DataStoresTest.java     |  6 +-
 10 files changed, 121 insertions(+), 172 deletions(-)

diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/LazySet.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/LazySet.java
index e70e9da650..c4cb25425f 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/LazySet.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/LazySet.java
@@ -16,46 +16,32 @@
  */
 package org.apache.sis.internal.referencing;
 
-import java.util.List;
 import java.util.Arrays;
-import java.util.Objects;
 import java.util.Iterator;
-import java.util.ServiceLoader;
 import java.util.NoSuchElementException;
-import org.apache.sis.internal.system.Reflect;
 import org.apache.sis.internal.util.SetOfUnknownSize;
-import org.apache.sis.internal.util.UnmodifiableArrayList;
 
 
 /**
- * An immutable set built from an iterator, which will be filled only when 
needed.
+ * An unmodifiable set built from an iterator, which will be filled only when 
needed.
  * 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 blocks 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>Some usages for this class are to prepend some values before the 
elements given by the source {@code Iterable},
  * or to replace some values when they are loaded. It may also be used for 
creating filtered sets when used together
  * with {@link org.apache.sis.internal.util.CollectionsExt#filter 
CollectionsExt.filter(…)}.</p>
  *
- * <p>This class is not thread-safe. Synchronization, if desired, shall be 
done by the caller.</p>
+ * <h2>Thread-safety</h2>
+ * This class is thread safe. The synchronization lock is {@code this}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.4
  *
  * @param <E>  the type of elements in the set.
  *
  * @since 0.6
  */
-public class LazySet<E> extends SetOfUnknownSize<E> {
-    /**
-     * The type of service to request with {@link ServiceLoader}, or {@code 
null} if unknown.
-     */
-    private final Class<E> service;
-
+public abstract class LazySet<E> extends SetOfUnknownSize<E> {
     /**
      * 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 
#cachedElements} array is null or not.
@@ -78,39 +64,19 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
     private int numCached;
 
     /**
-     * Constructs a set to be filled by the elements from the specified 
source. Iteration will start only when
-     * first needed, and at most one iteration will be performed (unless 
{@link #reload()} is invoked).
-     *
-     * @param  service  the type of service to request with {@link 
ServiceLoader}.
+     * Creates a new set.
      */
-    public LazySet(final Class<E> service) {
-        Objects.requireNonNull(service);
-        this.service = service;
+    protected LazySet() {
     }
 
     /**
-     * Constructs a set to be filled using the specified iterator.
-     * Iteration with the given iterator will occur only when needed.
+     * Creates the iterator which will provide the elements of this set before 
filtering.
+     * This method will be invoked only when first needed and at most once, 
unless {@link #reload()} is invoked.
+     * After creation, calls to {@link Iterator#next()} will also be done only 
when first needed.
      *
-     * @param  iterator  the iterator to use for filling this set.
+     * @return iterator over the elements of this set before filtering.
      */
-    public LazySet(final Iterator<? extends E> iterator) {
-        Objects.requireNonNull(iterator);
-        sourceIterator = iterator;
-        service = null;
-        createCache();
-    }
-
-    /**
-     * Notifies this {@code LazySet} that it should re-fetch the elements from 
the source given at construction time.
-     */
-    public void reload() {
-        if (service != null) {
-            sourceIterator = null;
-            cachedElements = null;
-            numCached = 0;
-        }
-    }
+    protected abstract Iterator<? extends E> createSourceIterator();
 
     /**
      * Hook for subclasses that want to prepend some values before the source 
{@code Iterable}.
@@ -151,7 +117,7 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
      */
     private boolean canPullMore() {
         if (sourceIterator == null && cachedElements == null) {
-            sourceIterator = ServiceLoader.load(service, 
Reflect.getContextClassLoader()).iterator();
+            sourceIterator = createSourceIterator();
             if (createCache()) {
                 return true;
             }
@@ -171,7 +137,7 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
      * @return {@code true} if this set has no element.
      */
     @Override
-    public final boolean isEmpty() {
+    public final synchronized boolean isEmpty() {
         return (numCached == 0) && !canPullMore();
     }
 
@@ -182,7 +148,7 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
      * @return number of elements in the iterator.
      */
     @Override
-    public final int size() {
+    public final synchronized int size() {
         if (canPullMore()) {
             while (sourceIterator.hasNext()) {
                 cache(next(sourceIterator));
@@ -206,12 +172,12 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
     }
 
     /**
-     * Caches a new element. Subclasses can override this method if they want 
to substitute the given value
-     * by another value.
+     * Caches a new element. This method is invoked by {@code LazySet} inside 
a synchronized block.
+     * Subclasses could override this method if they want to substitute the 
given value by another value.
      *
      * @param  element  the element to add to the cache.
      */
-    protected void cache(final E element) {
+    private void cache(final E element) {
         if (cachedElements == null) {
             createCache();
         }
@@ -221,16 +187,6 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
         cachedElements[numCached++] = element;
     }
 
-    /**
-     * Returns an unmodifiable view over the elements cached so far.
-     * The returned list does not contain any elements that were not yet 
fetched from the source.
-     *
-     * @return the elements cached so far.
-     */
-    protected final List<E> cached() {
-        return UnmodifiableArrayList.wrap(cachedElements, 0, numCached);
-    }
-
     /**
      * Returns {@code true} if an element exists at the given index.
      * The element is not loaded immediately.
@@ -239,7 +195,7 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
      * It is not suited for more general usage since it does not check for
      * negative index and for skipped elements.</p>
      */
-    final boolean exists(final int index) {
+    private synchronized boolean exists(final int index) {
         assert index <= numCached : index;
         return (index < numCached) || canPullMore();
     }
@@ -250,7 +206,7 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
      * @param  index  the index at which to get an element.
      * @return the element at the requested index.
      */
-    final E get(final int index) {
+    private synchronized E get(final int index) {
         assert numCached <= cachedElements.length : numCached;
         assert index <= numCached : index;
         if (index >= numCached) {
@@ -285,4 +241,13 @@ public class LazySet<E> extends SetOfUnknownSize<E> {
             }
         };
     }
+
+    /**
+     * Notifies this {@code LazySet} that it should re-fetch the elements from 
the source.
+     */
+    public synchronized void reload() {
+        sourceIterator = null;
+        cachedElements = null;
+        numCached = 0;
+    }
 }
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
index 1d67cf0fb9..04474329da 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
@@ -29,6 +29,7 @@ import org.opengis.referencing.crs.CRSAuthorityFactory;
 import org.opengis.referencing.datum.DatumAuthorityFactory;
 import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
 import org.apache.sis.internal.referencing.LazySet;
+import org.apache.sis.internal.system.Reflect;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.system.SystemListener;
@@ -95,11 +96,24 @@ final class AuthorityFactories<T extends AuthorityFactory> 
extends LazySet<T> {
         });
     }
 
+    /**
+     * The type of service to request with {@link ServiceLoader}, or {@code 
null} if unknown.
+     */
+    private final Class<T> service;
+
     /**
      * Creates a new provider for factories of the given type.
      */
     private AuthorityFactories(final Class<T> type) {
-        super(type);
+        service = type;
+    }
+
+    /**
+     * Creates the iterator which will provide the elements of this set before 
filtering.
+     */
+    @Override
+    protected Iterator<? extends T> createSourceIterator() {
+        return ServiceLoader.load(service, 
Reflect.getContextClassLoader()).iterator();
     }
 
     /**
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index 7c062b2ff2..783eca7656 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -57,7 +57,6 @@ import org.apache.sis.io.wkt.Parser;
 import org.apache.sis.internal.util.URLs;
 import org.apache.sis.internal.util.Strings;
 import org.apache.sis.internal.util.Constants;
-import org.apache.sis.internal.referencing.LazySet;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.referencing.CoordinateOperations;
 import org.apache.sis.internal.referencing.ReferencingUtilities;
@@ -67,6 +66,7 @@ import 
org.apache.sis.internal.referencing.provider.VerticalOffset;
 import org.apache.sis.internal.referencing.provider.GeographicToGeocentric;
 import org.apache.sis.internal.referencing.provider.GeocentricToGeographic;
 import org.apache.sis.internal.referencing.Resources;
+import org.apache.sis.internal.system.Reflect;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.parameter.DefaultParameterValueGroup;
 import org.apache.sis.parameter.Parameterized;
@@ -282,25 +282,7 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
      * @see #reload()
      */
     public DefaultMathTransformFactory() {
-        /*
-         * WORKAROUND for a JDK bug: ServiceLoader does not support usage of 
two Iterator instances
-         * before the first iteration is finished. Steps to reproduce:
-         *
-         *     ServiceLoader<?> loader = 
ServiceLoader.load(OperationMethod.class);
-         *
-         *     Iterator<?> it1 = loader.iterator();
-         *     assertTrue   ( it1.hasNext() );
-         *     assertNotNull( it1.next())   );
-         *
-         *     Iterator<?> it2 = loader.iterator();
-         *     assertTrue   ( it1.hasNext()) );
-         *     assertTrue   ( it2.hasNext()) );
-         *     assertNotNull( it1.next())    );
-         *     assertNotNull( it2.next())    );     // 
ConcurrentModificationException here !!!
-         *
-         * Wrapping the ServiceLoader in a LazySet avoid this issue.
-         */
-        this(new LazySet<OperationMethod>(OperationMethod.class));
+        this(ServiceLoader.load(OperationMethod.class, 
Reflect.getContextClassLoader()));
     }
 
     /**
@@ -1771,9 +1753,6 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
         synchronized (methods) {
             methodsByName.clear();
             final Iterable<? extends OperationMethod> m = methods;
-            if (m instanceof LazySet<?>) { // Workaround for JDK bug. See 
DefaultMathTransformFactory() constructor.
-                ((LazySet<? extends OperationMethod>) m).reload();
-            }
             if (m instanceof ServiceLoader<?>) {
                 ((ServiceLoader<?>) m).reload();
             }
diff --git 
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/LazySetTest.java
 
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/LazySetTest.java
index c28651963e..73388691b2 100644
--- 
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/LazySetTest.java
+++ 
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/LazySetTest.java
@@ -29,7 +29,7 @@ import static org.junit.Assert.*;
  * Tests {@link LazySet}
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.4
  * @since   0.6
  */
 public final class LazySetTest extends TestCase {
@@ -42,7 +42,11 @@ public final class LazySetTest extends TestCase {
      * Creates the set to use for testing purpose.
      */
     private static LazySet<String> create() {
-        return new LazySet<>(Arrays.asList(LABELS).iterator());
+        return new LazySet<>() {
+            @Override protected Iterator<String> createSourceIterator() {
+                return Arrays.asList(LABELS).iterator();
+            }
+        };
     }
 
     /**
diff --git 
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
 
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
index a775c0601a..14cac2b1b5 100644
--- 
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
+++ 
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
@@ -33,7 +33,7 @@ import static org.junit.Assert.*;
 
 
 /**
- * Tests {@link Providers} and some consistency rules of all providers defined 
in this package.
+ * Tests some consistency rules of all providers defined in this package.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.4
diff --git 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
index 4d90d2b28d..367fe18a94 100644
--- 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
+++ 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
@@ -19,6 +19,7 @@ package org.apache.sis.referencing.operation.transform;
 import java.util.Map;
 import java.util.Set;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.ServiceLoader;
 import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
@@ -89,6 +90,26 @@ public final class DefaultMathTransformFactoryTest extends 
TestCase {
         assertSame(factory(), factory);
     }
 
+    /**
+     * Tests the correction for a Java 8 bug. In Java 8, {@link ServiceLoader} 
didn't supported
+     * the usage of two {@link Iterator} instances before the first iteration 
is finished.
+     * This problem has been fixed with Java Platform Module System (JPMS) 
implementation.
+     */
+    @Test
+    public void testServiceLoaderIterator() {
+        ServiceLoader<?> loader = ServiceLoader.load(OperationMethod.class);
+
+        Iterator<?> it1 = loader.iterator();
+        assertTrue   (it1.hasNext());
+        assertNotNull(it1.next());
+
+        Iterator<?> it2 = loader.iterator();
+        assertTrue   (it1.hasNext());
+        assertTrue   (it2.hasNext());
+        assertNotNull(it1.next());
+        assertNotNull(it2.next());      // ConcurrentModificationException was 
used to be thownn here.
+    }
+
     /**
      * Tests the {@link 
DefaultMathTransformFactory#getOperationMethod(String)} method.
      *
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
index 72cdc7cd69..d165729949 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Locale;
+import java.util.ServiceLoader;
 import java.util.function.Function;
 import java.awt.Color;
 import javax.measure.Unit;
@@ -33,8 +34,8 @@ import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.referencing.operation.transform.TransferFunction;
 import org.apache.sis.referencing.datum.BursaWolfParameters;
 import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.internal.referencing.LazySet;
 import org.apache.sis.internal.coverage.j2d.ColorModelFactory;
+import org.apache.sis.internal.system.Reflect;
 import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.coverage.Category;
@@ -67,7 +68,7 @@ import ucar.nc2.constants.CF;
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.3
+ * @version 1.4
  *
  * @see <a href="https://issues.apache.org/jira/browse/SIS-315";>SIS-315</a>
  *
@@ -77,7 +78,8 @@ public class Convention {
     /**
      * All conventions found on the classpath.
      */
-    private static final LazySet<Convention> AVAILABLES = new 
LazySet<>(Convention.class);
+    private static final ServiceLoader<Convention> AVAILABLES =
+            ServiceLoader.load(Convention.class, 
Reflect.getContextClassLoader());
 
     /**
      * The convention to use when no specific conventions were found.
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
index 2290c9ad63..515cc89c49 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
@@ -18,10 +18,11 @@ package org.apache.sis.storage;
 
 import java.util.List;
 import java.util.LinkedList;
-import java.util.Set;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 import org.apache.sis.internal.system.Reflect;
+import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.system.SystemListener;
 import org.apache.sis.internal.storage.Resources;
 import org.apache.sis.internal.storage.StoreMetadata;
 import org.apache.sis.internal.referencing.LazySet;
@@ -31,12 +32,8 @@ import org.apache.sis.util.ArraysExt;
 
 /**
  * Creates {@link DataStore} instances for a given storage object by scanning 
all providers on the classpath.
- * Storage objects are typically {@link java.io.File} or {@link 
javax.sql.DataSource} instances, but can also
- * be any other objects documented in the {@link StorageConnector} class.
- *
- * <h2>API note</h2>
- * This class is package-private for now in order to get more experience about 
what could be a good API.
- * This class may become public in a future SIS version.
+ * Storage objects are typically {@link java.io.File} or {@link 
javax.sql.DataSource} instances,
+ * but can also be any other objects documented in the {@link 
StorageConnector} class.
  *
  * <h2>Thread safety</h2>
  * The same {@code DataStoreRegistry} instance can be safely used by many 
threads without synchronization
@@ -46,7 +43,19 @@ import org.apache.sis.util.ArraysExt;
  * @version 1.4
  * @since   0.4
  */
-final class DataStoreRegistry {
+final class DataStoreRegistry extends LazySet<DataStoreProvider> {
+    /**
+     * The unique instance of this registry.
+     */
+    static final DataStoreRegistry INSTANCE = new DataStoreRegistry();
+    static {
+        SystemListener.add(new SystemListener(Modules.STORAGE) {
+            @Override protected void classpathChanged() {
+                INSTANCE.reload();
+            }
+        });
+    }
+
     /**
      * The loader to use for searching for {@link DataStoreProvider} 
implementations.
      * Note that {@code ServiceLoader} are not thread-safe - usage of this 
field must
@@ -60,31 +69,17 @@ final class DataStoreRegistry {
      * provided that it can access at least the Apache SIS stores.
      */
     public DataStoreRegistry() {
-        this(Reflect.getContextClassLoader());
+        this.loader = ServiceLoader.load(DataStoreProvider.class, 
Reflect.getContextClassLoader());
     }
 
     /**
-     * Creates a new registry which will look for data stores accessible to 
the given class loader.
-     *
-     * @param  loader  the class loader to use for loading {@link 
DataStoreProvider} implementations.
+     * Creates the iterator over the data stores.
      */
-    public DataStoreRegistry(final ClassLoader loader) {
-        ArgumentChecks.ensureNonNull("loader", loader);
-        this.loader = ServiceLoader.load(DataStoreProvider.class, loader);
-    }
-
-    /**
-     * Returns the list of data store providers available at this method 
invocation time.
-     * More providers may be added later if new modules are added on the 
classpath.
-     *
-     * @return descriptions of available data stores.
-     *
-     * @since 0.8
-     */
-    public Set<DataStoreProvider> providers() {
+    @Override
+    protected Iterator<DataStoreProvider> createSourceIterator() {
         synchronized (loader) {
             final Iterator<DataStoreProvider> providers = loader.iterator();
-            return new LazySet<>(new Iterator<DataStoreProvider>() {
+            return new Iterator<DataStoreProvider>() {
                 @Override public boolean hasNext() {
                     synchronized (loader) {
                         return providers.hasNext();
@@ -96,7 +91,7 @@ final class DataStoreRegistry {
                         return providers.next();
                     }
                 }
-            });
+            };
         }
     }
 
@@ -317,4 +312,13 @@ search:     for (int ci=0; ci < categories.length; ci++) {
         }
         return selected;
     }
+
+    /**
+     * Notifies this registry that it should re-fetch the elements from the 
source.
+     */
+    @Override
+    public synchronized void reload() {
+        loader.reload();
+        super.reload();
+    }
 }
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
index 05718f99bc..c93587226f 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
@@ -18,8 +18,6 @@ package org.apache.sis.storage;
 
 import java.util.Collection;
 import org.apache.sis.util.Static;
-import org.apache.sis.internal.system.Modules;
-import org.apache.sis.internal.system.SystemListener;
 
 
 /**
@@ -29,33 +27,10 @@ import org.apache.sis.internal.system.SystemListener;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
+ * @version 1.4
  * @since   0.4
  */
 public final class DataStores extends Static {
-    /**
-     * The registry to use for searching for {@link DataStoreProvider} 
implementations.
-     *
-     * <h4>Class loader</h4>
-     * In current implementation, this registry is instantiated when first 
needed using the
-     * {@linkplain Thread#getContextClassLoader() context class loader}. This 
means that the set of
-     * available formats may depend on the first thread that invoked a {@code 
DataStores} method.
-     */
-    private static volatile DataStoreRegistry registry;
-
-    /*
-     * Forces a reload of all providers when the classpath changes. Note that 
invoking
-     * ServiceLoader.reload() is not sufficient because the ClassLoader may 
also change
-     * in OSGi context.
-     */
-    static {
-        SystemListener.add(new SystemListener(Modules.STORAGE) {
-            @Override protected void classpathChanged() {
-                registry = null;
-            }
-        });
-    }
-
     /**
      * Do not allow instantiation of this class.
      */
@@ -63,31 +38,16 @@ public final class DataStores extends Static {
     }
 
     /**
-     * Returns the registry, created when first needed.
-     */
-    private static DataStoreRegistry registry() {
-        DataStoreRegistry r = registry;
-        if (r == null) {
-            synchronized (DataStores.class) {
-                r = registry;
-                if (r == null) {
-                    registry = r = new DataStoreRegistry();
-                }
-            }
-        }
-        return r;
-    }
-
-    /**
-     * Returns the set of data store providers available at this method 
invocation time.
-     * More providers may be added later in a running JVM if new modules are 
added on the classpath.
+     * Returns the set of available data store providers.
+     * The returned collection is live: its content may change
+     * if new modules are added on the classpath at run-time.
      *
      * @return descriptions of available data stores.
      *
      * @since 0.8
      */
     public static Collection<DataStoreProvider> providers() {
-        return registry().providers();
+        return DataStoreRegistry.INSTANCE;
     }
 
     /**
@@ -98,7 +58,7 @@ public final class DataStores extends Static {
      * @throws DataStoreException if an error occurred while opening the 
storage.
      */
     public static String probeContentType(final Object storage) throws 
DataStoreException {
-        return registry().probeContentType(storage);
+        return DataStoreRegistry.INSTANCE.probeContentType(storage);
     }
 
     /**
@@ -121,6 +81,6 @@ public final class DataStores extends Static {
      * @throws DataStoreException if an error occurred while opening the 
storage.
      */
     public static DataStore open(final Object storage) throws 
UnsupportedStorageException, DataStoreException {
-        return registry().open(storage);
+        return DataStoreRegistry.INSTANCE.open(storage);
     }
 }
diff --git 
a/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoresTest.java 
b/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoresTest.java
index 237a0de900..cad22e13db 100644
--- 
a/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoresTest.java
+++ 
b/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoresTest.java
@@ -41,7 +41,7 @@ import static org.apache.sis.test.Assertions.assertSetEquals;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.1
+ * @version 1.4
  * @since   0.4
  */
 @DependsOn(StoreTest.class)
@@ -105,12 +105,12 @@ public final class DataStoresTest extends TestCase {
     private static List<Set<Class<?>>> collectProvidersConcurrently(final int 
nbWorkers, final ExecutorService executor)
             throws Exception
     {
-        final DataStoreRegistry dsr = new 
DataStoreRegistry(DataStoresTest.class.getClassLoader());
+        final DataStoreRegistry dsr = DataStoreRegistry.INSTANCE;
         final CyclicBarrier startSignal = new CyclicBarrier(nbWorkers);
         final Callable<Set<Class<?>>> collectProviderClasses = () -> {
             final Set<Class<?>> result = new HashSet<>();
             startSignal.await(10, TimeUnit.SECONDS);                        // 
Wait until all workers are ready.
-            for (DataStoreProvider p : dsr.providers()) {                   // 
This is the iteration to test.
+            for (DataStoreProvider p : dsr) {                               // 
This is the iteration to test.
                 result.add(p.getClass());
             }
             return result;

Reply via email to