You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2023/04/16 16:51:03 UTC

[sis] branch geoapi-4.0 updated (0e2089b190 -> 175b9f0ced)

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

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


    from 0e2089b190 If the resources to aggregate are instances of `MemoryGridResource`, aggregate directly the underlying `GridCoverage` instances.
     new 3906ad83eb The check for `MemoryGridResource` in `BandAggregateGridResource.create(…)` should not be an "all or nothing" operation. With this commit, shortcut is used even if only some of the resources to aggregate are `MemoryGridResource` instances.
     new 175b9f0ced Fix some javadoc errors.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../sis/coverage/grid/GridCoverageProcessor.java   |   2 +
 .../sis/internal/coverage/MultiSourceArgument.java |  32 +++++-
 .../apache/sis/parameter/ParameterValueList.java   |   2 +-
 .../referencing/factory/sql/AuthorityCodes.java    |   2 +-
 .../referencing/operation/projection/Mercator.java |   4 +-
 .../sis/internal/storage/MemoryGridResource.java   |  45 ++++-----
 .../org/apache/sis/storage/StorageConnector.java   |  44 ++++----
 .../aggregate/BandAggregateGridResource.java       | 112 +++++++++++++--------
 .../aggregate/BandAggregateGridResourceTest.java   |  42 ++++++--
 ...AggregatorTest.java => OpaqueGridResource.java} |  33 +++---
 10 files changed, 203 insertions(+), 115 deletions(-)
 copy storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/{CoverageAggregatorTest.java => OpaqueGridResource.java} (55%)


[sis] 01/02: The check for `MemoryGridResource` in `BandAggregateGridResource.create(…)` should not be an "all or nothing" operation. With this commit, shortcut is used even if only some of the resources to aggregate are `MemoryGridResource` instances.

Posted by de...@apache.org.
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 3906ad83eb828893f5c0ad93335a517078195cf2
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sun Apr 16 17:11:33 2023 +0200

    The check for `MemoryGridResource` in `BandAggregateGridResource.create(…)` should not be an "all or nothing" operation.
    With this commit, shortcut is used even if only some of the resources to aggregate are `MemoryGridResource` instances.
---
 .../sis/coverage/grid/GridCoverageProcessor.java   |   1 +
 .../sis/internal/coverage/MultiSourceArgument.java |  32 +++++-
 .../sis/internal/storage/MemoryGridResource.java   |  45 ++++-----
 .../aggregate/BandAggregateGridResource.java       | 112 +++++++++++++--------
 .../aggregate/BandAggregateGridResourceTest.java   |  42 ++++++--
 .../sis/storage/aggregate/OpaqueGridResource.java  |  46 +++++++++
 6 files changed, 203 insertions(+), 75 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
