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 a7ca5df1780f533c9ef6a60fbb6626371daa7232
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Oct 24 18:42:38 2025 +0200

    Move `MemoryFeatureSet` and `MemoryGridCoverage` to public API,
    after improvement in their API for consistency with each other.
---
 .../MultiResolutionCoverageLoaderTest.java         |  2 +-
 .../org/apache/sis/storage/landsat/BandGroup.java  |  7 +-
 .../apache/sis/storage/landsat/LandsatStore.java   |  2 +-
 .../sis/storage/landsat/MetadataReaderTest.java    |  2 +-
 .../apache/sis/storage/netcdf/base/TestCase.java   |  2 +-
 .../org/apache/sis/storage/AbstractResource.java   | 32 +++-----
 .../sis/storage/{base => }/MemoryFeatureSet.java   | 64 ++++++++++++----
 ...source.java => MemoryGridCoverageResource.java} | 87 +++++++++++-----------
 .../main/org/apache/sis/storage/Resource.java      | 22 ++++--
 .../storage/aggregate/AggregatedFeatureSet.java    | 12 ---
 .../sis/storage/aggregate/AggregatedResource.java  | 10 +++
 .../aggregate/BandAggregateGridResource.java       | 36 ++++-----
 .../storage/aggregate/ConcatenatedFeatureSet.java  |  2 +-
 .../aggregate/ConcatenatedGridCoverage.java        |  6 +-
 .../aggregate/ConcatenatedGridResource.java        | 12 +--
 .../sis/storage/aggregate/CoverageAggregator.java  | 16 +++-
 .../apache/sis/storage/base/PseudoResource.java    | 72 ++++++++++++++++++
 .../apache/sis/storage/base/TiledGridResource.java | 14 ----
 .../storage/image/WritableSingleImageStore.java    |  4 +-
 .../main/org/apache/sis/storage/package-info.java  |  8 +-
 .../org/apache/sis/storage/CoverageSubsetTest.java |  4 +-
 .../test/org/apache/sis/storage/DataStoreMock.java |  2 +-
 .../org/apache/sis/storage/FeatureQueryTest.java   |  1 -
 .../org/apache/sis/storage/GridResourceMock.java   | 12 +--
 ...st.java => MemoryGridCoverageResourceTest.java} | 21 +++---
 .../aggregate/BandAggregateGridResourceTest.java   | 11 +--
 .../aggregate/ConcatenatedFeatureSetTest.java      |  2 +-
 .../sis/storage/aggregate/CoverageMosaicTest.java  |  5 +-
 .../sis/storage/aggregate/JoinFeatureSetTest.java  |  2 +-
 .../sis/storage/aggregate/OpaqueGridResource.java  |  6 +-
 .../test/org/apache/sis/map/SEPortrayerTest.java   | 17 +----
 .../sis/map/service/GraphicsPortrayerTest.java     |  2 +-
 .../coveragejson/CoverageJsonStoreTest.java        |  4 +-
 .../org/apache/sis/gui/dataset/RootResource.java   | 16 ----
 34 files changed, 295 insertions(+), 222 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
 
