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 450ad41fa3f3d11a0af7081702e9e065ad2f862a Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Jul 26 11:09:55 2024 +0200 Move the Apache-licensed Java code of "non-free" modules from SVN repository. It does not include the EPSG data, which are subject to EPSG terms of use. --- .../apache/sis/buildtools/gradle/Conventions.java | 3 +- .../apache/sis/buildtools/gradle/Dependency.java | 2 + .../sis/buildtools/gradle/ModularCompilation.java | 2 +- netbeans-project/nbproject/project.properties | 5 + optional/build.gradle.kts | 77 ++++++- .../main/META-INF/NOTICE | 1 + .../org.apache.sis.setup.InstallationResources | 4 + .../main/module-info.java | 43 ++++ .../sis/resources/embedded/EmbeddedResources.java | 153 ++++++++++++++ .../sis/resources/embedded/package-info.java | 35 ++++ .../resources/embedded/EmbeddedResourcesTest.java | 125 ++++++++++++ .../apache/sis/resources/embedded/Generator.java | 222 +++++++++++++++++++++ .../main/META-INF/NOTICE | 10 + .../org.apache.sis.setup.InstallationResources | 4 + .../main/module-info.java | 41 ++++ .../sis/referencing/factory/sql/epsg/.gitignore | 7 + .../sis/referencing/factory/sql/epsg/README.md | 23 +++ .../factory/sql/epsg/ScriptProvider.java | 104 ++++++++++ .../referencing/factory/sql/epsg/package-info.java | 37 ++++ .../factory/sql/epsg/DataScriptFormatter.java | 0 .../factory/sql/epsg/DataScriptFormatterTest.java | 2 +- .../referencing/factory/sql/epsg/DebugTools.sql | 0 .../sis/referencing/factory/sql/epsg/README.md | 0 .../factory/sql/epsg/ScriptProviderTest.java | 84 ++++++++ 24 files changed, 977 insertions(+), 7 deletions(-) diff --git a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Conventions.java b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Conventions.java index 471f16d67c..445979d437 100644 --- a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Conventions.java +++ b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Conventions.java @@ -198,7 +198,8 @@ abstract class Conventions { } Files.createDirectories(target.getParent()); try { - Files.createLink(target, source); + // `toRealPath()` is necessary, otherwise symbolic links are reproduced verbatim and become broken. + Files.createLink(target, source.toRealPath()); } catch (UnsupportedOperationException e) { Files.copy(source, target, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); } diff --git a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Dependency.java b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Dependency.java index 4842e18481..d11e9bd05e 100644 --- a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Dependency.java +++ b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/Dependency.java @@ -67,6 +67,8 @@ public final class Dependency { Map.entry("profile.japan", "profiles:sis-japan-profile"), Map.entry("console", "application:sis-console"), Map.entry("openoffice", "application:sis-openoffice"), + Map.entry("epsg", "non-free:sis-epsg"), // Optional. + Map.entry("database", "non-free:sis-embedded-data"), // Optional. Map.entry("gui", "application:sis-javafx"), // Optional. Map.entry("cql", "core:sis-cql"), // Incubator. Map.entry("storage.shapefile", "core:sis-shapefile"), diff --git a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/ModularCompilation.java b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/ModularCompilation.java index 3f6486cdf3..bbce02b655 100644 --- a/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/ModularCompilation.java +++ b/buildSrc/src/main/java/org/apache/sis/buildtools/gradle/ModularCompilation.java @@ -253,6 +253,6 @@ final class ModularCompilation extends Conventions { } String ext = resource.getName(); ext = ext.substring(ext.lastIndexOf('.') + 1); - return !EXCLUDE_RESOURCES.contains(ext); + return !EXCLUDE_RESOURCES.contains(ext) || resource.getName().equals("LICENSE.html"); } } diff --git a/netbeans-project/nbproject/project.properties b/netbeans-project/nbproject/project.properties index 1dcac2e5eb..cdadf6edb2 100644 --- a/netbeans-project/nbproject/project.properties +++ b/netbeans-project/nbproject/project.properties @@ -70,6 +70,8 @@ modules.list = org.apache.sis.cloud.aws,\ org.apache.sis.profile.japan,\ org.apache.sis.referencing,\ org.apache.sis.referencing.gazetteer,\ + org.apache.sis.referencing.epsg,\ + org.apache.sis.referencing.database,\ org.apache.sis.storage,\ org.apache.sis.storage.earthobservation,\ org.apache.sis.storage.geotiff,\ @@ -87,6 +89,8 @@ read.options = --add-reads org.apache.sis.cloud.aws=org.junit.jupiter.api,junit --add-reads org.apache.sis.profile.japan=org.junit.jupiter.api,junit \ --add-reads org.apache.sis.referencing=org.junit.jupiter.api,junit \ --add-reads org.apache.sis.referencing.gazetteer=org.junit.jupiter.api,junit \ + --add-reads org.apache.sis.referencing.epsg=org.junit.jupiter.api,junit \ + --add-reads org.apache.sis.referencing.database=org.apache.sis.referencing.epsg,org.junit.jupiter.api,junit \ --add-reads org.apache.sis.storage=org.junit.jupiter.api,junit \ --add-reads org.apache.sis.storage.gimi=org.junit.jupiter.api,junit \ --add-reads org.apache.sis.storage.coveragejson=org.junit.jupiter.api,junit \ @@ -111,6 +115,7 @@ test.options = --add-modules jama,GeographicLib.Java,\ --add-exports org.apache.sis.metadata/org.apache.sis.xml.privy=org.apache.sis.storage.geotiff \ --add-exports org.apache.sis.metadata/org.apache.sis.xml.bind.gcx=org.apache.sis.referencing \ --add-exports org.apache.sis.metadata/org.apache.sis.metadata.privy=org.apache.sis.referencing.gazetteer \ + --add-exports org.apache.sis.metadata/org.apache.sis.metadata.sql.privy=org.apache.sis.referencing.epsg \ --add-exports org.apache.sis.referencing/org.apache.sis.referencing.internal=org.apache.sis.openoffice \ --add-exports org.apache.sis.feature/org.apache.sis.feature.privy=org.apache.sis.storage.sql \ --add-exports org.apache.sis.feature/org.apache.sis.geometry.wrapper.jts=org.apache.sis.storage.sql,org.apache.sis.portrayal.map \ diff --git a/optional/build.gradle.kts b/optional/build.gradle.kts index 1a7be341ac..3393fafdc7 100644 --- a/optional/build.gradle.kts +++ b/optional/build.gradle.kts @@ -68,8 +68,8 @@ dependencies { runtimeOnly (files("${mainDepPath}/org.apache.sis.storage.geotiff")) runtimeOnly (files("${mainDepPath}/org.apache.sis.storage.earthobservation")) api (files("${mainDepPath}/org.apache.sis.portrayal")) - runtimeOnly (drivers.derby.core) - runtimeOnly (drivers.derby.tools) + api (drivers.derby.core) + api (drivers.derby.tools) // Test dependencies testImplementation(tests.junit5) @@ -92,6 +92,7 @@ tasks.compileTestJava { srcDir.list().forEach { addRead(options.compilerArgs, it, "org.apache.sis.test.optional,org.junit.jupiter.api") } + addRead(options.compilerArgs, "org.apache.sis.referencing.database", "org.apache.sis.referencing.epsg"); } /* @@ -127,8 +128,15 @@ fun patchModuleWithTests(args : MutableList<String>, module : String) { */ fun patchForTests(args : MutableList<String>) { patchModuleWithTests(args, "org.apache.sis.util") + patchModuleWithTests(args, "org.apache.sis.metadata") patchModuleWithTests(args, "org.apache.sis.feature") - addExport(args, "org.apache.sis.util", "org.apache.sis.test", "org.apache.sis.gui") + // ――――――――――――― Module name ――――――――――――――――――――――― Package to export ――――――――――――――― + addExport(args, "org.apache.sis.util", "org.apache.sis.test", + "org.apache.sis.gui," + + "org.apache.sis.referencing.epsg," + + "org.apache.sis.referencing.database") + addExport(args, "org.apache.sis.metadata", "org.apache.sis.metadata.sql.privy", + "org.apache.sis.referencing.epsg") } /* @@ -166,6 +174,8 @@ tasks.test { addRead (args, "org.apache.sis.util", "ALL-UNNAMED") addExport(args, "org.apache.sis.util", "org.apache.sis.test", "ALL-UNNAMED") addExport(args, "org.apache.sis.gui", "org.apache.sis.gui.internal", "ALL-UNNAMED") + args.add("--add-opens") + args.add("org.apache.sis.metadata/org.apache.sis.metadata.sql=org.apache.sis.referencing.database") setAllJvmArgs(args) testLogging { events("FAILED", "STANDARD_OUT", "STANDARD_ERROR") @@ -192,6 +202,65 @@ tasks.jar { */ publishing { publications { + create<MavenPublication>("epsg") { + var module = "org.apache.sis.referencing.epsg" + groupId = "org.apache.sis.non-free" + artifactId = "sis-epsg" + artifact(layout.buildDirectory.file("libs/${module}.jar")) + artifact(layout.buildDirectory.file("docs/${module}-sources.jar")) {classifier = "sources"} + artifact(layout.buildDirectory.file("docs/${module}-javadoc.jar")) {classifier = "javadoc"} + pom { + name = "EPSG dataset for Apache SIS" + description = "The EPSG geodetic dataset provides definitions for thousands of Coordinate Reference Systems (CRS), " + + "together with parameter values for thousands of Coordinate Operations between various pairs of CRS. " + + "This module contains the SQL scripts for creating a local copy of EPSG geodetic dataset. " + + "EPSG is maintained by the IOGP Surveying & Positioning Committee and reproduced in this module " + + "with same content. See https://epsg.org/ for more information." + licenses { + license { + // Not included in source code, user must download explicitly. + // name = "EPSG terms of use" + url = "https://epsg.org/terms-of-use.html" + distribution = "manual" + } + license { + // name = "Apache License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + distribution = "repo" + } + } + } + } + create<MavenPublication>("database") { + var module = "org.apache.sis.referencing.database" + groupId = "org.apache.sis.non-free" + artifactId = "sis-embedded-data" + artifact(layout.buildDirectory.file("libs/${module}.jar")) + artifact(layout.buildDirectory.file("docs/${module}-sources.jar")) {classifier = "sources"} + artifact(layout.buildDirectory.file("docs/${module}-javadoc.jar")) {classifier = "javadoc"} + pom { + name = "Data in embedded environment" + description = "Provides non-free data, including the EPSG geodetic dataset, in a single read-only JAR file. " + + "This module contains a copy of EPSG geodetic dataset in an embedded Apache Derby database. " + + "Having this artifact on the module path avoid the need to set the 'SIS_DATA' environment variable " + + "for using the Coordinate Reference Systems (CRS) and Coordinate Operations defined by EPSG. " + + "EPSG is maintained by the IOGP Surveying & Positioning Committee and reproduced in this module " + + "with same content. See https://epsg.org/ for more information." + licenses { + license { + // Not included in source code, user must download explicitly. + // name = "EPSG terms of use" + url = "https://epsg.org/terms-of-use.html" + distribution = "manual" + } + license { + // name = "Apache License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + distribution = "repo" + } + } + } + } create<MavenPublication>("gui") { var module = "org.apache.sis.gui" groupId = "org.apache.sis.application" @@ -200,7 +269,7 @@ publishing { artifact(layout.buildDirectory.file("docs/${module}-sources.jar")) {classifier = "sources"} artifact(layout.buildDirectory.file("docs/${module}-javadoc.jar")) {classifier = "javadoc"} pom { - name = "Apache SIS application for JavaFX (optional)" + name = "Apache SIS application for JavaFX" description = "Client application for JavaFX. " + "This module requires the JavaFX environment to be pre-installed. " + "See https://openjfx.io/openjfx-docs/#install-javafx for details." diff --git a/optional/src/org.apache.sis.referencing.database/main/META-INF/NOTICE b/optional/src/org.apache.sis.referencing.database/main/META-INF/NOTICE new file mode 120000 index 0000000000..9a752793d4 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.database/main/META-INF/NOTICE @@ -0,0 +1 @@ +../../../org.apache.sis.referencing.epsg/main/META-INF/NOTICE \ No newline at end of file diff --git a/optional/src/org.apache.sis.referencing.database/main/META-INF/services/org.apache.sis.setup.InstallationResources b/optional/src/org.apache.sis.referencing.database/main/META-INF/services/org.apache.sis.setup.InstallationResources new file mode 100644 index 0000000000..ade1840ca9 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.database/main/META-INF/services/org.apache.sis.setup.InstallationResources @@ -0,0 +1,4 @@ +# Workaround for Maven bug https://issues.apache.org/jira/browse/MNG-7855 +# The content of this file is automatically derived from module-info.class file. +# Should be used only if the JAR file was on class-path rather than module-path. +org.apache.sis.resources.embedded.EmbeddedResources diff --git a/optional/src/org.apache.sis.referencing.database/main/module-info.java b/optional/src/org.apache.sis.referencing.database/main/module-info.java new file mode 100644 index 0000000000..cb55c1261a --- /dev/null +++ b/optional/src/org.apache.sis.referencing.database/main/module-info.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/** + * Embedded EPSG geodetic dataset. + * This module contains the data of the {@code org.apache.sis.referencing.epsg} module, + * but in a form that does not require the installation of a local database. + * + * <h2>Licensing</h2> + * EPSG is maintained by the <a href="https://www.iogp.org/">International Association of Oil and Gas Producers</a> + * (IOGP) Surveying & Positioning Committee and is subject to <a href="https://epsg.org/terms-of-use.html">EPSG + * terms of use</a>. This module is not included in the Apache <abbr>SIS</abbr> distribution of convenience binaries, + * and the source code contains only the Java classes without the <abbr>EPSG</abbr> data. For use in an application, + * see <a href="https://sis.apache.org/epsg.html">How to use EPSG geodetic dataset</a> on the <abbr>SIS</abbr> web site. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 0.7 + */ +module org.apache.sis.referencing.database { + requires transitive org.apache.sis.referencing; + requires org.apache.derby.tools; + + exports org.apache.sis.resources.embedded; + + uses org.apache.sis.setup.InstallationResources; + provides org.apache.sis.setup.InstallationResources + with org.apache.sis.resources.embedded.EmbeddedResources; +} diff --git a/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/EmbeddedResources.java b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/EmbeddedResources.java new file mode 100644 index 0000000000..fade9c8e45 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/EmbeddedResources.java @@ -0,0 +1,153 @@ +/* + * 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.resources.embedded; + +import java.util.Set; +import java.util.Collections; +import java.util.Locale; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import javax.sql.DataSource; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.apache.sis.util.privy.MetadataServices; +import org.apache.sis.metadata.sql.privy.Initializer; +import org.apache.sis.setup.InstallationResources; +import org.apache.sis.util.resources.Errors; + + +/** + * Provides an embedded database for the EPSG geodetic dataset and other resources. + * Provides also a copy of the <a href="https://epsg.org/terms-of-use.html">EPSG terms of use</a>, + * which should be accepted by users before the EPSG dataset can be installed. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 0.8 + * + * @see <a href="https://epsg.org/">https://epsg.org/</a> + */ +public class EmbeddedResources extends InstallationResources { + /** + * The name of the database embedded in the JAR file. + * It must be an invalid package name, because otherwise the Java Platform Module System (JPMS) enforces + * encapsulation in the same way as non-exported packages, which makes the database inaccessible to Derby. + * This naming trick is part of JPMS specification, so it should be reliable. + */ + static final String EMBEDDED_DATABASE = "spatial-metadata"; + + /** + * Creates a new provider for connections to the embedded database. + */ + public EmbeddedResources() { + } + + /** + * Returns the pseudo-authority, which is {@code "Embedded"}. + * + * @return {@code "Embedded"} pseudo-authority. + */ + @Override + public Set<String> getAuthorities() { + return Collections.singleton(MetadataServices.EMBEDDED); + } + + /** + * Verifies that the given authority is the expected values. + */ + private void verifyAuthority(final String authority) { + if (!MetadataServices.EMBEDDED.equalsIgnoreCase(authority)) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "authority", authority)); + } + } + + /** + * Returns the license of embedded data. + * + * @param authority shall be {@code "Embedded"}. + * @param locale the preferred locale for the terms of use. + * @param mimeType either {@code "text/plain"} or {@code "text/html"}. + * @return the terms of use in plain text or HTML, or {@code null} if none. + * @throws IllegalArgumentException if the given {@code authority} argument is not the expected values. + * @throws IOException if an error occurred while reading the license file. + */ + @Override + public String getLicense(String authority, Locale locale, String mimeType) throws IOException { + verifyAuthority(authority); + final String filename; + if ("text/plain".equalsIgnoreCase(mimeType)) { + filename = "LICENSE.txt"; + } else if ("text/html".equalsIgnoreCase(mimeType)) { + filename = "LICENSE.html"; + } else { + return null; + } + final StringBuilder buffer = new StringBuilder(); + final String lineSeparator = System.lineSeparator(); + try (BufferedReader in = new BufferedReader(new InputStreamReader( + EmbeddedResources.class.getResourceAsStream(filename), "UTF-8"))) + { + String line; + while ((line = in.readLine()) != null) { + buffer.append(line).append(lineSeparator); + } + } + return buffer.toString(); + } + + /** + * Returns the data source name, which is {@code "SpatialMetadata"}. + * + * @param authority shall be {@code "Embedded"}. + * @return {@code "SpatialMetadata"}. + */ + @Override + public String[] getResourceNames(String authority) { + verifyAuthority(authority); + return new String[] {Initializer.DATABASE}; + } + + /** + * Returns the data source for embedded database. + * + * @param authority shall be {@code "Embedded"}. + * @param index shall be 0. + * @return the embedded data source. + */ + @Override + public DataSource getResource(String authority, int index) { + verifyAuthority(authority); + final EmbeddedDataSource ds = new EmbeddedDataSource(); + ds.setDataSourceName(Initializer.DATABASE); + ds.setDatabaseName("classpath:SIS_DATA/Databases/" + EMBEDDED_DATABASE); + return ds; + } + + /** + * Unconditionally throws an exception since the embedded database is not provided as SQL scripts. + * + * @param authority shall be {@code "Embedded"}. + * @param resource shall be 0. + * @return never return. + * @throws IOException always thrown. + */ + @Override + public BufferedReader openScript(String authority, int resource) throws IOException { + verifyAuthority(authority); + throw new IOException(Errors.format(Errors.Keys.CanNotConvertFromType_2, DataSource.class, BufferedReader.class)); + } +} diff --git a/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/package-info.java b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/package-info.java new file mode 100644 index 0000000000..2ccb718065 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.database/main/org/apache/sis/resources/embedded/package-info.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/** + * Provides non-free data, including the EPSG geodetic dataset, in a single read-only JAR file. + * This module contains a copy of EPSG geodetic dataset in an embedded Apache Derby database. + * Having this module on the module-path avoid the need to set the {@code SIS_DATA} environment variable + * for using the Coordinate Reference Systems (<abbr>CRS</abbr>) and Coordinate Operations defined by EPSG. + * + * <h2>Licensing</h2> + * EPSG is maintained by the <a href="https://www.iogp.org/">International Association of Oil and Gas Producers</a> + * (IOGP) Surveying & Positioning Committee and is subject to <a href="https://epsg.org/terms-of-use.html">EPSG + * terms of use</a>. This module is not included in the Apache <abbr>SIS</abbr> distribution of convenience binaries, + * and the source code contains only the Java classes without the <abbr>EPSG</abbr> data. For use in an application, + * see <a href="https://sis.apache.org/epsg.html">How to use EPSG geodetic dataset</a> on the <abbr>SIS</abbr> web site. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 0.8 + */ +package org.apache.sis.resources.embedded; diff --git a/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/EmbeddedResourcesTest.java b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/EmbeddedResourcesTest.java new file mode 100644 index 0000000000..4809fbd9e9 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/EmbeddedResourcesTest.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.resources.embedded; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.ServiceLoader; +import javax.sql.DataSource; +import org.opengis.util.FactoryException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.apache.sis.setup.InstallationResources; +import org.apache.sis.metadata.sql.privy.Initializer; +import org.apache.sis.system.DataDirectory; +import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.factory.sql.epsg.ScriptProvider; + +// Test dependencies +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import org.apache.sis.test.TestUtilities; + + +/** + * Tests {@link EmbeddedResources}. + * + * @author Martin Desruisseaux (Geomatys) + */ +public final strictfp class EmbeddedResourcesTest { + /** + * Whether the database has been created. + */ + private static boolean databaseCreated; + + /** + * Returns the {@link EmbeddedResources} instance declared in the {@code META-INF/services/} directory. + * The provider may coexist with providers defined in other modules, so we need to filter them. + */ + private static synchronized InstallationResources getInstance() { + assumeTrue(ScriptProvider.class.getResource("LICENSE.txt") != null, + "EPSG resources not found. See `README.md` for manual installation."); + + if (!databaseCreated) try { + new Generator().run(); + databaseCreated = true; + } catch (Exception e) { + throw new AssertionError(e); + } + + InstallationResources provider = null; + for (InstallationResources candidate : ServiceLoader.load(InstallationResources.class)) { + if (candidate instanceof EmbeddedResources) { + assertNull(provider, "Expected only one instance."); + provider = candidate; + } + } + assertNotNull(provider, "Expected an instance."); + return provider; + } + + /** + * Tests fetching the licenses. + * + * @throws IOException if an error occurred while reading a license. + */ +// @Test + public void testLicences() throws IOException { + final InstallationResources provider = getInstance(); + assertTrue(provider.getLicense("Embedded", null, "text/plain").contains("IOGP")); + assertTrue(provider.getLicense("Embedded", null, "text/html" ).contains("IOGP")); + } + + /** + * Tests connecting to the database. + * + * @throws Exception if an error occurred while fetching the data source, or connecting to the database. + */ +// @Test + public void testConnection() throws Exception { + final String dir = DataDirectory.getenv(); + assertTrue((dir == null) || dir.isEmpty(), "The SIS_DATA environment variable must be unset for enabling this test."); + final DataSource ds = Initializer.getDataSource(); + assertNotNull(ds, "Cannot find the data source."); + try (Connection c = ds.getConnection()) { + assertEquals("jdbc:derby:classpath:SIS_DATA/Databases/spatial-metadata", c.getMetaData().getURL(), "URL"); + try (Statement s = c.createStatement()) { + try (ResultSet r = s.executeQuery("SELECT COORD_REF_SYS_NAME FROM EPSG.\"Coordinate Reference System\" WHERE COORD_REF_SYS_CODE = 4326")) { + assertTrue(r.next(), "ResultSet.next()"); + assertEquals(r.getString(1), "WGS 84"); + assertFalse(r.next(), "ResultSet.next()"); + } + } + } + } + + /** + * Tests {@link CRS#forCode(String)} with the embedded database. This test asks for a CRS for which + * no hard-coded fallback exists in {@link org.apache.sis.referencing.CommonCRS}. Consequently this + * test should fail if we do not have a connection to a complete EPSG database. + * + * @throws FactoryException if an error occurred while creating the CRS. + */ + @Test + public void testCrsforCode() throws FactoryException { + CoordinateReferenceSystem crs = CRS.forCode("EPSG:6676"); + String area = TestUtilities.getSingleton(crs.getDomains()).getDomainOfValidity().getDescription().toString(); + assertTrue(area.contains("Japan"), area); + } +} diff --git a/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/Generator.java b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/Generator.java new file mode 100644 index 0000000000..05a9c266a2 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.database/test/org/apache/sis/resources/embedded/Generator.java @@ -0,0 +1,222 @@ +/* + * 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.resources.embedded; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.io.InputStream; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import org.opengis.util.FactoryException; +import org.opengis.referencing.crs.GeographicCRS; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.apache.sis.metadata.sql.privy.Initializer; +import org.apache.sis.metadata.sql.privy.LocalDataSource; +import org.apache.sis.system.DataDirectory; +import org.apache.sis.system.Shutdown; +import org.apache.sis.metadata.MetadataStandard; +import org.apache.sis.metadata.sql.MetadataSource; +import org.apache.sis.metadata.sql.MetadataStoreException; +import org.apache.sis.referencing.factory.sql.EPSGFactory; +import org.apache.sis.referencing.factory.sql.epsg.ScriptProvider; + + +/** + * Generates {@code SpatialMetadata} database with EPSG geodetic dataset. + * This class is invoked only at build time and should be excluded from the final JAR file. + * The {@link #main(String[])} method generates resources directly in the {@code target/classes} directory. + * + * <p><b>Note:</b> + * Maven usage is to generate resources in the {@code target/generated-resources} directory. + * We don't do that for avoiding unnecessary file copy operations before the package phase. + * Instead we write the files right in their final destination, {@code target/classes}.</p> + * + * @author Martin Desruisseaux (Geomatys) + */ +public final class Generator extends ScriptProvider { + /** + * Generates the embedded resources in the {@code target/classes} directory. + * See class Javadoc for more information. + * + * @param args ignored. Can be null. + * @throws Exception if a failure occurred while searching directories, + * executing SQL scripts, copying data or any other operation. + */ + public static void main(String[] args) throws Exception { + new Generator().run(); + Shutdown.stop(Generator.class); + } + + /** + * Generates the embedded resources in the {@code target/classes} directory. + * + * @throws Exception if a failure occurred while searching directories, + * executing SQL scripts, copying data or any other operation. + */ + final void run() throws Exception { + if (dataSource != null) { + createMetadata(); + createEPSG(); + compress(); + shutdown(); + } + } + + /** + * Provides a connection to the "SpatialMetadata" database, or {@code null} if the database already exists. + * The connection URL will reference the {@code SIS_DATA/Databases/spatial-metadata} directory in the Maven + * {@code target/classes} directory. + */ + private final EmbeddedDataSource dataSource; + + /** + * Creates a new database generator. + */ + Generator() throws URISyntaxException, IOException { + Path target = copyLicenseFiles(); + do target = target.getParent(); // Move to the root directory of classes. + while (!target.getFileName().toString().startsWith("org.apache.sis.")); + target = target.resolve("META-INF").resolve(DataDirectory.ENV); + if (Files.isDirectory(target)) { + dataSource = null; + return; + } + /* + * Creates sub-directory step by step instead of invoking Files.createDirectories(…) + * for making sure that we do not create undesirable directories. + */ + target = Files.createDirectory(target); + target = Files.createDirectory(target.resolve(Path.of("Databases"))); + dataSource = new EmbeddedDataSource(); + dataSource.setDataSourceName(Initializer.DATABASE); + dataSource.setDatabaseName(target.resolve(EmbeddedResources.EMBEDDED_DATABASE).toString()); + dataSource.setCreateDatabase("create"); + } + + /** + * Copies the EPSG terms of use from the {@code sis-epsg} module to this {@code sis-embedded-data} module. + * We copy those files ourselves instead than relying on {@code maven-resources-plugin} because a future + * version may combine more licenses in a single file. + * + * @return the directory where the licenses have been copied. + */ + private Path copyLicenseFiles() throws URISyntaxException, IOException { + final Class<?> consumer = EmbeddedResources.class; + final Path target = Path.of(consumer.getResource(consumer.getSimpleName() + ".class").toURI()).getParent(); + final String[] files = {"LICENSE.txt", "LICENSE.html"}; + for (String file : files) { + try (InputStream in = openStream(file)) { + if (in == null) throw new FileNotFoundException(file); + Files.copy(in, target.resolve(file)); + } catch (FileAlreadyExistsException e) { + break; + } + } + return target; + } + + /** + * Creates the metadata database schema. + * + * @throws FactoryException if an error occurred while creating or querying the database. + */ + private void createMetadata() throws MetadataStoreException, ReflectiveOperationException { + try (MetadataSource md = new MetadataSource(MetadataStandard.ISO_19115, dataSource, "metadata", null)) { + Method install = md.getClass().getDeclaredMethod("install"); + install.setAccessible(true); + install.invoke(md); + } + } + + /** + * Creates the EPSG database schema. + * + * @throws FactoryException if an error occurred while creating or querying the database. + */ + private void createEPSG() throws FactoryException { + final Map<String,Object> properties = new HashMap<>(); + properties.put("dataSource", dataSource); + properties.put("scriptProvider", this); + /* + * Asking for any CRS will trig the database creation. + * We perform a simple verification on the created CRS as a matter of principle. + */ + final GeographicCRS crs; + try (EPSGFactory factory = new EPSGFactory(properties)) { + crs = factory.createGeographicCRS("4326"); + } + if (!crs.getName().getCode().equals("WGS 84")) { + throw new FactoryException("Unexpected CRS: " + crs.getName()); + } + } + + /** + * Compresses all tables in the EPSG schema. Compression can save space if there was many update + * or delete operations in the database. In the case of the database generated by this class, + * the benefit is very small because the database is fresh. But it is still non-zero. + */ + private void compress() throws SQLException { + try (Connection c = dataSource.getConnection()) { + List<String> tables = new ArrayList<>(80); // As (schema,table) pairs. + try (ResultSet r = c.getMetaData().getTables(null, null, null, null)) { + while (r.next()) { + final String schema = r.getString("TABLE_SCHEM"); + if (!schema.startsWith("SYS")) { + tables.add(schema); + tables.add(r.getString("TABLE_NAME")); + } + } + } + try (CallableStatement cs = c.prepareCall("CALL SYSCS_UTIL.SYSCS_COMPRESS_TABLE(?, ?, ?)")) { + for (int i=0; i<tables.size();) { + cs.setString(1, tables.get(i++)); // Schema name. + cs.setString(2, tables.get(i++)); // Table name. + cs.setShort (3, (short) 1); + cs.execute(); + } + } + } + } + + /** + * Shutdowns the Derby database. + */ + private void shutdown() throws SQLException { + dataSource.setCreateDatabase("no"); + dataSource.setShutdownDatabase("shutdown"); + try { + dataSource.getConnection().close(); + } catch (SQLException e) { + if (LocalDataSource.isSuccessfulShutdown(e)) { + return; + } + throw e; + } + throw new SQLException("Shutdown has not been completed."); + } +} diff --git a/optional/src/org.apache.sis.referencing.epsg/main/META-INF/NOTICE b/optional/src/org.apache.sis.referencing.epsg/main/META-INF/NOTICE new file mode 100644 index 0000000000..276d8b81c7 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/main/META-INF/NOTICE @@ -0,0 +1,10 @@ +EPSG geodetic dataset for Apache SIS +Copyright The Apache Software Foundation +Copyright International Association of Oil and Gas Producers (IOGP) + +This product includes software developed at +The Apache Software Foundation (https://www.apache.org/). + +This product includes geodetic dataset maintained by the +International Association of Oil and Gas Producers (IOGP) +https://epsg.org/ diff --git a/optional/src/org.apache.sis.referencing.epsg/main/META-INF/services/org.apache.sis.setup.InstallationResources b/optional/src/org.apache.sis.referencing.epsg/main/META-INF/services/org.apache.sis.setup.InstallationResources new file mode 100644 index 0000000000..ad7e1b09e3 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/main/META-INF/services/org.apache.sis.setup.InstallationResources @@ -0,0 +1,4 @@ +# Workaround for Maven bug https://issues.apache.org/jira/browse/MNG-7855 +# The content of this file is automatically derived from module-info.class file. +# Should be used only if the JAR file was on class-path rather than module-path. +org.apache.sis.referencing.factory.sql.epsg.ScriptProvider diff --git a/optional/src/org.apache.sis.referencing.epsg/main/module-info.java b/optional/src/org.apache.sis.referencing.epsg/main/module-info.java new file mode 100644 index 0000000000..a6ec05daf8 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/main/module-info.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Apache Software Foundation. + * + * Licensed 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. + */ + +/** + * SQL scripts for EPSG geodetic data set installation. + * This module provides the <abbr>EPSG</abbr> data of the {@code org.apache.sis.referencing.database} module, + * but in a form that allows installation on <abbr>SQL</abbr> databases other than Apache Derby. + * + * <h2>Licensing</h2> + * EPSG is maintained by the <a href="https://www.iogp.org/">International Association of Oil and Gas Producers</a> + * (IOGP) Surveying & Positioning Committee and is subject to <a href="https://epsg.org/terms-of-use.html">EPSG + * terms of use</a>. This module is not included in the Apache <abbr>SIS</abbr> distribution of convenience binaries, + * and the source code contains only the Java classes without the <abbr>EPSG</abbr> data. For use in an application, + * see <a href="https://sis.apache.org/epsg.html">How to use EPSG geodetic dataset</a> on the <abbr>SIS</abbr> web site. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 0.7 + */ +module org.apache.sis.referencing.epsg { + requires transitive org.apache.sis.referencing; + + exports org.apache.sis.referencing.factory.sql.epsg; + + uses org.apache.sis.setup.InstallationResources; + provides org.apache.sis.setup.InstallationResources + with org.apache.sis.referencing.factory.sql.epsg.ScriptProvider; +} diff --git a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/.gitignore b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/.gitignore new file mode 100644 index 0000000000..f7436babfc --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/.gitignore @@ -0,0 +1,7 @@ +# Those files must be put manually for licensing reasons. +# See README.md for more details. +Data.sql +FKeys.sql +LICENSE.html +LICENSE.txt +Tables.sql diff --git a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/README.md b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/README.md new file mode 100644 index 0000000000..fcd650b55e --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/README.md @@ -0,0 +1,23 @@ +# Manual installation of EPSG data + +This is the directory where EPSG data can be placed. +Those data are not commited in the Apache SIS source code repository because +they are licensed under [EPSG terms of use](https://epsg.org/terms-of-use.html). +For including the EPSG data in the `org.apache.sis.referencing.epsg` artifact, +the following commands must be executed manually with this directory as the +current directory: + +```shell +# Execute the following in a separated directory. +svn checkout https://svn.apache.org/repos/asf/sis/data/non-free/ +cd non-free +export NON_FREE_DIR=`pwd` + +# Execute the following in the directory of this `README.md` file. +ln --symbolic $NON_FREE_DIR/EPSG/LICENSE.txt +ln --symbolic $NON_FREE_DIR/EPSG/LICENSE.html +ln --symbolic $NON_FREE_DIR/EPSG/Tables.sql +ln --symbolic $NON_FREE_DIR/EPSG/Data.sql +ln --symbolic $NON_FREE_DIR/EPSG/FKeys.sql +cd - +``` diff --git a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/ScriptProvider.java b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/ScriptProvider.java new file mode 100644 index 0000000000..333a9b1dbf --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/ScriptProvider.java @@ -0,0 +1,104 @@ +/* + * 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.referencing.factory.sql.epsg; + +import java.util.Locale; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import org.apache.sis.util.resources.Errors; +import org.apache.sis.util.privy.Constants; +import org.apache.sis.referencing.factory.sql.InstallationScriptProvider; + + +/** + * Provides SQL scripts for creating a local copy of the EPSG geodetic dataset. + * Provides also a copy of the <a href="https://epsg.org/terms-of-use.html">EPSG terms of use</a>, + * which should be accepted by users before the EPSG dataset can be installed. + * + * <p><b>Notice</b></p> + * EPSG is maintained by the <a href="http://www.iogp.org/">International Association of Oil and Gas Producers</a> + * (IOGP) Surveying & Positioning Committee. The SQL scripts are given by this class with identical content, + * but in a more compact format. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 0.7 + * + * @see <a href="https://epsg.org/">https://epsg.org/</a> + */ +public class ScriptProvider extends InstallationScriptProvider { + /** + * Creates a new EPSG scripts provider. + */ + public ScriptProvider() { + super(Constants.EPSG, PREPARE, "Tables.sql", "Data.sql", "FKeys.sql", FINISH); + } + + /** + * Returns a copy of EPSG terms of use. + * + * @param authority one of the values returned by {@link #getAuthorities()}. + * @param locale the preferred locale for the terms of use. + * @param mimeType either {@code "text/plain"} or {@code "text/html"}. + * @return the terms of use in plain text or HTML, or {@code null} if the specified MIME type is not recognized. + * @throws IOException if an error occurred while reading the license file. + * + * @see <a href="https://epsg.org/terms-of-use.html">https://epsg.org/terms-of-use.html</a> + */ + @Override + public String getLicense(final String authority, final Locale locale, final String mimeType) throws IOException { + if (!Constants.EPSG.equals(authority)) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "authority", authority)); + } + final String filename; + if ("text/plain".equalsIgnoreCase(mimeType)) { + filename = "LICENSE.txt"; + } else if ("text/html".equalsIgnoreCase(mimeType)) { + filename = "LICENSE.html"; + } else { + return null; + } + final InputStream in = ScriptProvider.class.getResourceAsStream(filename); + if (in == null) { + throw new FileNotFoundException(filename); + } + final StringBuilder buffer = new StringBuilder(); + final String lineSeparator = System.lineSeparator(); + try (BufferedReader r = new BufferedReader(new InputStreamReader(in, "UTF-8"))) { + String line; + while ((line = r.readLine()) != null) { + buffer.append(line).append(lineSeparator); + } + } + return buffer.toString(); + } + + /** + * Returns the content for the SQL script of the given name. + * The file encoding is UTF-8. + * + * @param name either {@code "Tables.sql"}, {@code "Data.sql"} or {@code "FKeys.sql"}. + * @return the SQL script of the given name, or {@code null} if the given name is not one of the expected names. + */ + @Override + protected InputStream openStream(final String name) { + return ScriptProvider.class.getResourceAsStream(name); + } +} diff --git a/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/package-info.java b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/package-info.java new file mode 100644 index 0000000000..982b8fa434 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/main/org/apache/sis/referencing/factory/sql/epsg/package-info.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/** + * SQL scripts for EPSG geodetic data set installation. + * The <a href="https://epsg.org/">EPSG</a> geodetic dataset provides definitions for thousands of + * {@linkplain org.opengis.referencing.crs.CoordinateReferenceSystem Coordinate Reference Systems} (<abbr>CRS</abbr>), + * together with parameter values for thousands of {@linkplain org.opengis.referencing.operation.ConcatenatedOperation + * Coordinate Operations} between various <abbr>CRS</abbr> pairs. + * This module contains the SQL scripts for creating a local copy of EPSG geodetic dataset. + * + * <h2>Licensing</h2> + * EPSG is maintained by the <a href="https://www.iogp.org/">International Association of Oil and Gas Producers</a> + * (IOGP) Surveying & Positioning Committee and is subject to <a href="https://epsg.org/terms-of-use.html">EPSG + * terms of use</a>. This module is not included in the Apache <abbr>SIS</abbr> distribution of convenience binaries, + * and the source code contains only the Java classes without the <abbr>EPSG</abbr> data. For use in an application, + * see <a href="https://sis.apache.org/epsg.html">How to use EPSG geodetic dataset</a> on the <abbr>SIS</abbr> web site. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.5 + * @since 0.7 + */ +package org.apache.sis.referencing.factory.sql.epsg; diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java similarity index 100% rename from endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java rename to optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatter.java diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatterTest.java b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatterTest.java similarity index 93% rename from endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatterTest.java rename to optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatterTest.java index 094f688605..e34bf5b554 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatterTest.java +++ b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/DataScriptFormatterTest.java @@ -39,7 +39,7 @@ public final class DataScriptFormatterTest extends TestCase { */ @Test public void testRemoveLF() { - final StringBuilder buffer = new StringBuilder(" \nOne,\nTwo, \n Three Four\nFive \nSix \n"); + final var buffer = new StringBuilder(" \nOne,\nTwo, \n Three Four\nFive \nSix \n"); DataScriptFormatter.removeLF(buffer); assertEquals("One,Two,Three Four Five Six", buffer.toString()); } diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/DebugTools.sql b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/DebugTools.sql similarity index 100% rename from endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/DebugTools.sql rename to optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/DebugTools.sql diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/README.md b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md similarity index 100% rename from endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/epsg/README.md rename to optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md diff --git a/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/ScriptProviderTest.java b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/ScriptProviderTest.java new file mode 100644 index 0000000000..111bdd6474 --- /dev/null +++ b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/ScriptProviderTest.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.referencing.factory.sql.epsg; + +import java.io.IOException; +import java.io.BufferedReader; +import java.util.ServiceLoader; +import org.apache.sis.setup.InstallationResources; + +// Test dependencies +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + + +/** + * Test {@link ScriptProvider}. + * + * @author Martin Desruisseaux (Geomatys) + */ +public final strictfp class ScriptProviderTest { + /** + * Returns the {@link ScriptProvider} instance declared in the {@code META-INF/services/} directory. + * The provider may coexist with providers defined in other modules, so we need to filter them. + */ + private static InstallationResources getInstance() { + assumeTrue(ScriptProvider.class.getResource("LICENSE.txt") != null, + "EPSG resources not found. See `README.md` for manual installation."); + + InstallationResources provider = null; + for (InstallationResources candidate : ServiceLoader.load(InstallationResources.class)) { + if (candidate instanceof ScriptProvider) { + assertNull(provider, "Expected only one instance."); + provider = candidate; + } + } + assertNotNull(provider, "Expected an instance."); + return provider; + } + + /** + * Tests fetching the licenses. + * + * @throws IOException if an error occurred while reading a license. + */ + @Test + public void testLicences() throws IOException { + final InstallationResources provider = getInstance(); + assertTrue(provider.getLicense("EPSG", null, "text/plain").contains("IOGP")); + assertTrue(provider.getLicense("EPSG", null, "text/html" ).contains("IOGP")); + } + + /** + * Tests fetching the resources. + * + * @throws IOException if an error occurred while reading a resource. + */ + @Test + public void testResources() throws IOException { + final InstallationResources provider = getInstance(); + final String[] names = provider.getResourceNames("EPSG"); + assertArrayEquals(new String[] {"Prepare", "Tables.sql", "Data.sql", "FKeys.sql", "Finish"}, names); + for (int i=0; i<names.length; i++) { + try (BufferedReader in = provider.openScript("EPSG", i)) { + // Just verify that we can read. + assertFalse(in.readLine().isEmpty()); + } + } + } +}