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 23f06c63c307da91a3f87fd2d40986c30d327f7b
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue Oct 1 13:02:30 2024 +0200

    Make the GSF module independent of the GDAL module.
    It forces us to copy the `org.apache.sis.storage.panama` package,
    because we do not yet have a location for it that modules could share.
    However, we copy only a simplified version of that package in GSF for now.
---
 .../main/module-info.java                          |   3 -
 .../main/module-info.java                          |   3 -
 .../main/org/apache/sis/storage/gsf/GSF.java       |  34 +++---
 .../apache/sis/storage/gsf/GSFStoreProvider.java   |   6 +-
 .../sis/storage/gsf/panama/LibraryLoader.java      | 125 +++++++++++++++++++++
 .../sis/storage/gsf/panama/LibraryStatus.java}     |  29 +++--
 .../sis/storage/gsf/panama/NativeFunctions.java    |  84 ++++++++++++++
 .../sis/storage/gsf/panama/package-info.java}      |  20 +---
 8 files changed, 254 insertions(+), 50 deletions(-)

diff --git a/incubator/src/org.apache.sis.storage.gdal/main/module-info.java 
b/incubator/src/org.apache.sis.storage.gdal/main/module-info.java
index f191af4435..e4d87b9584 100644
--- a/incubator/src/org.apache.sis.storage.gdal/main/module-info.java
+++ b/incubator/src/org.apache.sis.storage.gdal/main/module-info.java
@@ -54,9 +54,6 @@ module org.apache.sis.storage.gdal {
 
     exports org.apache.sis.storage.gdal;
 
-    exports org.apache.sis.storage.panama to
-            org.apache.sis.storage.gsf;                 // In the "incubator" 
sub-project.
-
     provides org.apache.sis.storage.DataStoreProvider
             with org.apache.sis.storage.gdal.GDALStoreProvider;
 }