b/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
index a29b181882..2cfa93f0a4 100644
--- 
a/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
+++ 
b/endorsed/src/org.apache.sis.portrayal/test/org/apache/sis/map/coverage/MultiResolutionCoverageLoaderTest.java
@@ -101,7 +101,7 @@ public final class MultiResolutionCoverageLoaderTest 
extends TestCase {
     private static final class DummyResource extends 
AbstractGridCoverageResource {
         /** Creates a dummy resource. */
         DummyResource() {
-            super(null, false);
+            super(null);
         }
 
         /** Returns the preferred resolutions in units of CRS axes. */
diff --git 
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/BandGroup.java
 
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/BandGroup.java
index 3e56317e93..9596970d84 100644
--- 
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/BandGroup.java
+++ 
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/BandGroup.java
@@ -31,7 +31,6 @@ import org.apache.sis.storage.Aggregate;
 import org.apache.sis.storage.AbstractResource;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStore;
-import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.storage.base.StoreResource;
 import org.apache.sis.storage.base.MetadataBuilder;
 import org.apache.sis.util.ArraysExt;
@@ -69,10 +68,10 @@ final class BandGroup extends AbstractResource implements 
Aggregate, StoreResour
      * Creates a new aggregate for the specified group.
      * This constructor will copy only the resources for that group from the 
given array.
      */
-    private BandGroup(final StoreListeners parent, final BandGroupName group,
+    private BandGroup(final Resource parent, final BandGroupName group,
                       final Band[] resources, final int count)
     {
-        super(parent, false);
+        super(parent);
         this.group = group;
         int n = 0;
         Band[] components = new Band[resources.length];
@@ -88,7 +87,7 @@ final class BandGroup extends AbstractResource implements 
Aggregate, StoreResour
     /**
      * Creates aggregates for the given bands.
      */
-    static BandGroup[] group(final StoreListeners parent, final Band[] 
resources, final int count) {
+    static BandGroup[] group(final Resource parent, final Band[] resources, 
final int count) {
         final BandGroupName[] groups = BandGroupName.values();
         final BandGroup[] aggregates = new BandGroup[groups.length];
         int n = 0;
diff --git 
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
 
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
index edd45d2353..aa82c8cea5 100644
--- 
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
+++ 
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
@@ -251,7 +251,7 @@ public class LandsatStore extends DataStore implements 
Aggregate {
         } catch (FactoryException e) {
             throw new DataStoreReferencingException(e.getMessage(), e);
         }
-        final BandGroup[] bands = BandGroup.group(listeners, resources, count);
+        final BandGroup[] bands = BandGroup.group(this, resources, count);
         for (final BandGroup c : bands) {
             c.identifier = factory.createLocalName(scope, c.group.name());
         }
diff --git 
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
 
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
index 31099f6d44..bc1b7c8544 100644
--- 
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
@@ -246,7 +246,7 @@ public final class MetadataReaderTest extends TestCase {
         final class DummyResource extends AbstractResource {
             /** Creates a dummy resource without parent. */
             DummyResource() {
-                super(null, false);
+                super(null);
             }
 
             /** Makes listeners accessible to this package. */
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
index c34b3efeeb..cf34b35b18 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
@@ -138,7 +138,7 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
         final class DummyResource extends AbstractResource {
             /** Creates a dummy resource without parent. */
             DummyResource() {
-                super(null, false);
+                super(null);
             }
 
             /** Makes listeners accessible to this package. */
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractResource.java
index 49c9497819..d64b18401f 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/AbstractResource.java
@@ -18,7 +18,6 @@ package org.apache.sis.storage;
 
 import java.util.Locale;
 import java.util.Optional;
-import org.opengis.util.GenericName;
 import org.opengis.metadata.Metadata;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.operation.TransformException;
@@ -31,6 +30,7 @@ import org.apache.sis.storage.event.StoreEvent;
 import org.apache.sis.storage.event.StoreListener;
 import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.storage.internal.Resources;
+import org.apache.sis.storage.base.PseudoResource;
 import org.apache.sis.storage.base.MetadataBuilder;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.Logging;
@@ -43,7 +43,7 @@ import org.apache.sis.xml.NilReason;
  * Subclasses should override the following methods:
  *
  * <ul>
- *   <li>{@link #getIdentifier()} (strongly recommended)</li>
+ *   <li>{@link #getIdentifier()} (recommended)</li>
  *   <li>{@link #getEnvelope()} (recommended)</li>
  *   <li>{@link #createMetadata()} (optional)</li>
  *   <li>{@link #getSynchronizationLock()} (optional)</li>
@@ -54,7 +54,7 @@ import org.apache.sis.xml.NilReason;
  * Synchronization, when needed, uses {@link #getSynchronizationLock()}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.4
+ * @version 1.6
  * @since   1.2
  */
 public abstract class AbstractResource implements Resource {
@@ -85,7 +85,14 @@ public abstract class AbstractResource implements Resource {
     @SuppressWarnings("this-escape")
     protected AbstractResource(final Resource parent) {
         StoreListeners parentListeners = null;
-        if (parent instanceof AbstractResource) {
+        if (parent instanceof PseudoResource) {     // Internal hack, may 
change in any future version.
+            final var r = (PseudoResource) parent;
+            parentListeners = r.listeners;
+            if (parentListeners != null && r.childrenAreHidden) {
+                listeners = parentListeners;
+                return;
+            }
+        } else if (parent instanceof AbstractResource) {
             parentListeners = ((AbstractResource) parent).listeners;
         } else if (parent instanceof DataStore) {
             parentListeners = ((DataStore) parent).listeners;
@@ -119,23 +126,6 @@ public abstract class AbstractResource implements Resource 
{
         }
     }
 
-    /**
-     * Returns the resource persistent identifier if available.
-     * The default implementation returns an empty value.
-     * Subclasses are strongly encouraged to override if they can provide a 
value.
-     *
-     * <h4>Relationship with metadata</h4>
-     * The default implementation of {@link #createMetadata()} uses this 
identifier for initializing
-     * the {@code metadata/identificationInfo/citation/title} property.
-     *
-     * @return a persistent identifier unique within the data store.
-     * @throws DataStoreException if an error occurred while fetching the 
identifier.
-     */
-    @Override
-    public Optional<GenericName> getIdentifier() throws DataStoreException {
-        return Optional.empty();
-    }
-
     /**
      * Returns the spatiotemporal envelope of this resource. This information 
is part of API only in some kinds
      * of resource such as {@link FeatureSet}. But the method is provided in 
this base class for convenience.
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MemoryFeatureSet.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/MemoryFeatureSet.java
similarity index 58%
rename from 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MemoryFeatureSet.java
rename to 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/MemoryFeatureSet.java
index 8b25894a1b..a2d8297510 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MemoryFeatureSet.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/MemoryFeatureSet.java
@@ -14,14 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage.base;
+package org.apache.sis.storage;
 
 import java.util.Objects;
 import java.util.Collection;
 import java.util.OptionalLong;
 import java.util.stream.Stream;
-import org.apache.sis.storage.Resource;
-import org.apache.sis.storage.AbstractFeatureSet;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
 import org.opengis.feature.Feature;
@@ -29,36 +27,48 @@ import org.opengis.feature.FeatureType;
 
 
 /**
- * Set of features stored in memory. Features are specified at construction 
time.
- * Metadata can be specified by overriding {@link #createMetadata()}.
+ * Set of feature instances stored in memory.
+ * Features are specified at construction time.
+ * Metadata can be specified by overriding the {@link #createMetadata()} 
method.
+ *
+ * <h2>When to use</h2>
+ * This class is useful for small sets of features, or for testing purposes,
+ * or when the features are in memory anyway (for example, a computation 
result).
+ * It should generally not be used for large data sets read from files or 
databases.
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
+ *
+ * @since 1.6
  */
 public class MemoryFeatureSet extends AbstractFeatureSet {
     /**
-     * The type specified at construction time and returned by {@link 
#getType()}.
+     * The type specified at construction time.
+     *
+     * @see #getType()
      */
-    private final FeatureType type;
+    protected final FeatureType type;
 
     /**
      * The features specified at construction time, potentially as a 
modifiable collection.
      * For all features in this collection, {@link Feature#getType()} shall be 
{@link #type}.
+     *
+     * @see #features(boolean)
      */
-    private final Collection<Feature> features;
+    protected final Collection<Feature> features;
 
     /**
      * Creates a new set of features stored in memory. It is caller 
responsibility to ensure that
      * <code>{@linkplain Feature#getType()} == type</code> for all elements in 
the given collection
-     * (this is not verified).
+     * (this is not verified by this constructor).
      *
-     * @param parent     the parent resource, or {@code null} if none.
-     * @param type       the type of all features in the given collection.
-     * @param features   collection of stored features. This collection will 
not be copied.
+     * @param parent    the parent resource, or {@code null} if none.
+     * @param type      the type of all features in the given collection.
+     * @param features  collection of stored features. This collection will 
not be copied.
      */
     public MemoryFeatureSet(final Resource parent, final FeatureType type, 
final Collection<Feature> features) {
         super(parent);
-        this.type     = Objects.requireNonNull(type);
+        this.type = Objects.requireNonNull(type);
         this.features = Objects.requireNonNull(features);
     }
 
@@ -92,4 +102,32 @@ public class MemoryFeatureSet extends AbstractFeatureSet {
     public Stream<Feature> features(final boolean parallel) {
         return parallel ? features.parallelStream() : features.stream();
     }
+
+    /**
+     * Tests whether this memory feature set is wrapping the same feature 
instances as the given object.
+     * This method checks also that the listeners are equal.
+     *
+     * @param  obj  the object to compare.
+     * @return whether the two objects are memory resources wrapping the same 
features.
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj != null && obj.getClass() == getClass()) {
+            final var other = (MemoryFeatureSet) obj;
+            return type.equals(other.type) &&
+                   features.equals(other.features) &&
+                   listeners.equals(other.listeners);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for consistency with {@code equals(Object)}.
+     *
+     * @return a hash code value.
+     */
+    @Override
+    public int hashCode() {
+        return type.hashCode() + 31 * features.hashCode() + 37 * 
listeners.hashCode();
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MemoryGridResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/MemoryGridCoverageResource.java
similarity index 79%
rename from 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MemoryGridResource.java
rename to 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/MemoryGridCoverageResource.java
index dc4e70c0f2..3d0ed813a4 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MemoryGridResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/MemoryGridCoverageResource.java
@@ -14,14 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage.base;
+package org.apache.sis.storage;
 
 import java.util.List;
 import java.util.Arrays;
 import java.util.Objects;
-import java.util.Optional;
 import java.awt.image.RenderedImage;
-import org.opengis.util.GenericName;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridCoverageBuilder;
@@ -30,36 +28,41 @@ import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridRoundingMode;
 import org.apache.sis.coverage.grid.PixelInCell;
-import org.apache.sis.storage.AbstractGridCoverageResource;
-import org.apache.sis.storage.RasterLoadingStrategy;
-import org.apache.sis.storage.event.StoreListeners;
-import static org.apache.sis.storage.base.TiledGridCoverage.BIDIMENSIONAL;
 
 
 /**
- * A {@link org.apache.sis.storage.GridCoverageResource} in memory.
+ * A Grid Coverage Resource stored in memory.
  * This resource wraps an arbitrary {@link GridCoverage} specified at 
construction time.
- * Metadata can be specified by overriding {@link #createMetadata()}.
+ * Metadata can be specified by overriding the {@link #createMetadata()} 
method.
+ *
+ * <h2>When to use</h2>
+ * This class is useful for small grid coverages, or for testing purposes,
+ * or when the coverage is in memory anyway (for example, a computation 
result).
+ * It should generally not be used for large coverages read from files or 
databases.
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
+ *
+ * @since 1.6
  */
-public class MemoryGridResource extends AbstractGridCoverageResource {
+public class MemoryGridCoverageResource extends AbstractGridCoverageResource {
     /**
-     * The grid coverage specified at construction time.
+     * A constant for identifying code that relying on having 2 dimensions.
      */
-    public final GridCoverage coverage;
+    private static final int BIDIMENSIONAL = 2;
 
     /**
-     * The grid coverage processor to use for selecting bands.
-     * It may be configured with a colorizer for determining the color models.
+     * The grid coverage specified at construction time.
+     *
+     * @see #getGridCoverage()
      */
-    private final GridCoverageProcessor processor;
+    protected final GridCoverage coverage;
 
     /**
-     * The resource identifier, or {@code null} if none.
+     * The grid coverage processor to use for selecting bands.
+     * It may be configured with a colorizer for determining the color models.
      */
-    private final GenericName identifer;
+    protected final GridCoverageProcessor processor;
 
     /**
      * Whether to defer the calls to {@link GridCoverage#render(GridExtent)}.
@@ -71,26 +74,28 @@ public class MemoryGridResource extends 
AbstractGridCoverageResource {
     /**
      * Creates a new coverage stored in memory.
      *
-     * @param  parent      listeners of the parent resource, or {@code null} 
if none.
-     * @param  identifier  resource identifier, or {@code null} if none.
-     * @param  coverage    stored coverage retained as-is (not copied). Cannot 
be null.
-     * @param  processor   the grid coverage processor for selecting bands, or 
{@code null} for default.
+     * @param parent     the parent resource, or {@code null} if none.
+     * @param coverage   stored coverage retained as-is (not copied). Cannot 
be null.
+     * @param processor  the grid coverage processor for selecting bands, or 
{@code null} for default.
      */
-    public MemoryGridResource(final StoreListeners parent, final GenericName 
identifier,
-                              final GridCoverage coverage, final 
GridCoverageProcessor processor)
-    {
-        super(parent, false);
-        this.identifer = identifier;
+    public MemoryGridCoverageResource(final Resource parent, final 
GridCoverage coverage, final GridCoverageProcessor processor) {
+        super(parent);
         this.coverage  = Objects.requireNonNull(coverage);
         this.processor = (processor != null) ? processor : new 
GridCoverageProcessor();
     }
 
     /**
-     * Returns the resource identifier specified at construction time, if any.
+     * Returns the grid coverage wrapped by this resource.
+     * The grid coverage returned by this method shall be the same or 
equivalent
+     * to the coverage that would be returned by a call to {@code read(null)},
+     * and should not be expansive to get.
+     *
+     * @return the grid coverage wrapped by this resource.
+     *
+     * @see #read(GridGeometry, int...)
      */
-    @Override
-    public Optional<GenericName> getIdentifier() {
-        return Optional.ofNullable(identifer);
+    public GridCoverage getGridCoverage() {
+        return coverage;
     }
 
     /**
@@ -132,10 +137,10 @@ public class MemoryGridResource extends 
AbstractGridCoverageResource {
     }
 
     /**
-     * Returns a subset of the wrapped grid coverage. If a non-null grid 
geometry is specified, then
-     * this method tries to return a grid coverage matching the given grid 
geometry on a best-effort basis.
-     * In the current implementation, this is either a {@link 
org.apache.sis.coverage.grid.GridCoverage2D}
-     * or the original grid coverage.
+     * Returns a subset of the wrapped grid coverage. If a null grid geometry 
and a null or empty range is specified,
+     * then this method shall return the same grid coverage as {@link 
#getGridCoverage()} or an equivalent coverage.
+     * If a non-null grid geometry is specified, then this method tries to 
return a grid coverage matching the given
+     * grid geometry on a best-effort basis. It may be the whole coverage.
      *
      * @param  domain  desired grid extent and resolution, or {@code null} for 
the whole domain.
      * @param  ranges  0-based indices of sample dimensions to read, or {@code 
null} or an empty sequence for reading them all.
@@ -228,8 +233,8 @@ public class MemoryGridResource extends 
AbstractGridCoverageResource {
     }
 
     /**
-     * Tests whether this memory grid resource is wrapping the same coverage 
than the given object.
-     * This method requires also the listeners and processor to be the equal.
+     * Tests whether this memory grid coverage resource is wrapping the same 
coverage as the given object.
+     * This method checks also that the listeners and the grid coverage 
processor are equal.
      *
      * @param  obj  the object to compare.
      * @return whether the two objects are memory resources wrapping the same 
coverage.
@@ -237,9 +242,8 @@ public class MemoryGridResource extends 
AbstractGridCoverageResource {
     @Override
     public boolean equals(final Object obj) {
         if (obj != null && obj.getClass() == getClass()) {
-            final var other = (MemoryGridResource) obj;
-            return Objects.equals(identifer, other.identifer) &&
-                   coverage.equals(other.coverage)   &&
+            final var other = (MemoryGridCoverageResource) obj;
+            return coverage.equals(other.coverage)   &&
                    processor.equals(other.processor) &&
                    listeners.equals(other.listeners);
         }
@@ -253,10 +257,7 @@ public class MemoryGridResource extends 
AbstractGridCoverageResource {
      */
     @Override
     public int hashCode() {
-        return coverage.hashCode()
-                + 17 * Objects.hashCode(identifer)
-                + 31 * processor.hashCode()
-                + 37 * listeners.hashCode();
+        return coverage.hashCode() + 31 * processor.hashCode() + 37 * 
listeners.hashCode();
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/Resource.java 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/Resource.java
index 61022718dc..34f16f3acc 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/Resource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/Resource.java
@@ -54,7 +54,7 @@ import org.apache.sis.storage.event.StoreListener;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.6
  *
  * @see Aggregate#components()
  *
@@ -84,7 +84,9 @@ public interface Resource {
      *
      * @since 1.0
      */
-    Optional<GenericName> getIdentifier() throws DataStoreException;
+    default Optional<GenericName> getIdentifier() throws DataStoreException {
+        return Optional.empty();
+    }
 
     /**
      * Returns information about this resource.
@@ -140,7 +142,7 @@ public interface Resource {
      * If the caller wants to modify some metadata elements, it may be 
necessary to perform a
      * {@linkplain 
org.apache.sis.metadata.iso.DefaultMetadata#deepCopy(Metadata) deep copy} first.
      *
-     * @return information about this resource. Should not be {@code null}.
+     * @return information about this resource. Should not be {@code null}, 
but this is not strictly forbidden.
      * @throws DataStoreException if an error occurred while reading the 
metadata.
      *
      * @see DataStore#getMetadata()
@@ -364,11 +366,16 @@ public interface Resource {
      * This side-effect is applied on the assumption that the registered 
listener will handle
      * warnings in its own way, for example by showing warnings in a widget.
      *
+     * <h4>Default implementation</h4>
+     * The default implementation does nothing.
+     * This is okay for resources that do not emit any event.
+     *
      * @param  <T>        compile-time value of the {@code eventType} argument.
      * @param  listener   listener to notify about events.
      * @param  eventType  type of {@link StoreEvent}s to listen (cannot be 
{@code null}).
      */
-    <T extends StoreEvent> void addListener(Class<T> eventType, 
StoreListener<? super T> listener);
+    default <T extends StoreEvent> void addListener(Class<T> eventType, 
StoreListener<? super T> listener) {
+    }
 
     /**
      * Unregisters a listener previously added to this resource for the given 
type of events.
@@ -386,9 +393,14 @@ public interface Resource {
      * and if, after this method invocation, there are no remaining listeners 
for warning events,
      * then this {@code Resource} will send future warnings to the loggers.
      *
+     * <h4>Default implementation</h4>
+     * The default implementation does nothing.
+     * This is okay for resources that do not emit any event.
+     *
      * @param  <T>        compile-time value of the {@code eventType} argument.
      * @param  listener   listener to stop notifying about events.
      * @param  eventType  type of {@link StoreEvent}s which were listened 
(cannot be {@code null}).
      */
-    <T extends StoreEvent> void removeListener(Class<T> eventType, 
StoreListener<? super T> listener);
+    default <T extends StoreEvent> void removeListener(Class<T> eventType, 
StoreListener<? super T> listener) {
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedFeatureSet.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedFeatureSet.java
index 63b180e995..6a7e1f17b2 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedFeatureSet.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedFeatureSet.java
@@ -30,7 +30,6 @@ import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.AbstractFeatureSet;
-import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.storage.base.MetadataBuilder;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
@@ -70,17 +69,6 @@ abstract class AggregatedFeatureSet extends 
AbstractFeatureSet {
         super(parent);
     }
 
-    /**
-     * Creates a new aggregated feature set.
-     *
-     * @param  parent  listeners of the parent resource, or {@code null} if 
none.
-     *         This is usually the listeners of the {@link 
org.apache.sis.storage.DataStore}
-     *         that created this resource.
-     */
-    protected AggregatedFeatureSet(final StoreListeners parent) {
-        super(parent, false);
-    }
-
     /**
      * Returns all feature set used by this aggregation. This method is 
invoked for implementation of
      * {@link #getEnvelope()} and {@link #createMetadata(MetadataBuilder)}.
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedResource.java
index 4930ea9f4f..b037d547a7 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedResource.java
@@ -28,6 +28,7 @@ import org.apache.sis.storage.AbstractResource;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.storage.base.MetadataBuilder;
+import org.apache.sis.storage.base.PseudoResource;
 import org.apache.sis.geometry.Envelopes;
 import org.apache.sis.geometry.ImmutableEnvelope;
 import org.apache.sis.util.internal.shared.Strings;
@@ -73,6 +74,15 @@ abstract class AggregatedResource extends AbstractResource {
      */
     private boolean envelopeIsEvaluated;
 
+    /**
+     * Creates a new concatenated resource as the child of the given resource.
+     *
+     * @param  parent  the parent resource, or {@code null} if none.
+     */
+    AggregatedResource(final PseudoResource parent) {
+        super(parent);
+    }
+
     /**
      * Creates a new concatenated resource.
      *
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
index ad3fd98827..40d122fdf3 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
@@ -30,9 +30,9 @@ import org.apache.sis.storage.GridCoverageResource;
 import org.apache.sis.storage.AbstractGridCoverageResource;
 import org.apache.sis.storage.RasterLoadingStrategy;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 import org.apache.sis.storage.base.MetadataBuilder;
-import org.apache.sis.storage.base.MemoryGridResource;
-import org.apache.sis.storage.event.StoreListeners;
+import org.apache.sis.storage.base.PseudoResource;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.internal.shared.UnmodifiableArrayList;
@@ -109,18 +109,18 @@ final class BandAggregateGridResource extends 
AggregatedResource implements Grid
      * The {@linkplain #getSampleDimensions() list of sample dimensions} of 
the aggregated resource
      * will be the concatenation of the lists of all sources, or a subset of 
this concatenation.
      *
-     * @param  parentListeners  listeners of the parent resource, or {@code 
null} if none.
-     * @param  aggregate        sources to aggregate together with the bands 
to select for each source.
-     * @param  processor        the processor to use for creating grid 
coverages.
+     * @param  parent     the parent resource, or {@code null} if none.
+     * @param  aggregate  sources to aggregate together with the bands to 
select for each source.
+     * @param  processor  the processor to use for creating grid coverages.
      * @throws BackingStoreException if an error occurred while fetching the 
grid geometry or sample dimensions from a resource.
      * @throws IllegalGridGeometryException if a grid geometry is not 
compatible with the others.
      * @throws IllegalArgumentException if some band indices are duplicated or 
outside their range of validity.
      */
-    private BandAggregateGridResource(final StoreListeners parentListeners,
+    private BandAggregateGridResource(final PseudoResource parent,
                                       final 
BandAggregateArgument<GridCoverageResource> aggregate,
                                       final GridCoverageProcessor processor)
     {
-        super(null, parentListeners, false);
+        super(parent);
         this.sources          = aggregate.sources();
         this.gridGeometry     = 
aggregate.domain(BandAggregateGridResource::domain);
         this.sampleDimensions = List.copyOf(aggregate.ranges());
@@ -149,16 +149,16 @@ final class BandAggregateGridResource extends 
AggregatedResource implements Grid
      * The intersection of the domain of all resources shall be non-empty,
      * and all resources shall use the same data type in their rendered image.
      *
-     * @param  parentListeners  listeners of the parent resource, or {@code 
null} if none.
-     * @param  sources          resources whose bands shall be aggregated, in 
order. At least one resource must be provided.
-     * @param  bandsPerSource   sample dimensions for each source. May be 
{@code null} or may contain {@code null} elements.
-     * @param  processor        the processor to use for creating grid 
coverages.
+     * @param  parent          the parent resource, or {@code null} if none.
+     * @param  sources         resources whose bands shall be aggregated, in 
order. At least one resource must be provided.
+     * @param  bandsPerSource  sample dimensions for each source. May be 
{@code null} or may contain {@code null} elements.
+     * @param  processor       the processor to use for creating grid 
coverages.
      * @return the band aggregated grid resource.
      * @throws DataStoreException if an error occurred while fetching the grid 
geometry or sample dimensions from a resource.
      * @throws IllegalGridGeometryException if a grid geometry is not 
compatible with the others.
      * @throws IllegalArgumentException if some band indices are duplicated or 
outside their range of validity.
      */
-    static GridCoverageResource create(final StoreListeners parentListeners,
+    static GridCoverageResource create(final PseudoResource parent,
             GridCoverageResource[] sources, int[][] bandsPerSource,
             final GridCoverageProcessor processor) throws DataStoreException
     {
@@ -168,14 +168,14 @@ final class BandAggregateGridResource extends 
AggregatedResource implements Grid
         for (int i=0; i<sources.length; i++) {
             final GridCoverageResource source = sources[i];
             ArgumentChecks.ensureNonNullElement("sources", i, source);
-            if (source instanceof MemoryGridResource) {
+            if (source instanceof MemoryGridCoverageResource) {
                 if (count == 0) {
                     sources = sources.clone();              // Clone when 
first needed.
                     bandsPerSource = (bandsPerSource != null) ? 
bandsPerSource.clone() : new int[sources.length][];
                 }
                 final int[] bands    = bandsPerSource[i];
                 final int numBands   = (bands != null) ? bands.length : 
source.getSampleDimensions().size();
-                coverages[count]     = ((MemoryGridResource) source).coverage;
+                coverages[count]     = ((MemoryGridCoverageResource) 
source).getGridCoverage();
                 coverageBands[count] = bands;
                 bandsPerSource[i]    = ArraysExt.range(firstBand, firstBand + 
numBands);
                 sources[i]           = null;        // To be replaced by the 
aggregated coverage.
@@ -184,13 +184,13 @@ final class BandAggregateGridResource extends 
AggregatedResource implements Grid
             }
         }
         /*
-         * If at least one `MemoryGridResource` has been found, apply the 
aggregation directly
-         * on the grid coverage, then build a single `MemoryGridResource` with 
the result.
+         * If at least one `MemoryGridCoverageResource` has been found, apply 
the aggregation directly
+         * on the grid coverage, then build a single 
`MemoryGridCoverageResource` with the result.
          */
         if (count != 0) {
             coverages     = ArraysExt.resize(coverages,     count);
             coverageBands = ArraysExt.resize(coverageBands, count);
-            var aggregate = new MemoryGridResource(parentListeners, null, 
processor.aggregateRanges(coverages, coverageBands), processor);
+            var aggregate = new MemoryGridCoverageResource(parent, 
processor.aggregateRanges(coverages, coverageBands), processor);
             for (int i=0; i<sources.length; i++) {
                 if (sources[i] == null) {
                     sources[i] = aggregate;
@@ -209,7 +209,7 @@ final class BandAggregateGridResource extends 
AggregatedResource implements Grid
             if (aggregate.isIdentity()) {
                 return aggregate.sources()[0];
             }
-            return new BandAggregateGridResource(parentListeners, aggregate, 
processor);
+            return new BandAggregateGridResource(parent, aggregate, processor);
         } catch (BackingStoreException e) {
             throw e.unwrapOrRethrow(DataStoreException.class);
         }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedFeatureSet.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedFeatureSet.java
index dbafaf4e76..78a9582e76 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedFeatureSet.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedFeatureSet.java
@@ -76,7 +76,7 @@ public class ConcatenatedFeatureSet extends 
AggregatedFeatureSet {
      * but different sources. This is used for creating {@linkplain 
#subset(Query) subsets}.
      */
     private ConcatenatedFeatureSet(final FeatureSet[] sources, final 
ConcatenatedFeatureSet original) {
-        super(original.listeners);
+        super(original);
         this.sources = UnmodifiableArrayList.wrap(sources);
         commonType = original.commonType;
     }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridCoverage.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridCoverage.java
index 9649c38087..743bbf6863 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridCoverage.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridCoverage.java
@@ -28,9 +28,9 @@ import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.DisjointExtentException;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.internal.Resources;
-import org.apache.sis.storage.base.MemoryGridResource;
 import org.apache.sis.util.collection.Cache;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.internal.shared.Numerics;
@@ -135,8 +135,8 @@ final class ConcatenatedGridCoverage extends GridCoverage {
         if (opposite == null) {
             List<SampleDimension> sampleDimensions = null;
             for (final GridSlice slice : locator.slices) {
-                if (slice.resource instanceof MemoryGridResource) {
-                    GridCoverage coverage = ((MemoryGridResource) 
slice.resource).coverage;
+                if (slice.resource instanceof MemoryGridCoverageResource) {
+                    GridCoverage coverage = ((MemoryGridCoverageResource) 
slice.resource).getGridCoverage();
                     coverage = coverage.forConvertedValues(converted);
                     sampleDimensions = coverage.getSampleDimensions();
                     break;
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java
index 760d194e16..b7e01be507 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/ConcatenatedGridResource.java
@@ -34,9 +34,9 @@ import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreReferencingException;
 import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 import org.apache.sis.storage.RasterLoadingStrategy;
 import org.apache.sis.storage.event.StoreListeners;
-import org.apache.sis.storage.base.MemoryGridResource;
 import org.apache.sis.storage.base.MetadataBuilder;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.ComparisonMode;
@@ -72,7 +72,7 @@ final class ConcatenatedGridResource extends 
AggregatedResource implements GridC
      * <p>Whether a bit is set or not depends on three factors:</p>
      * <ul>
      *   <li>Whether deferred loading has been requested by a call to {@link 
#setLoadingStrategy(RasterLoadingStrategy)}.</li>
-     *   <li>Whether the resource is a {@link MemoryGridResource} instance, in 
which case it is not useful to delay.</li>
+     *   <li>Whether the resource is a {@link MemoryGridCoverageResource} 
instance, in which case it is not useful to delay.</li>
      *   <li>Whether the slice at the corresponding index can handle deferred 
loading itself.
      *       In such case, we let the resource manages its own lazy 
loading.</li>
      * </ul>
@@ -335,12 +335,12 @@ final class ConcatenatedGridResource extends 
AggregatedResource implements GridC
 
     /**
      * Returns whether the given slice should be ignored in the determination 
of a loading strategy.
-     * {@link MemoryGridResource} instances are ignored because they usually 
behave like "at get tile time",
+     * {@link MemoryGridCoverageResource} instances are ignored because they 
usually behave like "at get tile time",
      * even if their {@code setLoadingStrategy(…)} method rejects the value 
(because it cannot be guaranteed).
      * We also don't flag those instances as deferred for the same reason.
      */
     private static boolean ignore(final GridCoverageResource slice) {
-        return slice instanceof MemoryGridResource;
+        return slice instanceof MemoryGridCoverageResource;
     }
 
     /**
@@ -473,7 +473,7 @@ final class ConcatenatedGridResource extends 
AggregatedResource implements GridC
          * For all coverages that have been read immediately, wrap them in a 
memory resource.
          * This look cannot be inlined inside above loop because we need to 
know the adjusted domain.
          * This loop has some tolerance regarding coverages with a resolution 
different than expected.
-         * This is okay if `MemoryGridResource` applies the missing 
subsampling in its `read(…)` method.
+         * This is okay if `MemoryGridCoverageResource` applies the missing 
subsampling in its `read(…)` method.
          */
         if (coverages != null) try {
             for (int i=0; i < selected.length; i++) {
@@ -481,7 +481,7 @@ final class ConcatenatedGridResource extends 
AggregatedResource implements GridC
                 if (coverage != null) {
                     GridGeometry geometry = coverage.getGridGeometry();
                     GridExtent inGroup = domain.extentOf(geometry, 
GridSlice.CELL_ANCHOR, GridRoundingMode.NEAREST);
-                    var resource = new MemoryGridResource(listeners, null, 
coverage, processor);
+                    var resource = new MemoryGridCoverageResource(this, 
coverage, processor);
                     selected[i] = selected[i].resolve(resource, 
geometry.getExtent(), inGroup);
                 }
             }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java
index 5de1f71862..92c3203e0a 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/CoverageAggregator.java
@@ -44,7 +44,8 @@ import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.storage.GridCoverageResource;
-import org.apache.sis.storage.base.MemoryGridResource;
+import org.apache.sis.storage.MemoryGridCoverageResource;
+import org.apache.sis.storage.base.PseudoResource;
 import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.SubspaceNotSpecifiedException;
@@ -188,6 +189,13 @@ public final class CoverageAggregator extends 
Group<GroupBySample> {
         return (listeners != null) ? listeners.getSourceName() : null;
     }
 
+    /**
+     * Returns this aggregator as a pseudo-resource, used only for passing the 
listeners.
+     */
+    private PseudoResource asPseudoResource() {
+        return new PseudoResource(listeners, false);
+    }
+
     /**
      * Adds the given coverage. This method can be invoked from any thread.
      *
@@ -197,10 +205,10 @@ public final class CoverageAggregator extends 
Group<GroupBySample> {
      */
     public void add(final GridCoverage coverage) {
         try {
-            add(new MemoryGridResource(listeners, null, coverage, processor));
+            add(new MemoryGridCoverageResource(asPseudoResource(), coverage, 
processor));
         } catch (DataStoreException e) {
             /*
-             * `DataStoreException` are never thrown by `MemoryGridResource`.
+             * `DataStoreException` are never thrown by 
`MemoryGridCoverageResource`.
              * The only case where we could get that exception with default
              * `add(GridCoverageResource)` is with non-invertible transform.
              */
@@ -520,7 +528,7 @@ search: synchronized (members) {
      */
     public void addRangeAggregate(final GridCoverageResource[] sources, final 
int[][] bandsPerSource) throws DataStoreException {
         if (sources.length != 0) {
-            add(BandAggregateGridResource.create(listeners, sources, 
bandsPerSource, processor));
+            add(BandAggregateGridResource.create(asPseudoResource(), sources, 
bandsPerSource, processor));
         }
     }
 
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PseudoResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PseudoResource.java
new file mode 100644
index 0000000000..9d14b40547
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PseudoResource.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.base;
+
+import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.AbstractResource;
+import org.apache.sis.storage.event.StoreListeners;
+import org.opengis.metadata.Metadata;
+
+
+/**
+ * A pseudo-resource used as a way to specify listeners to the {@link 
AbstractResource} constructor.
+ * Instances of this class are short-lived: no reference should be stored.
+ * This pseudo-resource should never be visible to users.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+public final class PseudoResource implements Resource {
+    /**
+     * The listeners that {@link AbstractResource} should take. May be {@code 
null}.
+     */
+    public final StoreListeners listeners;
+
+    /**
+     * Whether the children of this pseudo-resource should be hidden.
+     * If {@code false} (the recommended value), then the children will have 
their own set of listeners
+     * and each child will be the {@linkplain StoreListeners#getSource() 
source of their own events}.
+     * It will be possible to add and remove listeners independently from the 
set of parent listeners.
+     * Conversely if {@code true}, then the {@linkplain #listeners} will be 
used directly and the
+     * children resource will not appear as the source of any event.
+     *
+     * <p>In any cases, the listeners of all parents (ultimately the data 
store that created the resource)
+     * will always be notified, either directly if {@code childrenAreHidden} 
is {@code true} or indirectly
+     * if {@code childrenAreHidden} is {@code false}.</p>
+     */
+    public final boolean childrenAreHidden;
+
+    /**
+     * Creates a new instance wrapping the given resources.
+     *
+     * @param  listeners          the listeners that {@link AbstractResource} 
should take, or {@code null}.
+     * @param  childrenAreHidden  whether the children of this pseudo-resource 
should be hidden.
+     */
+    public PseudoResource(final StoreListeners listeners, final boolean 
childrenAreHidden) {
+        this.listeners = listeners;
+        this.childrenAreHidden = childrenAreHidden;
+    }
+
+    /**
+     * Ignored.
+     *
+     * @return {@code null}.
+     */
+    @Override
+    public Metadata getMetadata() {
+        return null;
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
index 145daf7ae5..d2442b62cc 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/TiledGridResource.java
@@ -45,7 +45,6 @@ import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.AbstractGridCoverageResource;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.RasterLoadingStrategy;
-import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.internal.shared.Numerics;
@@ -158,19 +157,6 @@ public abstract class TiledGridResource extends 
AbstractGridCoverageResource {
         super(parent);
     }
 
-    /**
-     * Creates a new resource.
-     *
-     * @param  parent  listeners of the parent resource, or {@code null} if 
none.
-     *         This is usually the listeners of the {@link 
org.apache.sis.storage.DataStore}
-     *         that created this resource.
-     * @param  hidden  {@code false} if this resource shall use its own {@link 
StoreListeners}
-     *         with the specified parent, or {@code true} for using {@code 
parentListeners} directly.
-     */
-    protected TiledGridResource(final StoreListeners parent, final boolean 
hidden) {
-        super(parent, hidden);
-    }
-
     /**
      * Returns the size of tiles in this resource.
      * The length of the returned array is the number of dimensions,
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableSingleImageStore.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableSingleImageStore.java
index 3c00dfd441..fa05ffb012 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableSingleImageStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WritableSingleImageStore.java
@@ -25,11 +25,11 @@ import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 import org.apache.sis.storage.RasterLoadingStrategy;
 import org.apache.sis.storage.UnsupportedQueryException;
 import org.apache.sis.storage.WritableGridCoverageResource;
 import org.apache.sis.storage.Query;
-import org.apache.sis.storage.base.MemoryGridResource;
 
 
 /**
@@ -168,7 +168,7 @@ final class WritableSingleImageStore extends WritableStore 
implements WritableGr
     public void write(final GridCoverage coverage, final Option... options) 
throws DataStoreException {
         try {
             if (isMultiImages() == 0) {
-                add(new MemoryGridResource(listeners, null, coverage, null));
+                add(new MemoryGridCoverageResource(this, coverage, null));
             } else {
                 delegate().write(coverage, options);
             }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/package-info.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/package-info.java
index acb177d843..4a846c5c9d 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/package-info.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/package-info.java
@@ -16,13 +16,11 @@
  */
 
 /**
- * {@linkplain org.apache.sis.storage.DataStore Data store} base types for 
retrieving and saving geospatial data
- * in various storage formats.
- *
- * <p>{@code DataStore} provides the methods for reading or writing geospatial 
data in a given storage.
+ * Data store base types for retrieving and saving geospatial data in various 
storage formats.
+ * {@link org.apache.sis.storage.DataStore} provides the methods for reading 
or writing geospatial data in a given storage.
  * A storage may be a file, a directory, a connection to a database or any 
other implementation specific mechanism.
  * Suitable {@code DataStore} implementation for a given storage can be 
discovered and opened by the static methods
- * provided in {@link org.apache.sis.storage.DataStores}.</p>
+ * provided in {@link org.apache.sis.storage.DataStores}.
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/CoverageSubsetTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/CoverageSubsetTest.java
index 833577cd04..2d1fad781c 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/CoverageSubsetTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/CoverageSubsetTest.java
@@ -28,7 +28,6 @@ import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridOrientation;
 import org.apache.sis.geometry.ImmutableEnvelope;
-import org.apache.sis.storage.base.MemoryGridResource;
 import org.apache.sis.measure.Units;
 
 // Test dependencies
@@ -46,6 +45,7 @@ import static 
org.apache.sis.referencing.Assertions.assertEquivalent;
  * @author  Alexis Manin (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 public final class CoverageSubsetTest extends TestCase {
     /**
      * Size (in pixels) of the image to build for testing purpose.
@@ -70,7 +70,7 @@ public final class CoverageSubsetTest extends TestCase {
         final var domain = new GridGeometry(extent, region, 
GridOrientation.HOMOTHETY);
         final var band   = new 
SampleDimension.Builder().addQuantitative("101-based row-major order pixel 
number", 101, 105, 1, 0, Units.UNITY).build();
         final var buffer = new DataBufferInt(values(), WIDTH * HEIGHT);
-        return new MemoryGridResource(null, null, new 
BufferedGridCoverage(domain, List.of(band), buffer), null);
+        return new MemoryGridCoverageResource(null, new 
BufferedGridCoverage(domain, List.of(band), buffer), null);
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreMock.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreMock.java
index 90d6ee2975..86c581c180 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreMock.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreMock.java
@@ -100,7 +100,7 @@ public final class DataStoreMock extends DataStore {
      * @return a dummy child.
      */
     public Resource newChild() {
-        return new AbstractResource(listeners, false) {
+        return new AbstractResource(this) {
         };
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
index ac13d60d71..4642c8380d 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
@@ -24,7 +24,6 @@ import org.apache.sis.feature.Features;
 import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.feature.builder.AttributeRole;
 import org.apache.sis.feature.internal.shared.AttributeConvention;
-import org.apache.sis.storage.base.MemoryFeatureSet;
 import org.apache.sis.filter.DefaultFilterFactory;
 import org.apache.sis.util.iso.Names;
 
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/GridResourceMock.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/GridResourceMock.java
index 306bcea036..7e33359497 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/GridResourceMock.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/GridResourceMock.java
@@ -23,6 +23,7 @@ import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridCoverage2D;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 
 // Test dependencies
 import static org.junit.jupiter.api.Assertions.*;
@@ -30,11 +31,10 @@ import static org.junit.jupiter.api.Assertions.*;
 
 /**
  * A resource for one-banded images generated on-the-fly when {@link 
#read(GridGeometry, int...)} is invoked.
- * This class has some similarities with {@link 
org.apache.sis.storage.base.MemoryGridResource} except that
- * the {@link GridCoverage} returned by {@link #read read(…)} is guaranteed to 
wrap an image having exactly the
- * requested size (i.e. the size specified by {@link 
GridGeometry#getExtent()}).
- * By contrast {@code org.apache.sis.storage.base.MemoryGridResource} may 
return images larger than requested,
- * which make testing more difficult.
+ * This class has some similarities with {@link MemoryGridCoverageResource} 
except that the {@link GridCoverage}
+ * returned by the {@link #read read(…)} method is guaranteed to wrap an image 
having exactly the requested size
+ * (i.e. the size specified by {@link GridGeometry#getExtent()}). By contrast, 
{@link MemoryGridCoverageResource}
+ * may return images larger than requested, which make testing more difficult.
  *
  * @author  Johann Sorel (Geomatys)
  */
@@ -53,7 +53,7 @@ final class GridResourceMock extends 
AbstractGridCoverageResource {
      * Creates a resource mock with the given grid geometry.
      */
     GridResourceMock(final GridGeometry gridGeometry) {
-        super(null, false);
+        super(null);
         assertNotNull(gridGeometry);
         this.gridGeometry     = gridGeometry;
         this.sampleDimensions = List.of(new 
SampleDimension.Builder().setName(0).build());
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/base/MemoryGridResourceTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/MemoryGridCoverageResourceTest.java
similarity index 80%
rename from 
endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/base/MemoryGridResourceTest.java
rename to 
endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/MemoryGridCoverageResourceTest.java
index ef0750a4ae..eb59bca38f 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/base/MemoryGridResourceTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/MemoryGridCoverageResourceTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage.base;
+package org.apache.sis.storage;
 
 import java.awt.image.BufferedImage;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -34,11 +34,12 @@ import static 
org.apache.sis.test.Assertions.assertEqualsIgnoreMetadata;
 
 
 /**
- * Tests {@link MemoryGridResource}.
+ * Tests {@link MemoryGridCoverageResource}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-public final class MemoryGridResourceTest extends TestCase {
+@SuppressWarnings("exports")
+public final class MemoryGridCoverageResourceTest extends TestCase {
     /**
      * Arbitrary size for the grid to test.
      */
@@ -57,24 +58,24 @@ public final class MemoryGridResourceTest extends TestCase {
     /**
      * The resource to be tested by each test method.
      */
-    private final MemoryGridResource resource;
+    private final MemoryGridCoverageResource resource;
 
     /**
      * Creates a new test case.
      */
-    public MemoryGridResourceTest() {
+    public MemoryGridCoverageResourceTest() {
         crs = HardCodedCRS.WGS84;
         gridToCRS = new AffineTransform2D(2, 0, 0, 3, 0, 0);
-        final GridGeometry grid = new GridGeometry(new GridExtent(WIDTH, 
HEIGHT), PixelInCell.CELL_CENTER, gridToCRS, crs);
-        final BufferedImage image = new BufferedImage(WIDTH, HEIGHT, 
BufferedImage.TYPE_BYTE_BINARY);
-        resource = new MemoryGridResource(null, null, new GridCoverage2D(grid, 
null, image), null);
+        final var grid = new GridGeometry(new GridExtent(WIDTH, HEIGHT), 
PixelInCell.CELL_CENTER, gridToCRS, crs);
+        final var image = new BufferedImage(WIDTH, HEIGHT, 
BufferedImage.TYPE_BYTE_BINARY);
+        resource = new MemoryGridCoverageResource(null, new 
GridCoverage2D(grid, null, image), null);
     }
 
     /**
      * Creates an arbitrary grid geometry included inside the {@linkplain 
#resource} extent.
      */
     private GridGeometry createSubGrid() {
-        final GridExtent extent = new GridExtent(null,
+        final var extent = new GridExtent(null,
                 new long[] {7, 4},
                 new long[] {WIDTH - 9, HEIGHT - 11}, true);
 
@@ -82,7 +83,7 @@ public final class MemoryGridResourceTest extends TestCase {
     }
 
     /**
-     * Tests {@link MemoryGridResource#read(GridGeometry, int...)}.
+     * Tests {@link MemoryGridCoverageResource#read(GridGeometry, int[])}.
      */
     @Test
     public void testRead() {
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
index adc7968511..4c02d10c85 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
@@ -33,7 +33,7 @@ import org.apache.sis.coverage.grid.BufferedGridCoverage;
 import org.apache.sis.coverage.grid.GridCoverageProcessor;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.GridCoverageResource;
-import org.apache.sis.storage.base.MemoryGridResource;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
@@ -48,6 +48,7 @@ import org.apache.sis.referencing.crs.HardCodedCRS;
  * @author  Alexis Manin (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 public final class BandAggregateGridResourceTest extends TestCase {
     /**
      * Width and height of images created for tests.
@@ -65,7 +66,7 @@ public final class BandAggregateGridResourceTest extends 
TestCase {
     private final GridCoverageProcessor processor;
 
     /**
-     * Whether to hide {@link MemoryGridResource} in order to disable 
optimizations.
+     * Whether to hide {@link MemoryGridCoverageResource} in order to disable 
optimizations.
      */
     private boolean opaque;
 
@@ -153,7 +154,7 @@ public final class BandAggregateGridResourceTest extends 
TestCase {
         final var aggregator = new CoverageAggregator(null, processor);
         aggregator.addRangeAggregate(first, second);
         /*
-         * If the result is not an instance of `MemoryGridResource`,
+         * If the result is not an instance of `MemoryGridCoverageResource`,
          * this is a bug in `BandAggregateGridResource.create(…)`.
          */
         final LocalName testName = Names.createLocalName(null, null, 
"test-name");
@@ -167,7 +168,7 @@ public final class BandAggregateGridResourceTest extends 
TestCase {
     }
 
     /**
-     * Tests the shortcut for {@link MemoryGridResource} instances.
+     * Tests the shortcut for {@link MemoryGridCoverageResource} instances.
      * {@link BandAggregateGridResource} should apply aggregations directly on 
the underlying grid coverages.
      *
      * @throws DataStoreException if an error occurred while reading a 
resource.
@@ -200,7 +201,7 @@ public final class BandAggregateGridResourceTest extends 
TestCase {
             System.arraycopy(bandValues, 0, data, i, numBands);
         }
         final var values = new DataBufferInt(data, data.length);
-        final var r = new MemoryGridResource(null, null, new 
BufferedGridCoverage(domain, samples, values), null);
+        final var r = new MemoryGridCoverageResource(null, new 
BufferedGridCoverage(domain, samples, values), null);
         return opaque ? new OpaqueGridResource(r) : r;
     }
 
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/ConcatenatedFeatureSetTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/ConcatenatedFeatureSetTest.java
index cd509bf382..f0e4fe4883 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/ConcatenatedFeatureSetTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/ConcatenatedFeatureSetTest.java
@@ -23,7 +23,7 @@ import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.base.MemoryFeatureSet;
+import org.apache.sis.storage.MemoryFeatureSet;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/CoverageMosaicTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/CoverageMosaicTest.java
index dccd97d35c..cf337d3f82 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/CoverageMosaicTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/CoverageMosaicTest.java
@@ -52,6 +52,7 @@ import org.apache.sis.test.TestUtilities;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public final class CoverageMosaicTest extends TestCase {
     /**
@@ -367,10 +368,10 @@ public final class CoverageMosaicTest extends TestCase {
         assertEquals(ranges, coverage.getSampleDimensions());
         GridExtent extent = coverage.getGridGeometry().getExtent();
         /*
-         * At the time of writing this test, the `MemoryGridResource.read(…)` 
implementation
+         * At the time of writing this test, the 
`MemoryGridCoverageResource.read(…)` implementation
          * does not apply subsampling. Therefore, the coverage is as 
`testReadTilesFully()`.
          * If a test failure happens below in a future version, this is not 
necessarily a bug.
-         * Maybe `MemoryGridResource` has been improved and this test should 
be adjusted.
+         * Maybe `MemoryGridCoverageResource` has been improved and this test 
should be adjusted.
          */
         assertEquals(NUM_TILES*TILE_WIDTH,  extent.getSize(0));
         assertEquals(NUM_TILES*TILE_HEIGHT, extent.getSize(1));
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/JoinFeatureSetTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/JoinFeatureSetTest.java
index 2034ca8e58..a284783097 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/JoinFeatureSetTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/JoinFeatureSetTest.java
@@ -27,7 +27,7 @@ import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.feature.internal.shared.AttributeConvention;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.base.MemoryFeatureSet;
+import org.apache.sis.storage.MemoryFeatureSet;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/OpaqueGridResource.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/OpaqueGridResource.java
index 671b6b3e83..4bb8c7272e 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/OpaqueGridResource.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/aggregate/OpaqueGridResource.java
@@ -18,13 +18,13 @@ package org.apache.sis.storage.aggregate;
 
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 import org.apache.sis.storage.base.GridResourceWrapper;
-import org.apache.sis.storage.base.MemoryGridResource;
 
 
 /**
  * Wraps a grid coverage resource without changing anything. This is used for 
disabling optimizations,
- * in order to test different code paths that what would be used with {@code 
MemoryGridResource}.
+ * in order to test different code paths that what would be used with {@code 
MemoryGridCoverageResource}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
@@ -38,7 +38,7 @@ final class OpaqueGridResource extends GridResourceWrapper {
      * Creates a new wrapper for the given coverage.
      */
     OpaqueGridResource(final GridCoverage source) {
-        this.source = new MemoryGridResource(null, null, source, null);
+        this.source = new MemoryGridCoverageResource(null, source, null);
     }
 
     /**
diff --git 
a/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/SEPortrayerTest.java
 
b/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/SEPortrayerTest.java
index aeb8903057..06797449e3 100644
--- 
a/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/SEPortrayerTest.java
+++ 
b/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/SEPortrayerTest.java
@@ -20,7 +20,6 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
@@ -29,7 +28,6 @@ import org.locationtech.jts.geom.CoordinateXY;
 import org.locationtech.jts.geom.GeometryFactory;
 import org.locationtech.jts.geom.Point;
 import org.locationtech.jts.geom.Polygon;
-import org.opengis.util.GenericName;
 import org.opengis.geometry.Envelope;
 import org.opengis.metadata.Metadata;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -52,7 +50,7 @@ import org.apache.sis.storage.Aggregate;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.storage.Resource;
-import org.apache.sis.storage.base.MemoryFeatureSet;
+import org.apache.sis.storage.MemoryFeatureSet;
 import org.apache.sis.style.se1.FeatureTypeStyle;
 import org.apache.sis.style.se1.Symbology;
 import org.apache.sis.style.se1.StyleFactory;
@@ -60,8 +58,6 @@ import org.apache.sis.style.se1.Symbolizer;
 import org.apache.sis.style.se1.SemanticType;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.storage.event.StoreEvent;
-import org.apache.sis.storage.event.StoreListener;
 import org.apache.sis.util.iso.Names;
 
 // Test dependencies
@@ -543,21 +539,10 @@ public class SEPortrayerTest {
                 return list;
             }
 
-            @Override
-            public Optional<GenericName> getIdentifier() throws 
DataStoreException {
-                return Optional.empty();
-            }
-
             @Override
             public Metadata getMetadata() throws DataStoreException {
                 return null;
             }
-
-            @Override
-            public <T extends StoreEvent> void addListener(Class<T> eventType, 
StoreListener<? super T> listener) {}
-
-            @Override
-            public <T extends StoreEvent> void removeListener(Class<T> 
eventType, StoreListener<? super T> listener) {}
         };
 
         final MapLayer aggLayer = new MapLayer();
diff --git 
a/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/service/GraphicsPortrayerTest.java
 
b/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/service/GraphicsPortrayerTest.java
index fa435f29b3..711db8eb5b 100644
--- 
a/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/service/GraphicsPortrayerTest.java
+++ 
b/incubator/src/org.apache.sis.portrayal.map/test/org/apache/sis/map/service/GraphicsPortrayerTest.java
@@ -39,7 +39,7 @@ import org.apache.sis.map.SEPresentation;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.base.MemoryFeatureSet;
+import org.apache.sis.storage.MemoryFeatureSet;
 import org.apache.sis.style.se1.FeatureTypeStyle;
 import org.apache.sis.style.se1.LineSymbolizer;
 import org.apache.sis.style.se1.Rule;
diff --git 
a/incubator/src/org.apache.sis.storage.coveragejson/test/org/apache/sis/storage/coveragejson/CoverageJsonStoreTest.java
 
b/incubator/src/org.apache.sis.storage.coveragejson/test/org/apache/sis/storage/coveragejson/CoverageJsonStoreTest.java
index eda64970b1..0a9d1d9027 100644
--- 
a/incubator/src/org.apache.sis.storage.coveragejson/test/org/apache/sis/storage/coveragejson/CoverageJsonStoreTest.java
+++ 
b/incubator/src/org.apache.sis.storage.coveragejson/test/org/apache/sis/storage/coveragejson/CoverageJsonStoreTest.java
@@ -34,10 +34,10 @@ import org.apache.sis.storage.Aggregate;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.MemoryGridCoverageResource;
 import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.WritableAggregate;
-import org.apache.sis.storage.base.MemoryGridResource;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
 
@@ -132,7 +132,7 @@ public class CoverageJsonStoreTest {
             gcb.setValues(image);
             final GridCoverage coverage = gcb.build();
 
-            final GridCoverageResource gcr = new MemoryGridResource(null, 
null, coverage, null);
+            final GridCoverageResource gcr = new 
MemoryGridCoverageResource(null, coverage, null);
 
             aggregate.add(gcr);
 
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/RootResource.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/RootResource.java
index 8bcc1722ef..43466ea1de 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/RootResource.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/RootResource.java
@@ -19,14 +19,10 @@ package org.apache.sis.gui.dataset;
 import java.util.AbstractList;
 import java.util.Collection;
 import java.util.List;
-import java.util.Optional;
 import javafx.scene.control.TreeItem;
 import org.opengis.metadata.Metadata;
-import org.opengis.util.GenericName;
 import org.apache.sis.storage.Aggregate;
 import org.apache.sis.storage.Resource;
-import org.apache.sis.storage.event.StoreEvent;
-import org.apache.sis.storage.event.StoreListener;
 
 
 /**
@@ -109,14 +105,6 @@ final class RootResource implements Aggregate {
         };
     }
 
-    /**
-     * Returns empty optional since this resource has no identifier.
-     */
-    @Override
-    public Optional<GenericName> getIdentifier() {
-        return Optional.empty();
-    }
-
     /**
      * Returns null since this resource has no metadata. Returning null is 
normally
      * not allowed for this method, but {@link ResourceTree} is robust to this 
case.
@@ -125,8 +113,4 @@ final class RootResource implements Aggregate {
     public Metadata getMetadata() {
         return null;
     }
-
-    /** Ignored since this class does not emit any event. */
-    @Override public <T extends StoreEvent> void    addListener(Class<T> 
eventType, StoreListener<? super T> listener) {}
-    @Override public <T extends StoreEvent> void removeListener(Class<T> 
eventType, StoreListener<? super T> listener) {}
 }

Reply via email to