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 18e2964bf2afd0b03a178b8973bd0d545e013a3c
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Jul 12 15:18:05 2023 +0200

    `ScriptRunner.run(…)` shall receive an `InputStream` supplied by the caller
    instead of invoking `Class.getResourceAsStream(String)` as a convenience.
    This is necessary in JPMS (Jigsaw) context.
---
 .../sis/internal/metadata/sql/ScriptRunner.java    | 35 +++++++++++++++++-----
 .../org/apache/sis/metadata/sql/Installer.java     | 15 ++++++----
 .../java/org/apache/sis/test/sql/TestDatabase.java | 29 +++++++++---------
 .../sql/feature/SelectionClauseWriterTest.java     |  5 ++--
 .../sis/internal/sql/postgis/PostgresTest.java     | 28 +++++++++++++++--
 .../org/apache/sis/storage/sql/SQLStoreTest.java   | 29 +++++++++++++-----
 6 files changed, 101 insertions(+), 40 deletions(-)

diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
index 5ef740b0c8..ee703a1350 100644
--- 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
@@ -22,12 +22,15 @@ import java.util.Locale;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 import java.util.function.BiFunction;
+import java.io.FileNotFoundException;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.BufferedReader;
 import java.io.LineNumberReader;
 import java.io.InputStreamReader;
