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 dab1256806e44d60f0a8c4c892f1e8b1a1cb1855
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sat Sep 14 17:19:59 2024 +0200

    Better `probeContent` implementation, including MIME type.
    `GDALStore.close()` needs to close child components too.
---
 .../org/apache/sis/storage/gdal/GDALStore.java     | 33 ++++++++++++++++++-
 .../apache/sis/storage/gdal/GDALStoreProvider.java | 14 ++++----
 .../main/org/apache/sis/storage/gdal/Opener.java   | 38 +++++++++++++++++++++-
 .../org/apache/sis/storage/gdal/GDALStoreTest.java | 24 ++++++++++++--
 4 files changed, 98 insertions(+), 11 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
index 6182b45554..8122818c66 100644
--- 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
+++ 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStore.java
@@ -490,8 +490,36 @@ public class GDALStore extends DataStore implements 
Aggregate, ResourceOnFileSys
             }
         }
         try (Flush _ = new Flush()) {
+            closeRecursively();
+        }
+    }
+
+    /**
+     * Closes all child components (if any) recursively, then closes this data 
store.
+     */
+    private void closeRecursively() {
+        RuntimeException error = null;
+        try {
+            listeners.close();
+        } catch (RuntimeException e) {
+            error = e;      // Should not happen even if a listener threw an 
exception, but we want to be safe.
+        } finally {
             try {
-                listeners.close();
+                final List<? extends Resource> children;
+                synchronized (this) {
+                    children = components;
+                    components = null;
+                }
+                if (children != null) {
+                    for (Resource child : children) {
+                        if (child instanceof Subdataset) try {
+                            ((GDALStore) child).closeRecursively();
+                        } catch (RuntimeException e) {
+                            if (error == null) error = e;
+                            else error.addSuppressed(e);
+                        }
+                    }
+                }
             } finally {
                 synchronized (this) {
                     handle = null;
@@ -499,5 +527,8 @@ public class GDALStore extends DataStore implements 
Aggregate, ResourceOnFileSys
                 }
             }
         }
+        if (error != null) {
+            throw error;
+        }
     }
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStoreProvider.java
 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStoreProvider.java
index 885c44efaa..d1f6c053cc 100644
--- 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStoreProvider.java
+++ 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/GDALStoreProvider.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.storage.gdal;
 
+import java.net.URI;
 import java.util.List;
 import java.util.Optional;
 import java.util.logging.Logger;