diff --git a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java 
b/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
index d006a4f811..143d3bc638 100644
--- a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
+++ b/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
@@ -25,9 +25,6 @@ module org.apache.sis.storage.gsf {
     requires transitive org.apache.sis.referencing;
     requires transitive org.apache.sis.storage;
 
-    // For internal usage only.
-    requires org.apache.sis.storage.gdal;
-
     provides org.apache.sis.storage.DataStoreProvider
             with org.apache.sis.storage.gsf.GSFStoreProvider;
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
index 1a00375184..e08338175f 100644
--- 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSF.java
@@ -17,7 +17,6 @@
 package org.apache.sis.storage.gsf;
 
 import java.lang.foreign.AddressLayout;
-import java.lang.foreign.Arena;
 import java.lang.foreign.FunctionDescriptor;
 import java.lang.foreign.MemoryLayout;
 import java.lang.foreign.MemorySegment;
@@ -30,9 +29,9 @@ import java.util.Optional;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.panama.LibraryLoader;
-import org.apache.sis.storage.panama.LibraryStatus;
-import org.apache.sis.storage.panama.NativeFunctions;
+import org.apache.sis.storage.gsf.panama.LibraryLoader;
+import org.apache.sis.storage.gsf.panama.LibraryStatus;
+import org.apache.sis.storage.gsf.panama.NativeFunctions;
 import org.apache.sis.util.logging.Logging;
 
 /**
@@ -680,11 +679,13 @@ public class GSF extends NativeFunctions {
 
     /**
      * Creates the handles for all <abbr>GSF</abbr> functions which will be 
needed.
+     * This constructor is public for {@link LibraryLoader} purpose only.
+     * <strong>Do not use.</strong>
      *
      * @param  loader  the object used for loading the library.
      * @throws NoSuchElementException if a <abbr>GSF</abbr> function has not 
been found in the library.
      */
-    private GSF(final LibraryLoader<GSF> loader) {
+    public GSF(final LibraryLoader loader) {
         super(loader);
 
         final FunctionDescriptor p = FunctionDescriptor.of(GSF.C_POINTER);
@@ -729,10 +730,6 @@ public class GSF extends NativeFunctions {
         gsfGetPositionOffsets                   = 
lookup("gsfGetPositionOffsets",                   
FunctionDescriptor.of(GSF.C_POINTER, Position.LAYOUT, Position.LAYOUT, 
GSF.C_DOUBLE, GSF.C_DOUBLE));
     }
 
-    public Arena getArena() {
-        return arena();
-    }
-
     public int open(MemorySegment filename, int mode, MemorySegment handle) 
throws Throwable {
         return (int) gsfOpen.invokeExact(filename, mode, handle);
     }
@@ -883,7 +880,7 @@ public class GSF extends NativeFunctions {
     /**
      * Raise an exception if code is an error code.
      */
-    public void catchError(int error) throws GSFException {
+    public static void catchError(int error) throws GSFException {
         if (error == 0) return;
         String message = ERRORCODES.get(error);
         if (message == null) message = "UNKNOWN ERROR CODE";
@@ -899,13 +896,13 @@ public class GSF extends NativeFunctions {
      *         In such case, the caller must be synchronized and {@link 
#global} must be initially null.
      * @return the library loader for <abbr>GSF</abbr>.
      */
-    private static LibraryLoader<GSF> load(final boolean now) {
-        final var loader = new LibraryLoader<>(GSF::new);
+    private static LibraryLoader load(final boolean now) {
+        final var loader = new LibraryLoader();
         if (now) {
             try {
-                global = loader.global("gsf");
+                global = loader.global();
             } finally {
-                globalStatus = loader.status();
+                globalStatus = loader.status;
             }
             if (global != null) {
                 if (GSFStoreProvider.LOGGER.isLoggable(Level.CONFIG)) {
@@ -945,9 +942,11 @@ public class GSF extends NativeFunctions {
      */
     static synchronized GSF global() throws DataStoreException {
         if (globalStatus == null) {
-            load(true).validate(GSFStoreProvider.NAME);
+            load(true).validate();
+        }
+        if (globalStatus != LibraryStatus.LOADED) {
+            throw new DataStoreException("GSF not loaded.");
         }
-        globalStatus.report(GSFStoreProvider.NAME, null);
         return global;
     }
 
@@ -959,7 +958,7 @@ public class GSF extends NativeFunctions {
      */
     static synchronized Optional<GSF> tryGlobal(final String caller) {
         if (globalStatus == null) {
-            load(true).getError(GSFStoreProvider.NAME).ifPresent((record) -> 
log(caller, record));
+            load(true).getError().ifPresent((record) -> log(caller, record));
         }
         return Optional.ofNullable(global);
     }
@@ -973,5 +972,4 @@ public class GSF extends NativeFunctions {
     private static void log(final String caller, final LogRecord record) {
         Logging.completeAndLog(GSFStoreProvider.LOGGER, 
GSFStoreProvider.class, caller, record);
     }
-
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStoreProvider.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStoreProvider.java
index 4be4cdd695..f74d71e125 100644
--- 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStoreProvider.java
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/GSFStoreProvider.java
@@ -29,7 +29,7 @@ import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.base.StoreMetadata;
 import org.apache.sis.storage.base.Capability;
 import org.apache.sis.storage.base.URIDataStoreProvider;
-import org.apache.sis.storage.panama.LibraryStatus;
+import org.apache.sis.storage.gsf.panama.LibraryStatus;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.system.Cleaners;
@@ -114,7 +114,9 @@ public class GSFStoreProvider extends DataStoreProvider {
         if (status == null) {
             return GSF.global();        // Fetch each time (no cache) because 
may have changed outside this class.
         }
-        status.report(NAME, null);      // Should never return if 
`nativeFunctions` is null.
+        if (status != LibraryStatus.LOADED) {
+            throw new DataStoreException("GSF not loaded.");
+        }
         return nativeFunctions;
     }
 
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/LibraryLoader.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/LibraryLoader.java
new file mode 100644
index 0000000000..b42ebfeaaa
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/LibraryLoader.java
@@ -0,0 +1,125 @@
+/*
+ * 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.gsf.panama;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.lang.foreign.Arena;
+import java.lang.foreign.SymbolLookup;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.gsf.GSF;
+import org.apache.sis.system.Shutdown;
+import org.apache.sis.util.Exceptions;
+
+
+/**
+ * A helper class for loading a native library.
+ *
+ * @see org.apache.sis.storage.panama.LibraryLoader
+ */
+public final class LibraryLoader {
+    /**
+     * Value to assign to {@link NativeFunctions#arena}.
+     */
+    Arena arena;
+
+    /**
+     * Value to assign to {@link NativeFunctions#symbols}.
+     */
+    SymbolLookup symbols;
+
+    /**
+     * Whether the library has been found.
+     */
+    public LibraryStatus status;
+
+    /**
+     * Cause of failure to load the library, or {@code null} if none.
+     */
+    private RuntimeException error;
+
+    /**
+     * Creates a new instance.
+     */
+    public LibraryLoader() {
+    }
+
+    /**
+     * Loads the native library from the given file.
+     * Callers should register the returned instance in a {@link 
java.lang.ref.Cleaner}.
+     */
+    @SuppressWarnings("restricted")
+    public GSF load(final Path library) {
+        status = LibraryStatus.CANNOT_LOAD_LIBRARY;
+        arena  = Arena.ofShared();
+        final GSF instance;
+        try {
+            symbols  = SymbolLookup.libraryLookup(library, arena);
+            status   = LibraryStatus.FUNCTION_NOT_FOUND;
+            instance = new GSF(this);
+            status   = LibraryStatus.LOADED;
+        } catch (Throwable e) {
+            arena.close();
+            throw e;
+        }
+        return instance;
+    }
+
+    /**
+     * Searches the native library in the default library path.
+     */
+    @SuppressWarnings("restricted")
+    public GSF global() {
+        status = LibraryStatus.CANNOT_LOAD_LIBRARY;
+        String filename = (File.separatorChar == '\\') ? "gsf.dll" : 
"libgsf.so";
+        try {
+            symbols = SymbolLookup.libraryLookup(filename, Arena.global());
+            GSF instance = new GSF(this);
+            status = LibraryStatus.LOADED;
+            Shutdown.register(instance);
+            return instance;
+        } catch (RuntimeException e) {
+            error = e;
+            return null;
+        }
+    }
+
+    /**
+     * Throws an exception if the loading of the native library failed.
+     */
+    public void validate() throws DataStoreException {
+        if (error != null) {
+            throw new DataStoreException(error);
+        }
+    }
+
+    /**
+     * Returns the error as a log message.
+     */
+    public Optional<LogRecord> getError() {
+        if (error == null) {
+            return Optional.empty();
+        }
+        String msg = "Cannot initialize the GSF library.";
+        var record = new LogRecord(Level.CONFIG, 
Exceptions.formatChainedMessages(null, msg, error));
+        record.setThrown(error);
+        return Optional.of(record);
+    }
+}
diff --git a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/LibraryStatus.java
similarity index 56%
copy from incubator/src/org.apache.sis.storage.gsf/main/module-info.java
copy to 
incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/LibraryStatus.java
index d006a4f811..9b21d9afeb 100644
--- a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/LibraryStatus.java
@@ -14,20 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.sis.storage.gsf.panama;
+
 
 /**
- * LibGSF Panama binding.
+ * Status of the native library.
  *
- * @author Johann Sorel (Geomatys)
+ * @see org.apache.sis.storage.panama.LibraryStatus
  */
-module org.apache.sis.storage.gsf {
-    // Dependencies used in public API.
-    requires transitive org.apache.sis.referencing;
-    requires transitive org.apache.sis.storage;
+public enum LibraryStatus {
+    /**
+     * The native library is ready for use.
+     */
+    LOADED,
 
-    // For internal usage only.
-    requires org.apache.sis.storage.gdal;
+    /**
+     * The native library has not been found or cannot be loaded. Note: this 
is a merge of
+     * {@link org.apache.sis.storage.panama.LibraryStatus#LIBRARY_NOT_FOUND} 
and
+     * {@link org.apache.sis.storage.panama.LibraryStatus#UNAUTHORIZED}.
+     */
+    CANNOT_LOAD_LIBRARY,
 
-    provides org.apache.sis.storage.DataStoreProvider
-            with org.apache.sis.storage.gsf.GSFStoreProvider;
+    /**
+     * The native library was found, but not symbol that we searched.
+     */
+    FUNCTION_NOT_FOUND
 }
diff --git 
a/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/NativeFunctions.java
 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/NativeFunctions.java
new file mode 100644
index 0000000000..41e107b886
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/NativeFunctions.java
@@ -0,0 +1,84 @@
+/*
+ * 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.gsf.panama;
+
+import java.util.concurrent.Callable;
+import java.lang.foreign.Arena;
+import java.lang.foreign.Linker;
+import java.lang.foreign.SymbolLookup;
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.invoke.MethodHandle;
+
+
+/**
+ * Base class for sets of method handles to native functions.
+ *
+ * @see org.apache.sis.storage.panama.NativeFunctions
+ */
+public abstract class NativeFunctions implements Runnable, Callable<Object> {
+    /**
+     * The arena used for loading the library, or {@code null} for the global 
arena.
+     */
+    private final Arena arena;
+
+    /**
+     * The lookup for retrieving the address of a symbol in the native library.
+     */
+    public final SymbolLookup symbols;
+
+    /**
+     * The linker to use for fetching method handles from the {@linkplain 
#symbols}.
+     */
+    public final Linker linker;
+
+    /**
+     * Creates a new set of handles to native functions.
+     */
+    protected NativeFunctions(final LibraryLoader loader) {
+        arena   = loader.arena;
+        symbols = loader.symbols;
+        linker  = Linker.nativeLinker();
+    }
+
+    /**
+     * Returns the method handler for the <abbr>GSF</abbr> function of given 
name and signature.
+     */
+    @SuppressWarnings("restricted")
+    protected final MethodHandle lookup(final String function, final 
FunctionDescriptor signature) {
+        return symbols.find(function).map((method) -> 
linker.downcallHandle(method, signature)).orElseThrow();
+    }
+
+    /**
+     * Unloads the native library. If the arena is global,
+     * then this method should not be invoked before <abbr>JVM</abbr> shutdown.
+     */
+    @Override
+    public void run() {
+        if (arena != null) {
+            arena.close();
+        }
+    }
+
+    /**
+     * Synonymous of {@link #run()}, used in shutdown hook.
+     */
+    @Override
+    public final Object call() {
+        run();
+        return null;
+    }
+}
diff --git a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/package-info.java
similarity index 61%
copy from incubator/src/org.apache.sis.storage.gsf/main/module-info.java
copy to 
incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/package-info.java
index d006a4f811..ce1282d7de 100644
--- a/incubator/src/org.apache.sis.storage.gsf/main/module-info.java
+++ 
b/incubator/src/org.apache.sis.storage.gsf/main/org/apache/sis/storage/gsf/panama/package-info.java
@@ -16,18 +16,10 @@
  */
 
 /**
- * LibGSF Panama binding.
- *
- * @author Johann Sorel (Geomatys)
+ * Partial (simplified) copy of the {@code org.apache.sis.storage.panama} 
package.
+ * This copy is for keeping this <abbr>GSF</abbr> module independent from the 
<abbr>GDAL</abbr> module,
+ * because we do not yet have a location where to put the {@code 
org.apache.sis.storage.panama} package
+ * in a way where it can be reused by other modules. This package will be 
deleted in a future version
+ * if we find a home for the {@code org.apache.sis.storage.panama} package.
  */
-module org.apache.sis.storage.gsf {
-    // Dependencies used in public API.
-    requires transitive org.apache.sis.referencing;
-    requires transitive org.apache.sis.storage;
-
-    // For internal usage only.
-    requires org.apache.sis.storage.gdal;
-
-    provides org.apache.sis.storage.DataStoreProvider
-            with org.apache.sis.storage.gsf.GSFStoreProvider;
-}
+package org.apache.sis.storage.gsf.panama;

Reply via email to