index b952560d91..c38ec7d876 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
@@ -790,6 +790,7 @@ public class GridCoverageProcessor implements Cloneable {
         final var aggregate = new MultiSourceArgument<>(sources, bandsPerSource);
         aggregate.unwrap(BandAggregateGridCoverage::unwrap);
         aggregate.validate(GridCoverage::getSampleDimensions);
+        aggregate.mergeConsecutiveSources();
         if (aggregate.isIdentity()) {
             return aggregate.sources()[0];
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/MultiSourceArgument.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/MultiSourceArgument.java
index 8044bd7d2c..6cab63d7ed 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/MultiSourceArgument.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/MultiSourceArgument.java
@@ -407,12 +407,37 @@ next:   for (int i=0; i<sources.length; i++) {          // `sources.length` may
     }
 
     /**
-     * If the same sources are repeated many times, merges them in a single reference.
+     * For each source which is repeated in consecutive positions, merges the repetition in a single reference.
+     * This method does the same work than {@link #mergeDuplicatedSources()}, except that it is restricted to
+     * repetitions in consecutive positions. Because of this restriction, the band order is never modified by
+     * this method call.
+     */
+    public void mergeConsecutiveSources() {
+        checkValidationState(true);
+        for (int i=1; i < validatedSourceCount;) {
+            if (sources[i] == sources[i-1]) {
+                bandsPerSource[i-1] = ArraysExt.concatenate(bandsPerSource[i-1], bandsPerSource[i]);
+                final int remaining = --validatedSourceCount - i;
+                System.arraycopy(sources,           i+1, sources,           i, remaining);
+                System.arraycopy(bandsPerSource,    i+1, bandsPerSource,    i, remaining);
+                System.arraycopy(numBandsPerSource, i+1, numBandsPerSource, i, remaining);
+            } else {
+                i++;
+            }
+        }
+    }
+
+    /**
+     * If the same sources are repeated many times, merges each repetition in a single reference.
      * The {@link #sources()} and {@link #bandsPerSource(boolean)} values are modified in-place.
      * The bands associated to each source reference are merged together, but not necessarily in the same order.
      * Caller must perform a "band select" operation using the array returned by this method
      * in order to reconstitute the band order specified by the user.
      *
+     * <p>This method does the same work than {@link #mergeConsecutiveSources()} except that this method can merge
+     * sources that are not necessarily at consecutive positions. The sources can be repeated at random positions.
+     * But the cost of this flexibility is the possible modification of band order.</p>
+     *
      * <h4>Use cases</h4>
      * {@code BandAggregateImage.subset(…)} and
      * {@code BandAggregateGridResource.read(…)}
@@ -468,9 +493,8 @@ next:   for (int i=0; i<sources.length; i++) {          // `sources.length` may
                  */
                 for (int j=0; j < tuples.length; j++) {
                     final long t = tuples[j];
-                    final int sourceBand = (int) (t >>> Integer.SIZE);
-                    reordered[(int) t] = sourceBand + targetBand;
-                    selected[j] = sourceBand;
+                    reordered[(int) t] = targetBand + j;
+                    selected[j] = (int) (t >>> Integer.SIZE);
                 }
                 targetBand += tuples.length;
                 numBandsPerSource[validatedSourceCount] = numBandsPerSource[i];
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryGridResource.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryGridResource.java
index 32a1eda795..f96563a553 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryGridResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryGridResource.java
@@ -23,12 +23,10 @@ import org.opengis.referencing.datum.PixelInCell;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridCoverageBuilder;
+import org.apache.sis.coverage.grid.GridCoverageProcessor;
 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.image.ImageProcessor;
-import org.apache.sis.internal.coverage.RangeArgument;
-import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.storage.AbstractGridCoverageResource;
 import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.util.ArgumentChecks;
@@ -41,10 +39,10 @@ import org.apache.sis.util.ArgumentChecks;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.3
+ * @version 1.4
  * @since   1.1
  */
-public class MemoryGridResource extends AbstractGridCoverageResource {
+public final class MemoryGridResource extends AbstractGridCoverageResource {
     /**
      * The grid coverage specified at construction time.
      */
@@ -94,8 +92,16 @@ public class MemoryGridResource extends AbstractGridCoverageResource {
      */
     @Override
     public GridCoverage read(GridGeometry domain, final int... ranges) {
-        List<SampleDimension> bands = coverage.getSampleDimensions();
-        final RangeArgument rangeIndices = RangeArgument.validate(bands.size(), ranges, listeners);
+        /*
+         * If the user requested a subset of the bands, select the bands on the grid coverage.
+         * It is slightly more expensive than selecting the bands on the image produced at the
+         * end of this method, except if the coverage is a `BandAggregateGridCoverage` because
+         * the latter will do rendering only on the selected coverage components.
+         */
+        GridCoverage subset = coverage;
+        if (ranges != null && ranges.length != 0) {
+            subset = new GridCoverageProcessor().selectSampleDimensions(subset, ranges);
+        }
         /*
          * The given `domain` may use arbitrary `gridToCRS` and `CRS` properties.
          * For this simple implementation we need the same `gridToCRS` and `CRS`
@@ -107,7 +113,7 @@ public class MemoryGridResource extends AbstractGridCoverageResource {
          *       by adjusting the pixel stride in SampleModel.
          */
         GridExtent intersection = null;
-        final GridGeometry source = coverage.getGridGeometry();
+        final GridGeometry source = subset.getGridGeometry();
         if (domain == null) {
             domain = source;
         } else {
@@ -122,9 +128,8 @@ public class MemoryGridResource extends AbstractGridCoverageResource {
         /*
          * Quick check before to invoke the potentially costly `coverage.render(…)` method.
          */
-        final boolean sameBands = rangeIndices.isIdentity();
-        if (sameBands && intersection == null) {
-            return coverage;
+        if (intersection == null) {
+            return subset;
         }
         /*
          * After `render(…)` execution, the (minX, minY) image coordinates are the differences between
@@ -132,7 +137,7 @@ public class MemoryGridResource extends AbstractGridCoverageResource {
          * we need to translate the `GridExtent` in order to make it matches what we got. But before to
          * apply that translation, we adjust the grid size (because it may add another translation).
          */
-        RenderedImage data = coverage.render(intersection);
+        RenderedImage data = subset.render(intersection);
         if (intersection != null) {
             final int[]  sd      = intersection.getSubspaceDimensions(2);
             final int    dimX    = sd[0];
@@ -157,26 +162,20 @@ public class MemoryGridResource extends AbstractGridCoverageResource {
             intersection  = intersection.translate(changes);
             /*
              * If the result is the same intersection than the source coverage,
-             * we may be able to return that coverage directly.
+             * we can return that coverage directly.
              */
             if (intersection.equals(source.getExtent())) {
-                if (sameBands) {
-                    return coverage;
-                }
-                domain = source;
+                return subset;
             } else {
                 domain = new GridGeometry(intersection, PixelInCell.CELL_CORNER,
                         source.getGridToCRS(PixelInCell.CELL_CORNER),
                         source.getCoordinateReferenceSystem());
             }
         }
-        if (!sameBands) {
-            data  = new ImageProcessor().selectBands(data, ranges);
-            bands = UnmodifiableArrayList.wrap(rangeIndices.select(bands));
-        }
         return new GridCoverageBuilder()
                 .setValues(data)
-                .setRanges(bands)
-                .setDomain(domain).build();
+                .setDomain(domain)
+                .setRanges(subset.getSampleDimensions())
+                .build();
     }
 }
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
index 301f28a259..5487b2cea2 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/aggregate/BandAggregateGridResource.java
@@ -38,6 +38,8 @@ import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ArraysExt;
 
 
 /**
@@ -120,6 +122,29 @@ final class BandAggregateGridResource extends AbstractGridCoverageResource imple
      * 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.
+     * @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,
+                                      final MultiSourceArgument<GridCoverageResource> aggregate,
+                                      final GridCoverageProcessor processor)
+    {
+        super(parentListeners, false);
+        this.sources          = aggregate.sources();
+        this.gridGeometry     = aggregate.domain(BandAggregateGridResource::domain);
+        this.sampleDimensions = List.copyOf(aggregate.ranges());
+        this.bandsPerSource   = aggregate.bandsPerSource(false);
+        this.processor        = processor;
+    }
+
+    /**
+     * Creates a new range aggregation of grid coverage resources,
+     * potentially unwrapping in-memory resources for efficiency.
+     *
      * <p>The {@code bandsPerSource} argument specifies the bands to select in each resource.
      * That array can be {@code null} for selecting all bands in all resources,
      * or may contain {@code null} elements for selecting all bands of the corresponding resource.
@@ -141,24 +166,63 @@ final class BandAggregateGridResource extends AbstractGridCoverageResource imple
      * @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.
      */
-    BandAggregateGridResource(final StoreListeners parentListeners,
-            final GridCoverageResource[] sources, final int[][] bandsPerSource,
+    static GridCoverageResource create(final StoreListeners parentListeners,
+            GridCoverageResource[] sources, int[][] bandsPerSource,
             final GridCoverageProcessor processor) throws DataStoreException
     {
-        super(parentListeners, false);
+        var coverages     = new GridCoverage[sources.length];
+        var coverageBands = new int[sources.length][];
+        int firstBand = 0, count = 0;
+        for (int i=0; i<sources.length; i++) {
+            final GridCoverageResource source = sources[i];
+            ArgumentChecks.ensureNonNullElement("sources", i, source);
+            if (source instanceof MemoryGridResource) {
+                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;
+                coverageBands[count] = bands;
+                bandsPerSource[i]    = ArraysExt.range(firstBand, firstBand + numBands);
+                sources[i]           = null;        // To be replaced by the aggregated coverage.
+                firstBand += numBands;
+                count++;
+            }
+        }
+        /*
+         * 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 (count != 0) {
+            coverages     = ArraysExt.resize(coverages,     count);
+            coverageBands = ArraysExt.resize(coverageBands, count);
+            var aggregate = new MemoryGridResource(parentListeners, processor.aggregateRanges(coverages, coverageBands));
+            for (int i=0; i<sources.length; i++) {
+                if (sources[i] == null) {
+                    sources[i] = aggregate;
+                }
+            }
+        }
+        /*
+         * If the same source appears two or more times consecutively, `MultiSourceArgument` will merge them
+         * in a single reference to that source. Consequently the arrays of sources may become shorter.
+         */
         try {
             final var aggregate = new MultiSourceArgument<GridCoverageResource>(sources, bandsPerSource);
             aggregate.unwrap(BandAggregateGridResource::unwrap);
             aggregate.validate(BandAggregateGridResource::range);
-            this.sources          = aggregate.sources();
-            this.gridGeometry     = aggregate.domain(BandAggregateGridResource::domain);
-            this.sampleDimensions = List.copyOf(aggregate.ranges());
-            this.bandsPerSource   = aggregate.bandsPerSource(false);
-            this.processor        = processor;
+            aggregate.mergeConsecutiveSources();
+            if (aggregate.isIdentity()) {
+                return aggregate.sources()[0];
+            }
+            return new BandAggregateGridResource(parentListeners, aggregate, processor);
         } catch (BackingStoreException e) {
             throw e.unwrapOrRethrow(DataStoreException.class);
         }
@@ -202,38 +266,6 @@ final class BandAggregateGridResource extends AbstractGridCoverageResource imple
         }
     }
 
-    /**
-     * Creates a new range aggregation of grid coverage resources,
-     * potentially unwrapping in-memory resources for efficiency.
-     *
-     * @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.
-     * @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,
-            final GridCoverageResource[] sources, final int[][] bandsPerSource,
-            final GridCoverageProcessor processor) throws DataStoreException
-    {
-        GridCoverageResource source = sources[0];
-        if (source instanceof MemoryGridResource) {
-            final var coverages = new GridCoverage[sources.length];
-            int i = 0;
-            do {
-                coverages[i] = ((MemoryGridResource) source).coverage;
-                if (++i >= sources.length) {
-                    GridCoverage coverage = processor.aggregateRanges(coverages, bandsPerSource);
-                    return new MemoryGridResource(parentListeners, coverage);
-                }
-            } while ((source = sources[i]) instanceof MemoryGridResource);
-        }
-        return new BandAggregateGridResource(parentListeners, sources, bandsPerSource, processor);
-    }
-
     /** Not applicable to this implementation. */
     @Override public Resource apply(MergeStrategy strategy) {return this;}
 
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java b/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
index 9af75669e8..95ef5dc7bb 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/BandAggregateGridResourceTest.java
@@ -65,10 +65,16 @@ public final class BandAggregateGridResourceTest extends TestCase {
      */
     private final GridCoverageProcessor processor;
 
+    /**
+     * Whether to hide {@link MemoryGridResource} in order to disable optimizations.
+     */
+    private boolean opaque;
+
     /**
      * Creates a new test case.
      */
     public BandAggregateGridResourceTest() {
+        opaque = true;
         processor = new GridCoverageProcessor();
         domain = new GridGeometry(new GridExtent(WIDTH, HEIGHT), PixelInCell.CELL_CENTER,
                                   MathTransforms.identity(2), HardCodedCRS.WGS84);
@@ -82,8 +88,8 @@ public final class BandAggregateGridResourceTest extends TestCase {
      * @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.
      */
-    private BandAggregateGridResource create(final GridCoverageResource... sources) throws DataStoreException {
-        return new BandAggregateGridResource(null, sources, null, processor);
+    private GridCoverageResource create(final GridCoverageResource... sources) throws DataStoreException {
+        return BandAggregateGridResource.create(null, sources, null, processor);
     }
 
     /**
@@ -125,12 +131,13 @@ public final class BandAggregateGridResourceTest extends TestCase {
          * In addition, band order in one of the 3 coverages is modified.
          */
         final LocalName testName = Names.createLocalName(null, null, "test-name");
-        aggregation = new BandAggregateGridResource(null,
+        aggregation = BandAggregateGridResource.create(null,
                 new GridCoverageResource[] {firstAndSecondBands, thirdAndFourthBands, fifthAndSixthBands},
                 new int[][] {null, new int[] {1, 0}, new int[] {1}}, processor);
-
-        aggregation.setIdentifier(testName);
-        assertEquals(testName, aggregation.getIdentifier().orElse(null));
+        if (opaque) {
+            ((BandAggregateGridResource) aggregation).setIdentifier(testName);
+            assertEquals(testName, aggregation.getIdentifier().orElse(null));
+        }
         assertAllPixelsEqual(aggregation.read(null), 101, 102, 104, 103, 106);
         assertAllPixelsEqual(aggregation.read(null, 2, 4), 104, 106);
     }
@@ -150,12 +157,30 @@ public final class BandAggregateGridResourceTest extends TestCase {
          * If the result is not an instance of `MemoryGridResource`,
          * this is a bug in `BandAggregateGridResource.create(…)`.
          */
-        final var aggregation = (MemoryGridResource) aggregator.build(null);
+        final LocalName testName = Names.createLocalName(null, null, "test-name");
+        final var aggregation = (GridCoverageResource) aggregator.build(testName);
+        if (opaque) {
+            assertEquals(testName, aggregation.getIdentifier().orElse(null));
+        }
         assertAllPixelsEqual(aggregation.read(null), 17, 23);
         assertAllPixelsEqual(aggregation.read(null, 0), 17);
         assertAllPixelsEqual(aggregation.read(null, 1), 23);
     }
 
+    /**
+     * Tests the shortcut for {@link MemoryGridResource} instances.
+     * {@link BandAggregateGridResource} should apply aggregations directly on the underlying grid coverages.
+     *
+     * @throws DataStoreException if an error occurred while reading a resource.
+     */
+    @Test
+    public void testMemoryGridResourceShortcut() throws DataStoreException {
+        opaque = false;
+        aggregateBandsFromSingleBandSources();
+        aggregateBandsFromMultiBandSources();
+        usingCoverageAggregator();
+    }
+
     /**
      * Creates a new grid coverage resource with bands having the given values.
      * The length of the {@code bandValues} array is the number of bands to create.
@@ -176,7 +201,8 @@ public final class BandAggregateGridResourceTest extends TestCase {
             System.arraycopy(bandValues, 0, data, i, numBands);
         }
         final var values = new DataBufferInt(data, data.length);
-        return new MemoryGridResource(null, new BufferedGridCoverage(domain, samples, values));
+        final var r = new MemoryGridResource(null, new BufferedGridCoverage(domain, samples, values));
+        return opaque ? new OpaqueGridResource(r) : r;
     }
 
     /**
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/OpaqueGridResource.java b/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/OpaqueGridResource.java
new file mode 100644
index 0000000000..1e1193813d
--- /dev/null
+++ b/storage/sis-storage/src/test/java/org/apache/sis/storage/aggregate/OpaqueGridResource.java
@@ -0,0 +1,46 @@
+/*
+ * 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.aggregate;
+
+import org.apache.sis.internal.storage.GridResourceWrapper;
+import org.apache.sis.storage.GridCoverageResource;
+
+
+/**
+ * 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}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.4
+ * @since   1.4
+ */
+final class OpaqueGridResource extends GridResourceWrapper {
+    /**
+     * The resource to hide.
+     */
+    private final GridCoverageResource source;
+
+    /**
+     * Creates a new wrapper.
+     */
+    OpaqueGridResource(final GridCoverageResource source) {
+        this.source = source;
+    }
+
+    @Override protected Object getSynchronizationLock()     {return source;}
+    @Override protected GridCoverageResource createSource() {return source;}
+}


[sis] 02/02: Fix some javadoc errors.

Posted by de...@apache.org.
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 175b9f0cedf9a06f064c9cbc4aedaa9e5acae700
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sun Apr 16 18:50:45 2023 +0200

    Fix some javadoc errors.
---
 .../sis/coverage/grid/GridCoverageProcessor.java   |  1 +
 .../apache/sis/parameter/ParameterValueList.java   |  2 +-
 .../referencing/factory/sql/AuthorityCodes.java    |  2 +-
 .../referencing/operation/projection/Mercator.java |  4 +-
 .../org/apache/sis/storage/StorageConnector.java   | 44 ++++++++++++----------
 5 files changed, 29 insertions(+), 24 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
index c38ec7d876..a708489344 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverageProcessor.java
@@ -31,6 +31,7 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.coverage.Category;
 import org.apache.sis.coverage.RegionOfInterest;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.SubspaceNotSpecifiedException;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
index b7abe02409..c14390e7ed 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
@@ -43,7 +43,7 @@ import org.apache.sis.internal.referencing.Resources;
  * This class performs checks on the parameter values to be added or removed.
  * This implementation supports {@code set(…)}, {@code add(…)} and {@code remove(…)} operations.
  *
- * <h4>Implementation note</h4>
+ * <h2>Implementation note</h2>
  * This class reproduces some {@link java.util.ArrayList} functionalities.
  * However, we do <strong>not</strong> extend {@code ArrayList} because we really need the default method
  * implementations provided by {@code AbstractList} — the optimizations performed by {@code ArrayList}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
index 6c1e899463..bcf8bcb5a0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
@@ -26,8 +26,8 @@ import java.sql.PreparedStatement;
 import java.sql.Statement;
 import org.opengis.referencing.operation.Projection;
 import org.apache.sis.util.collection.BackingStoreException;
-import org.apache.sis.internal.util.AbstractMap;
 import org.apache.sis.util.collection.IntegerList;
+import org.apache.sis.internal.util.AbstractMap;
 
 
 /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
index add9caf444..fe6d1f2275 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
@@ -492,8 +492,8 @@ subst:  if (variant.spherical || (eccentricity == 0 && getClass() == Mercator.cl
     /**
      * Provides the transform equations for the spherical case of the Mercator projection.
      *
-     * <h4>Implementation note</h4>
-     * this class contains an explicit check for latitude values at a pole. If floating point arithmetic had infinite
+     * <h2>Implementation note</h2>
+     * This class contains an explicit check for latitude values at a pole. If floating point arithmetic had infinite
      * precision, such checks would not be necessary since the formulas lead naturally to infinite values at poles,
      * which is the correct answer. In practice the infinite value emerges by itself at only one pole, and the other
      * one produces a high value (approximately 1E+16). This is because there is no accurate representation of π/2,
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
index 269ba41729..759331e2a1 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
@@ -20,6 +20,9 @@ import java.util.Map;
 import java.util.Iterator;
 import java.util.IdentityHashMap;
 import java.util.function.UnaryOperator;
+import java.net.URI;
+import java.net.URL;
+import java.io.File;
 import java.io.Reader;
 import java.io.DataInput;
 import java.io.DataOutput;
@@ -35,8 +38,9 @@ import java.nio.channels.Channel;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritableByteChannel;
 import java.nio.channels.SeekableByteChannel;
-import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
 import java.nio.file.OpenOption;
+import java.nio.file.NoSuchFileException;
 import javax.imageio.stream.ImageInputStream;
 import javax.imageio.stream.ImageOutputStream;
 import javax.imageio.IIOException;
@@ -77,10 +81,10 @@ import org.apache.sis.setup.OptionKey;
  * {@code StorageConnector} wraps an input {@link Object}, which can be any of the following types:
  *
  * <ul>
- *   <li>A {@link java.nio.file.Path} or a {@link java.io.File} for a file or a directory.</li>
- *   <li>A {@link java.net.URI} or a {@link java.net.URL} to a distant resource.</li>
+ *   <li>A {@link Path} or a {@link File} for a file or a directory.</li>
+ *   <li>A {@link URI} or a {@link URL} to a distant resource.</li>
  *   <li>A {@link CharSequence} interpreted as a filename or a URL.</li>
- *   <li>A {@link java.nio.channels.Channel}, {@link DataInput}, {@link InputStream} or {@link Reader}.</li>
+ *   <li>A {@link Channel}, {@link DataInput}, {@link InputStream} or {@link Reader}.</li>
  *   <li>A {@link DataSource} or a {@link Connection} to a JDBC database.</li>
  *   <li>Any other {@code DataStore}-specific object, for example {@link ucar.nc2.NetcdfFile}.</li>
  * </ul>
@@ -222,10 +226,10 @@ public class StorageConnector implements Serializable {
          * exception if the conversion fail. Instead, getStorageAs(Class) will return null.
          * Classes not listed here will let the UnconvertibleObjectException propagates.
          */
-        add(java.net.URI.class,       null);
-        add(java.net.URL.class,       null);
-        add(java.io.File.class,       null);
-        add(java.nio.file.Path.class, null);
+        add(URI.class,  null);
+        add(URL.class,  null);
+        add(File.class, null);
+        add(Path.class, null);
     }
 
     /**
@@ -294,7 +298,7 @@ public class StorageConnector implements Serializable {
      * used independently. They are views that may advance {@code storage} position, but not at the same time than the
      * {@link #view} position (typically because the view reads some bytes in advance and stores them in a buffer).
      * Such coupling may occur when the storage is an {@link InputStream}, an {@link java.io.OutputStream} or a
-     * {@link java.nio.channels.Channel}. The coupled {@link #view} can be:
+     * {@link Channel}. The coupled {@link #view} can be:
      *
      * <ul>
      *   <li>{@link Reader} that are wrappers around {@code InputStream}.</li>
@@ -641,8 +645,8 @@ public class StorageConnector implements Serializable {
      * {@linkplain #getStorage() storage} object:
      *
      * <ul>
-     *   <li>For {@link java.nio.file.Path}, {@link java.io.File}, {@link java.net.URI} or {@link java.net.URL}
-     *       instances, this method uses dedicated API like {@link java.nio.file.Path#getFileName()}.</li>
+     *   <li>For {@link Path}, {@link File}, {@link URI} or {@link URL}
+     *       instances, this method uses dedicated API like {@link Path#getFileName()}.</li>
      *   <li>For {@link CharSequence} instances, this method gets a string representation of the storage object
      *       and returns the part after the last {@code '/'} character or platform-dependent name separator.</li>
      *   <li>For instances of unknown type, this method builds a string representation using the class name.
@@ -669,7 +673,7 @@ public class StorageConnector implements Serializable {
      * the following choices based on the type of the {@linkplain #getStorage() storage} object:
      *
      * <ul>
-     *   <li>For {@link java.nio.file.Path}, {@link java.io.File}, {@link java.net.URI}, {@link java.net.URL} or
+     *   <li>For {@link Path}, {@link File}, {@link URI}, {@link URL} or
      *       {@link CharSequence} instances, this method returns the string after the last {@code '.'} character
      *       in the filename, provided that the {@code '.'} is not the first filename character. This may be an
      *       empty string if the filename has no extension, but never {@code null}.</li>
@@ -701,17 +705,17 @@ public class StorageConnector implements Serializable {
      * <ul>
      *   <li>{@link String}:
      *     <ul>
-     *       <li>If the {@linkplain #getStorage() storage} object is an instance of the {@link java.nio.file.Path},
-     *           {@link java.io.File}, {@link java.net.URL}, {@link java.net.URI} or {@link CharSequence} types,
+     *       <li>If the {@linkplain #getStorage() storage} object is an instance of the {@link Path},
+     *           {@link File}, {@link URL}, {@link URI} or {@link CharSequence} types,
      *           returns the string representation of their path.</li>
      *
      *       <li>Otherwise this method returns {@code null}.</li>
      *     </ul>
      *   </li>
-     *   <li>{@link java.nio.file.Path}, {@link java.net.URI}, {@link java.net.URL}, {@link java.io.File}:
+     *   <li>{@link Path}, {@link URI}, {@link URL}, {@link File}:
      *     <ul>
-     *       <li>If the {@linkplain #getStorage() storage} object is an instance of the {@link java.nio.file.Path},
-     *           {@link java.io.File}, {@link java.net.URL}, {@link java.net.URI} or {@link CharSequence} types and
+     *       <li>If the {@linkplain #getStorage() storage} object is an instance of the {@link Path},
+     *           {@link File}, {@link URL}, {@link URI} or {@link CharSequence} types and
      *           that type can be converted to the requested type, returned the conversion result.</li>
      *
      *       <li>Otherwise this method returns {@code null}.</li>
@@ -735,8 +739,8 @@ public class StorageConnector implements Serializable {
      *           backed by a read-only view of that buffer is created when first needed and returned.
      *           The properties (position, mark, limit) of the original buffer are unmodified.</li>
      *
-     *       <li>Otherwise if the input is an instance of {@link java.nio.file.Path}, {@link java.io.File},
-     *           {@link java.net.URI}, {@link java.net.URL}, {@link CharSequence}, {@link InputStream} or
+     *       <li>Otherwise if the input is an instance of {@link Path}, {@link File},
+     *           {@link URI}, {@link URL}, {@link CharSequence}, {@link InputStream} or
      *           {@link java.nio.channels.ReadableByteChannel}, then an {@link ImageInputStream} backed by a
      *           {@link ByteBuffer} is created when first needed and returned.</li>
      *
@@ -830,7 +834,7 @@ public class StorageConnector implements Serializable {
          * Note that InputStream may need to be reset if it has been used indirectly by other kind
          * of stream (for example a java.io.Reader). Example:
          *
-         *    1) The storage specified at construction time is a java.nio.file.Path.
+         *    1) The storage specified at construction time is a `Path`.
          *    2) getStorageAs(InputStream.class) opens an InputStream. Caller rewinds it after use.
          *    3) getStorageAs(Reader.class) wraps the InputStream. Caller rewinds the Reader after use,
          *       but invoking BufferedReader.reset() has no effect on the underlying InputStream.