@@ -279,18 +280,17 @@ public class GDALStoreProvider extends DataStoreProvider {
      * @return a {@linkplain ProbeResult#isSupported() supported} status with 
the MIME type
      *         if the given storage seems to be readable by {@code GDALStore} 
instances.
      * @throws DataStoreException if an I/O error occurred.
-     *
-     * @todo Need to check whether GDAL library has been found.
-     * @todo Need better check. Does GDAL provides a probe API?
      */
     @Override
     public ProbeResult probeContent(final StorageConnector connector) throws 
DataStoreException {
-        final Path path = connector.getStorageAs(Path.class);
-        if (path != null) {
+        final URI url = connector.getStorageAs(URI.class);
+        if (url != null) {
             final GDAL gdal = tryGDAL("probeContent").orElse(null);
             if (gdal != null) {
-                final String mimeType = null;   // TODO
-                return new ProbeResult(true, mimeType, null);
+                try (Opener p = Opener.read(this, Opener.toURL(url, 
connector.getStorageAs(Path.class)))) {
+                    String mimeType = p.getMetadataItem(gdal, "DMD_MIMETYPE");
+                    return new ProbeResult(true, mimeType, null);
+                }
             }
         }
         return ProbeResult.UNSUPPORTED_STORAGE;
diff --git 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
index 297ab3c950..af3dc8e7cf 100644
--- 
a/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
+++ 
b/incubator/src/org.apache.sis.storage.gdal/main/org/apache/sis/storage/gdal/Opener.java
@@ -24,6 +24,7 @@ import java.lang.foreign.Arena;
 import java.lang.foreign.ValueLayout;
 import java.lang.foreign.MemorySegment;
 import org.apache.sis.util.privy.Constants;
+import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 
 
@@ -39,7 +40,7 @@ import org.apache.sis.storage.DataStoreException;
  * @author  Quentin Bialota (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  */
-final class Opener implements Runnable {
+final class Opener implements Runnable, AutoCloseable {
     /**
      * Schemes of URLs to open with <var>GDAL</var> Virtual File Systems 
backed by <abbr>CURL</abbr>.
      */
@@ -155,6 +156,41 @@ final class Opener implements Runnable {
         return array;
     }
 
+    /**
+     * Returns a metadata item from the driver.
+     *
+     * @param  gdal  set of handles for invoking <abbr>GDAL</abbr> functions.
+     * @param  name  the key for the metadata item to fetch.
+     * @return the metadata given by the driver, or {@code null} if 
unspecified.
+     * @throws DataStoreException if an error occurred while invoking a 
<abbr>GDAL</abbr> function.
+     */
+    final String getMetadataItem(final GDAL gdal, final String name) throws 
DataStoreException {
+        try (var arena = Arena.ofConfined()) {
+            final MemorySegment driver = (MemorySegment) 
gdal.getDatasetDriver.invokeExact(handle);
+            if (!GDAL.isNull(driver)) {
+                MemorySegment n = arena.allocateFrom(name);
+                MemorySegment r = (MemorySegment) 
gdal.getMetadataItem.invokeExact(driver, n, MemorySegment.NULL);
+                return GDAL.toString(r);
+            }
+        } catch (Throwable e) {
+            throw GDAL.propagate(e);
+        } finally {
+            ErrorHandler.throwOnFailure(null, "probeContent");
+        }
+        return null;
+    }
+
+    /**
+     * Closes the <abbr>GDAL</abbr> data set. This method shall be invoked
+     * by {@link GDALStoreProvider#probeContent(StorageConnector)} only.
+     * {@link GDALStore} has its own close method.
+     */
+    @Override
+    public void close() throws DataStoreException {
+        run();
+        ErrorHandler.throwOnFailure(null, "probeContent");
+    }
+
     /**
      * Invoked by {@link java.lang.ref.Cleaner} when the native resource is 
ready to be closed.
      * This method shall not be invoked explicitly. The {@code Cleaner} 
<abbr>API</abbr> ensures
diff --git 
a/incubator/src/org.apache.sis.storage.gdal/test/org/apache/sis/storage/gdal/GDALStoreTest.java
 
b/incubator/src/org.apache.sis.storage.gdal/test/org/apache/sis/storage/gdal/GDALStoreTest.java
index 7ea4afcf5d..9353bdf4a5 100644
--- 
a/incubator/src/org.apache.sis.storage.gdal/test/org/apache/sis/storage/gdal/GDALStoreTest.java
+++ 
b/incubator/src/org.apache.sis.storage.gdal/test/org/apache/sis/storage/gdal/GDALStoreTest.java
@@ -29,11 +29,13 @@ import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.PixelInCell;
+import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.GridCoverageResource;
 import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.DataStores;
 import org.apache.sis.storage.DataStoreProvider;
 import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.ProbeResult;
 
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
@@ -65,6 +67,25 @@ public final class GDALStoreTest {
         fail("Provider not found.");
     }
 
+    /**
+     * Returns the storage connector to the test file to use as input.
+     */
+    private static StorageConnector input() {
+        return new 
StorageConnector(GDALStoreTest.class.getResource("test.tiff"));
+    }
+
+    /**
+     * Tests providing the MIME type of an image.
+     *
+     * @throws DataStoreException if any error occurred.
+     */
+    @Test
+    public void testProbeContent() throws DataStoreException {
+        final var provider = new GDALStoreProvider();
+        ProbeResult result = provider.probeContent(input());
+        assertEquals("image/tiff", result.getMimeType());
+    }
+
     /**
      * Tests reading an indexed image. The test uses a small image with 1 band 
and indexed color palette.
      *
@@ -74,8 +95,7 @@ public final class GDALStoreTest {
     public void readIndexedImage() throws Exception {
         boolean foundGrid = false;
         boolean foundBand = false;
-        final var input = new 
StorageConnector(GDALStoreTest.class.getResource("test.tiff"));
-        try (GDALStore store = new GDALStore(new GDALStoreProvider(), input)) {
+        try (GDALStore store = new GDALStore(new GDALStoreProvider(), 
input())) {
             for (final Resource r : store.components()) {
                 assertFalse(foundGrid);
                 foundGrid = true;

Reply via email to