+import java.io.InputStream;
 import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
 import java.sql.Statement;
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -51,7 +54,7 @@ import org.apache.sis.util.resources.Errors;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.1
+ * @version 1.4
  * @since   0.7
  */
 public class ScriptRunner implements AutoCloseable {
@@ -440,24 +443,40 @@ public class ScriptRunner implements AutoCloseable {
     }
 
     /**
-     * Runs the SQL script of the given name in the same package than the 
given class.
-     * The script is presumed encoded in UTF-8.
+     * Runs the SQL script from the given (filename, input stream) pair.
+     * The file name is used only if an error needs to be reported.
+     * The stream content is presumed encoded in UTF-8 and the stream will be 
closed by this method.
+     * This method is intended to be invoked by code like this:
      *
-     * @param  loader    the class to use for loading the SQL script.
-     * @param  filename  the SQL script filename, relative to the {@code 
loader} package.
+     * {@snippet lang="java" :
+     *     run("myFile.sql", MyClass.getResourceAsStream("myFile.sql"));
+     * }
+     *
+     * <h4>Rational</h4>
+     * Because {@link Class#getResourceAsStream(String)} is caller-sensitive, 
it must be invoked
+     * from the module containing the resource. Invoking {@code 
getResourceAsStream(…)} from this
+     * {@code run(…)} method does not work even with a {@link Class} instance 
passed in argument.
+     *
+     * @param  filename  name of the SQL script being executed. This is used 
only for error reporting.
+     * @param  in  the stream to read. It will be closed by this method.
      * @return the number of rows added or modified as a result of the 
statement execution.
      * @throws IOException if an error occurred while reading the input.
      * @throws SQLException if an error occurred while executing a SQL 
statement.
      */
-    public final int run(final Class<?> loader, final String filename) throws 
IOException, SQLException {
-        try (BufferedReader in = new LineNumberReader(new 
InputStreamReader(loader.getResourceAsStream(filename), "UTF-8"))) {
-            return run(filename, in);
+    public final int run(final String filename, final InputStream in) throws 
IOException, SQLException {
+        if (in == null) {
+            throw new 
FileNotFoundException(Errors.format(Errors.Keys.FileNotFound_1, filename));
+        }
+        try (BufferedReader reader = new LineNumberReader(new 
InputStreamReader(in, StandardCharsets.UTF_8))) {
+            return run(filename, reader);
         }
     }
 
     /**
      * Runs the script from the given reader. Lines are read and grouped up to 
the
      * terminal {@value #END_OF_STATEMENT} character, then sent to the 
database.
+     * Note that contrarily to {@link #run(String, InputStream)},
+     * this method does <strong>not</strong> close the given reader.
      *
      * @param  filename  name of the SQL script being executed. This is used 
only for error reporting.
      * @param  in        the stream to read. It is caller's responsibility to 
close this reader.
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Installer.java 
b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Installer.java
index ee3831d080..9c0140c26b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Installer.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Installer.java
@@ -34,7 +34,7 @@ import org.apache.sis.util.StringBuilders;
  *       dependencies.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.4
  * @since   0.8
  */
 final class Installer extends ScriptRunner {
@@ -71,10 +71,15 @@ final class Installer extends ScriptRunner {
      * Runs the installation scripts.
      */
     public void run() throws IOException, SQLException {
-        run(Installer.class, "Citations.sql");
-        run(Installer.class, "Contents.sql");
-        run(Installer.class, "Metadata.sql");
-        run(Installer.class, "Referencing.sql");
+        final String[] scripts = {
+            "Citations.sql",
+            "Contents.sql",
+            "Metadata.sql",
+            "Referencing.sql"
+        };
+        for (final String filename : scripts) {
+            run(filename, Installer.class.getResourceAsStream(filename));
+        }
     }
 
     /**
diff --git 
a/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java 
b/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java
index a76ca252f6..d5bdcad545 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java
@@ -16,7 +16,10 @@
  */
 package org.apache.sis.test.sql;
 
+import java.util.List;
+import java.util.function.Supplier;
 import java.io.IOException;
+import java.io.InputStream;
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.Statement;
@@ -276,25 +279,23 @@ public class TestDatabase implements AutoCloseable {
     }
 
     /**
-     * Executes the given SQL statements, or statements from the given 
resource files.
-     * If an element from the {@code scripts} array begin by {@code "file:"}, 
then the part
-     * after {@code ":"} will be read as a resource file loaded by the given 
{@code loader}.
-     * Otherwise the script is executed as a SQL statement. Null element are 
ignored.
+     * Executes the given SQL statements, or statements from the given 
resource streams.
+     * Each element of the list shall be either a {@link String} or a {@code 
Supplier<InputStream>}.
+     * In the latter case, {@code Supplier.toString()} is used in error 
message if an error happens.
      *
-     * @param loader   a class in the package of the resource file. This is 
usually the test class.
-     * @param scripts  SQL statements or names of the SQL files to load and 
execute.
+     * @param  scripts  SQL statements or names of the SQL files to load and 
execute.
      * @throws IOException if an error occurred while reading a resource file.
      * @throws SQLException if an error occurred while executing a SQL 
statement.
+     * @throws ClassCastException if an element of the list is not a {@code 
String} or a {@code Supplier<InputStream>}.
      */
-    public void executeSQL(final Class<?> loader, final String... scripts) 
throws IOException, SQLException {
+    public final void executeSQL(final List<?> scripts) throws IOException, 
SQLException {
         try (Connection c = source.getConnection(); ScriptRunner r = new 
ScriptRunner(c, 1000)) {
-            for (final String sql : scripts) {
-                if (sql != null) {
-                    if (sql.startsWith("file:")) {
-                        r.run(loader, sql.substring(5));
-                    } else {
-                        r.run(sql);
-                    }
+            for (final Object sql : scripts) {
+                if (sql instanceof String) {
+                    r.run((String) sql);
+                } else {
+                    final var s = (Supplier<?>) sql;
+                    r.run(s.toString(), (InputStream) s.get());
                 }
             }
         }
diff --git 
a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/feature/SelectionClauseWriterTest.java
 
b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/feature/SelectionClauseWriterTest.java
index d89eb696de..b38b6c0ad8 100644
--- 
a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/feature/SelectionClauseWriterTest.java
+++ 
b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/feature/SelectionClauseWriterTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.sql.feature;
 
+import java.util.List;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStore;
@@ -73,9 +74,7 @@ public final class SelectionClauseWriterTest extends TestCase 
implements SchemaM
     @Test
     public void testOnDerby() throws Exception {
         try (TestDatabase db = TestDatabase.create("SQLStore")) {
-            db.executeSQL(SelectionClauseWriterTest.class,
-                    "CREATE TABLE TEST (ALPHA INTEGER, BETA INTEGER, GAMMA 
INTEGER, PI FLOAT);");
-
+            db.executeSQL(List.of("CREATE TABLE TEST (ALPHA INTEGER, BETA 
INTEGER, GAMMA INTEGER, PI FLOAT);"));
             final StorageConnector connector = new StorageConnector(db.source);
             connector.setOption(SchemaModifier.OPTION, this);
             try (DataStore store = new SQLStoreProvider().open(connector)) {
diff --git 
a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/PostgresTest.java
 
b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/PostgresTest.java
index de621ddf2e..1a114b6ad3 100644
--- 
a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/PostgresTest.java
+++ 
b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/PostgresTest.java
@@ -16,14 +16,17 @@
  */
 package org.apache.sis.internal.sql.postgis;
 
+import java.util.List;
+import java.util.stream.Stream;
+import java.util.function.Supplier;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.lang.reflect.Method;
-import java.util.stream.Stream;
 import org.opengis.geometry.Envelope;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.crs.ProjectedCRS;
@@ -65,11 +68,30 @@ import static org.opengis.test.Assert.assertInstanceOf;
  *
  * @author  Alexis Manin (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.3
+ * @version 1.4
  * @since   1.1
  */
 @DependsOn({RasterReaderTest.class, RasterWriterTest.class})
 public final class PostgresTest extends TestCase {
+    /**
+     * Creates a new test case.
+     */
+    public PostgresTest() {
+    }
+
+    /**
+     * Provides a stream for a resource in the same package than this class.
+     * The implementation invokes {@code getResourceAsStream(filename)}.
+     * This invocation must be done in this module because the invoked
+     * method is caller-sensitive.
+     */
+    private static Supplier<InputStream> resource(final String filename) {
+        return new Supplier<>() {
+            @Override public String toString() {return filename;}
+            @Override public InputStream get() {return 
PostgresTest.class.getResourceAsStream(filename);}
+        };
+    }
+
     /**
      * Tests {@link Postgres#parseVersion(String)}.
      */
@@ -89,7 +111,7 @@ public final class PostgresTest extends TestCase {
     @Test
     public void testSpatialFeatures() throws Exception {
         try (TestDatabase database = 
TestDatabase.createOnPostgreSQL(SQLStoreTest.SCHEMA, true)) {
-            database.executeSQL(PostgresTest.class, 
"file:SpatialFeatures.sql");
+            database.executeSQL(List.of(resource("SpatialFeatures.sql")));
             final StorageConnector connector = new 
StorageConnector(database.source);
             connector.setOption(OptionKey.GEOMETRY_LIBRARY, 
GeometryLibrary.JTS);
             final ResourceDefinition table = ResourceDefinition.table(null, 
SQLStoreTest.SCHEMA, "SpatialData");
diff --git 
a/storage/sis-sqlstore/src/test/java/org/apache/sis/storage/sql/SQLStoreTest.java
 
b/storage/sis-sqlstore/src/test/java/org/apache/sis/storage/sql/SQLStoreTest.java
index 53bb6abf66..94a763cbce 100644
--- 
a/storage/sis-sqlstore/src/test/java/org/apache/sis/storage/sql/SQLStoreTest.java
+++ 
b/storage/sis-sqlstore/src/test/java/org/apache/sis/storage/sql/SQLStoreTest.java
@@ -20,9 +20,12 @@ import java.util.Map;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.stream.Stream;
+import java.util.function.Supplier;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.io.InputStream;
 import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.storage.FeatureQuery;
 import org.apache.sis.storage.StorageConnector;
@@ -108,6 +111,19 @@ public final class SQLStoreTest extends TestOnAllDatabases 
{
         FF = DefaultFilterFactory.forFeatures();
     }
 
+    /**
+     * Provides a stream for a resource in the same package than this class.
+     * The implementation invokes {@code getResourceAsStream(filename)}.
+     * This invocation must be done in this module because the invoked
+     * method is caller-sensitive.
+     */
+    private static Supplier<InputStream> resource(final String filename) {
+        return new Supplier<>() {
+            @Override public String toString() {return filename;}
+            @Override public InputStream get() {return 
SQLStoreTest.class.getResourceAsStream(filename);}
+        };
+    }
+
     /**
      * Runs all tests on a single database software. A temporary schema is 
created at the beginning of this method
      * and deleted after all tests finished. The schema is created and 
populated by the {@code Features.sql} script.
@@ -118,14 +134,13 @@ public final class SQLStoreTest extends 
TestOnAllDatabases {
      */
     @Override
     protected void test(final TestDatabase database, final boolean noschema) 
throws Exception {
-        final String[] scripts = {
-            "CREATE SCHEMA " + SCHEMA + ';',
-            "file:Features.sql"
-        };
-        if (!noschema) {
-            scripts[0] = null;      // Omit the "CREATE SCHEMA" statement if 
the schema already exists.
+        final var scripts = new ArrayList<>(2);
+        if (noschema) {
+            scripts.add("CREATE SCHEMA " + SCHEMA + ';');
+            // Omit the "CREATE SCHEMA" statement if the schema already exists.
         }
-        database.executeSQL(SQLStoreTest.class, scripts);
+        scripts.add(resource("Features.sql"));
+        database.executeSQL(scripts);
         final StorageConnector connector = new 
StorageConnector(database.source);
         final ResourceDefinition table = ResourceDefinition.table(null, 
noschema ? null : SCHEMA, "Cities");
         testTableQuery(connector, table);

Reply via email to