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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push: new ab02e95 Add `InfoStatements.findSRID(CoordinateReferenceSystem)` method and use it in `RasterWriter`. Initial draft of test cases for WKB raster in the context of PostGIS database. ab02e95 is described below commit ab02e95fa78c22f6b979fb7a447b54cecd83799e Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Tue Dec 21 22:51:01 2021 +0100 Add `InfoStatements.findSRID(CoordinateReferenceSystem)` method and use it in `RasterWriter`. Initial draft of test cases for WKB raster in the context of PostGIS database. --- .../apache/sis/internal/sql/feature/Database.java | 11 +- .../sis/internal/sql/feature/InfoStatements.java | 134 +++++++++++++++++++-- .../apache/sis/internal/sql/feature/Resources.java | 5 + .../sis/internal/sql/feature/Resources.properties | 1 + .../internal/sql/feature/Resources_fr.properties | 1 + .../sis/internal/sql/postgis/RasterReader.java | 3 + .../sis/internal/sql/postgis/RasterWriter.java | 34 +++--- .../sis/internal/sql/postgis/PostgresTest.java | 82 ++++++++++++- .../sis/internal/sql/postgis/RasterReaderTest.java | 18 ++- .../sis/internal/sql/postgis/RasterWriterTest.java | 7 +- .../sis/internal/sql/postgis/TestRaster.java | 2 +- .../org/apache/sis/storage/sql/SQLStoreTest.java | 6 +- .../sis/internal/sql/postgis/SpatialFeatures.sql | 21 ++++ 13 files changed, 281 insertions(+), 44 deletions(-) diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java index 533fc31..cf81859 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Database.java @@ -20,6 +20,7 @@ import java.util.Set; import java.util.List; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.WeakHashMap; import java.util.ArrayList; import java.util.Locale; import java.util.logging.LogRecord; @@ -90,7 +91,7 @@ import org.apache.sis.util.Debug; * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) * @author Alexis Manin (Geomatys) - * @version 1.1 + * @version 1.2 * @since 1.1 * @module */ @@ -181,6 +182,13 @@ public class Database<G> extends Syntax { final Cache<Integer, CoordinateReferenceSystem> cacheOfCRS; /** + * Cache of SRID for a given Coordinate Reference System. + * This is the converse of {@link #cacheOfCRS}. + * Accesses to this map must be synchronized on the map itself. + */ + final WeakHashMap<CoordinateReferenceSystem, Integer> cacheOfSRID; + + /** * Creates a new handler for a spatial database. * * @param source provider of (pooled) connections to the database. @@ -213,6 +221,7 @@ public class Database<G> extends Syntax { this.geomLibrary = geomLibrary; this.listeners = listeners; this.cacheOfCRS = new Cache<>(7, 2, false); + this.cacheOfSRID = new WeakHashMap<>(); this.tablesByNames = new FeatureNaming<>(); supportsCatalogs = metadata.supportsCatalogsInDataManipulation(); supportsSchemas = metadata.supportsSchemasInDataManipulation(); diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/InfoStatements.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/InfoStatements.java index 613724c..3b62c34 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/InfoStatements.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/InfoStatements.java @@ -17,6 +17,10 @@ package org.apache.sis.internal.sql.feature; import java.util.Map; +import java.util.Set; +import java.util.HashSet; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Iterator; import java.util.Locale; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -25,20 +29,27 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import org.opengis.metadata.Identifier; +import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.crs.CRSAuthorityFactory; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.apache.sis.storage.DataStoreContentException; +import org.apache.sis.storage.DataStoreReferencingException; import org.apache.sis.internal.referencing.DefinitionVerifier; import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.internal.metadata.sql.SQLBuilder; import org.apache.sis.internal.feature.GeometryType; import org.apache.sis.internal.system.Modules; +import org.apache.sis.internal.util.Constants; import org.apache.sis.io.wkt.Convention; import org.apache.sis.io.wkt.WKTFormat; import org.apache.sis.io.wkt.Warnings; import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.IdentifiedObjects; +import org.apache.sis.referencing.factory.IdentifiedObjectFinder; import org.apache.sis.util.Localized; +import org.apache.sis.util.Utilities; /** @@ -48,6 +59,7 @@ import org.apache.sis.util.Localized; * <ul> * <li>Searching for geometric information using SQL queries specialized for Simple Feature table.</li> * <li>Fetching a Coordinate Reference System (CRS) from a SRID.</li> + * <li>Finding a SRID from a Coordinate Reference System (CRS).</li> * </ul> * * This class is <strong>not</strong> thread-safe. Each instance should be used in a single thread. @@ -55,7 +67,7 @@ import org.apache.sis.util.Localized; * * @author Alexis Manin (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @since 1.1 + * @since 1.2 * * @see <a href="https://www.ogc.org/standards/sfs">OGC Simple feature access — Part 2: SQL option</a> * @@ -114,6 +126,11 @@ public class InfoStatements implements Localized, AutoCloseable { private PreparedStatement wktFromSrid; /** + * The statement for fetching a SRID from a CRS and its set of authority codes. + */ + private PreparedStatement sridFromCRS; + + /** * The object to use for parsing Well-Known Text (WKT), created when first needed. */ private WKTFormat wktReader; @@ -312,13 +329,9 @@ public class InfoStatements implements Localized, AutoCloseable { CoordinateReferenceSystem fromWKT = null; final String wkt = result.getString(3); if (wkt != null && !wkt.isEmpty()) { - if (wktReader == null) { - wktReader = new WKTFormat(null, null); - wktReader.setConvention(Convention.WKT1_COMMON_UNITS); - } final Object parsed; try { - parsed = wktReader.parseObject(wkt); + parsed = wktReader().parseObject(wkt); } catch (ParseException e) { if (authorityError != null) { e.addSuppressed(authorityError); @@ -401,7 +414,110 @@ public class InfoStatements implements Localized, AutoCloseable { } /** - * Closes all prepared statements.This method does <strong>not</strong> close the connection. + * Finds a SRID code from the spatial reference systems table for the given CRS. + * + * @param crs the CRS for which to find a SRID, or {@code null}. + * @return SRID for the given CRS, or 0 if the given CRS was null. + * @throws Exception if an SQL error, parsing error or other error occurred. + */ + public final int findSRID(final CoordinateReferenceSystem crs) throws Exception { + if (crs == null) { + return 0; + } + synchronized (database.cacheOfSRID) { + final Integer srid = database.cacheOfSRID.get(crs); + if (srid != null) { + return srid; + } + } + final Set<SimpleImmutableEntry<String,String>> done = new HashSet<>(); + Iterator<IdentifiedObject> alternatives = null; + IdentifiedObject candidate = crs; + Exception error = null; + for (;;) { + /* + * First, iterate over the identifiers declared in the CRS object. + * If we can not find an identifier that we can map to a SRID, then this loop may be + * executed more times with CRS from EPSG database that are equal, ignore axis order. + */ + for (final Identifier id : candidate.getIdentifiers()) { + final String authority = id.getCodeSpace(); + if (authority == null) continue; + final String code = id.getCode(); + if (!done.add(new SimpleImmutableEntry<>(authority, code))) { + continue; // Skip "authority:code" that we already tried. + } + final int codeValue; + try { + codeValue = Integer.parseInt(code); + } catch (NumberFormatException e) { + if (error == null) error = e; + else error.addSuppressed(e); + continue; // Ignore codes that are not integers. + } + /* + * Found an "authority:code" pair that we did not tested before. + * Get the WKT and verifies if the CRS is approximately equal. + */ + if (sridFromCRS == null) { + final SQLBuilder sql = new SQLBuilder(database); + sql.append("SELECT srtext, srid"); + appendFrom(sql, SPATIAL_REF_SYS); + sql.append("auth_name=? AND auth_srid=?"); + sridFromCRS = connection.prepareStatement(sql.toString()); + } + sridFromCRS.setString(1, authority); + sridFromCRS.setInt(2, codeValue); + try (ResultSet result = sridFromCRS.executeQuery()) { + while (result.next()) { + final String wkt = result.getString(1); + if (wkt != null && !wkt.isEmpty()) try { + final Object parsed = wktReader().parseObject(wkt); + if (Utilities.equalsApproximately(parsed, crs)) { + final int srid = result.getInt(2); + synchronized (database.cacheOfSRID) { + database.cacheOfSRID.put(crs, srid); + } + return srid; + } + } catch (ParseException e) { + if (error == null) error = e; + else error.addSuppressed(e); + } + } + } + } + /* + * Tried all identifiers associated to the CRS and found no match. + * It may be because the CRS has no identifier at all. Search for + * possible identifiers in the EPSG database, then try them. + */ + if (alternatives == null) { + final IdentifiedObjectFinder finder = IdentifiedObjects.newFinder(Constants.EPSG); + finder.setIgnoringAxes(true); + alternatives = finder.find(crs).iterator(); + } + if (!alternatives.hasNext()) break; + candidate = alternatives.next(); + } + throw new DataStoreReferencingException(Resources.format( + Resources.Keys.CanNotFindSRID_1, IdentifiedObjects.getDisplayName(crs, null)), error); + } + + /** + * Returns the object to use for parsing Well Known Text (CRS). + * The parser is created when first needed. + */ + private WKTFormat wktReader() { + if (wktReader == null) { + wktReader = new WKTFormat(null, null); + wktReader.setConvention(Convention.WKT1_COMMON_UNITS); + } + return wktReader; + } + + /** + * Closes all prepared statements. This method does <strong>not</strong> close the connection. * * @throws SQLException if an error occurred while closing a connection. */ @@ -415,5 +531,9 @@ public class InfoStatements implements Localized, AutoCloseable { wktFromSrid.close(); wktFromSrid = null; } + if (sridFromCRS != null) { + sridFromCRS.close(); + sridFromCRS = null; + } } } diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java index 517a205..885dc3a 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java @@ -64,6 +64,11 @@ public final class Resources extends IndexedResourceBundle { public static final short CanNotFetchCRS_1 = 8; /** + * Can not find an identifier in the database for the reference system “{0}”. + */ + public static final short CanNotFindSRID_1 = 15; + + /** * Provider of connections to the database. */ public static final short DataSource = 1; diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.properties b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.properties index 83d294e..133fd1a 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.properties +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.properties @@ -20,6 +20,7 @@ # For resources shared by all modules in the Apache SIS project, see "org.apache.sis.util.resources" package. # CanNotFetchCRS_1 = Can not fetch a Coordinate Reference System (CRS) for SRID code {0}. +CanNotFindSRID_1 = Can not find an identifier in the database for the reference system \u201c{0}\u201d. DataSource = Provider of connections to the database. DuplicatedColumn_1 = Unexpected duplication of column named \u201c{0}\u201d. DuplicatedSRID_2 = Spatial Reference Identifier (SRID) {1} has more than one entry in \u201c{0}\u201d table. diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_fr.properties b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_fr.properties index 6a83f5c..c46969e 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_fr.properties +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_fr.properties @@ -25,6 +25,7 @@ # U+00A0 NO-BREAK SPACE before : # CanNotFetchCRS_1 = Ne peut pas obtenir un syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es pour le code SRID {0}. +CanNotFindSRID_1 = Ne peut pas trouver un identifiant dans la base de donn\u00e9es pour le syst\u00e8me de r\u00e9f\u00e9rence \u00ab\u202f{0}\u202f\u00bb. DataSource = Fournisseur de connexions \u00e0 la base de donn\u00e9es. DuplicatedColumn_1 = Doublon inattendu d\u2019une colonne nomm\u00e9e \u00ab\u202f{0}\u202f\u00bb. DuplicatedSRID_2 = L\u2019identifiant de r\u00e9f\u00e9rence spatiale (SRID) {1} a plusieurs entr\u00e9s dans la table \u00ab\u202f{0}\u202f\u00bb. diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java index 244aa3e..693c6ed 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterReader.java @@ -314,6 +314,9 @@ public final class RasterReader extends RasterFormat { final int sampleSize = ((MultiPixelPackedSampleModel) sm).getPixelBitStride(); maximum = (1 << sampleSize) - 1; minimum = 0; + } else if (dataType == DataBuffer.TYPE_BYTE) { + minimum = 0; + maximum = 0xFF; } else { final Band band = bands[visibleBand]; final NumberRange<?> range = Vector.create(band.data, band.isUnsigned()).range(); diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterWriter.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterWriter.java index 4188e0e..5ce3d89 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterWriter.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/postgis/RasterWriter.java @@ -35,18 +35,15 @@ import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.RenderedImage; import java.awt.image.Raster; import java.awt.image.RasterFormatException; -import org.opengis.util.FactoryException; -import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.image.PixelIterator; import org.apache.sis.coverage.SampleDimension; import org.apache.sis.coverage.grid.GridCoverage; import org.apache.sis.coverage.grid.GridGeometry; -import org.apache.sis.internal.util.Constants; +import org.apache.sis.internal.sql.feature.Resources; import org.apache.sis.internal.sql.feature.InfoStatements; import org.apache.sis.internal.storage.io.ChannelDataOutput; import org.apache.sis.referencing.IdentifiedObjects; -import org.apache.sis.referencing.factory.IdentifiedObjectFinder; import org.apache.sis.referencing.operation.matrix.AffineTransforms2D; import org.apache.sis.util.resources.Errors; @@ -121,9 +118,10 @@ public final class RasterWriter extends RasterFormat { * * @param gg the grid to CRS conversion together with target CRS. * @throws IllegalArgumentException if the "grid to CRS" transform is not affine. - * @throws FactoryException if an error occurred during the search for SRID code. + * @throws Exception if an error occurred during the search for SRID code. + * May be SQL error, WKT parsing error, factory error, <i>etc.</i> */ - public void setGridToCRS(final GridGeometry gg) throws FactoryException { + public void setGridToCRS(final GridGeometry gg) throws Exception { if (gg.isDefined(GridGeometry.CRS)) { final CoordinateReferenceSystem crs = gg.getCoordinateReferenceSystem(); /* @@ -131,21 +129,16 @@ public final class RasterWriter extends RasterFormat { * Otherwise use EPSG code only as a starting point, ignoring axis order, * and search for the corresponding SRID. */ - Integer epsg; - if (spatialRefSys == null) { - epsg = IdentifiedObjects.lookupEPSG(crs); + if (spatialRefSys != null) { + srid = spatialRefSys.findSRID(crs); } else { - epsg = null; - final IdentifiedObjectFinder finder = IdentifiedObjects.newFinder(Constants.EPSG); - finder.setIgnoringAxes(true); - for (final IdentifiedObject candidate : finder.find(crs)) { - // TODO + final Integer epsg = IdentifiedObjects.lookupEPSG(crs); + if (epsg == null) { + throw new IllegalArgumentException(Resources.format( + Resources.Keys.CanNotFindSRID_1, IdentifiedObjects.getDisplayName(crs, null))); } + srid = epsg; } - if (epsg == null) { - throw new IllegalArgumentException("Can not find an identifier in the database for the Coordinate Reference System."); - } - srid = epsg; } else { srid = 0; } @@ -176,9 +169,10 @@ public final class RasterWriter extends RasterFormat { * @param output where to write the bytes. * @throws RasterFormatException if the raster to write is not supported. * @throws IOException in an error occurred while writing to the given output. - * @throws FactoryException if an error occurred during the search for SRID code. + * @throws Exception if an error occurred during the search for SRID code. + * May be SQL error, WKT parsing error, factory error, <i>etc.</i> */ - public void write(final GridCoverage coverage, final ChannelDataOutput output) throws IOException, FactoryException { + public void write(final GridCoverage coverage, final ChannelDataOutput output) throws Exception { setGridToCRS(coverage.getGridGeometry()); setNodataValues(coverage.getSampleDimensions()); write(coverage.render(null), output); 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 7a43465..a473b64 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,30 +16,106 @@ */ package org.apache.sis.internal.sql.postgis; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.lang.reflect.Method; +import org.opengis.referencing.crs.ProjectedCRS; +import org.apache.sis.setup.OptionKey; +import org.apache.sis.setup.GeometryLibrary; +import org.apache.sis.storage.sql.SQLStore; +import org.apache.sis.storage.sql.SQLStoreProvider; +import org.apache.sis.storage.sql.ResourceDefinition; +import org.apache.sis.storage.StorageConnector; +import org.apache.sis.storage.sql.SQLStoreTest; +import org.apache.sis.internal.storage.io.ChannelDataInput; +import org.apache.sis.referencing.crs.HardCodedCRS; +import org.apache.sis.test.sql.TestDatabase; +import org.apache.sis.test.DependsOn; import org.apache.sis.test.TestCase; import org.apache.sis.util.Version; import org.junit.Test; -import static org.junit.Assert.*; +import static org.opengis.test.Assert.*; /** * Tests {@link Postgres}. * * @author Alexis Manin (Geomatys) - * @version 1.1 + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 * @since 1.1 * @module */ +@DependsOn({RasterReaderTest.class, RasterWriterTest.class}) public final strictfp class PostgresTest extends TestCase { /** * Tests {@link Postgres#parseVersion(String)}. */ @Test - public void parse_postgis_version() { + public void testParseVersion() { final Version version = Postgres.parseVersion("3.1 USE_GEOS=1 USE_PROJ=1 USE_STATS=1"); assertEquals(3, version.getMajor()); assertEquals(1, version.getMinor()); assertNull ( version.getRevision()); } + + /** + * Tests reading and writing features and rasters. + * + * @throws Exception if an error occurred while testing the database. + */ + @Test + public void testSpatialFeatures() throws Exception { + try (TestDatabase database = TestDatabase.createOnPostgreSQL(SQLStoreTest.SCHEMA, true)) { + database.executeSQL(PostgresTest.class, "file: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"); + try (SQLStore store = new SQLStore(new SQLStoreProvider(), connector, table)) { + /* + * Invoke the private `model()` method. We have to use reflection because the class + * is not in the same package and we do not want to expose the method in public API. + */ + final Method modelAccessor = SQLStore.class.getDeclaredMethod("model"); + modelAccessor.setAccessible(true); + final Postgres<?> pg = (Postgres<?>) modelAccessor.invoke(store); + try (Connection connection = database.source.getConnection(); + ExtendedInfo info = new ExtendedInfo(pg, connection)) + { + testInfoStatements(info); +// testRasterReader(TestRaster.USHORT, info, connection); + } + } + } + } + + /** + * Tests {@link org.apache.sis.internal.sql.feature.InfoStatements}. + * + * @throws Exception if an error occurred while testing the database. + */ + private void testInfoStatements(final ExtendedInfo info) throws Exception { + assertEquals("findSRID", 4326, info.findSRID(HardCodedCRS.WGS84)); + assertInstanceOf("fetchCRS", ProjectedCRS.class, info.fetchCRS(3395)); + } + + /** + * Tests {@link RasterReader}. + */ + private void testRasterReader(final TestRaster test, final ExtendedInfo info, final Connection connection) throws Exception { + final RasterReader reader = new RasterReader(info); + try (PreparedStatement stmt = connection.prepareStatement("SELECT image FROM features.\"SpatialData\" WHERE filename=?")) { + stmt.setString(1, test.filename); + final ResultSet r = stmt.executeQuery(); + assertTrue(r.next()); + final ChannelDataInput input = new ChannelDataInput(test.filename, + Channels.newChannel(r.getBinaryStream(1)), ByteBuffer.allocate(50), false); + RasterReaderTest.compareReadResult(test, reader, input); + assertFalse(r.next()); + } + } } diff --git a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterReaderTest.java b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterReaderTest.java index 7b4a1d6..fc7595a 100644 --- a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterReaderTest.java +++ b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterReaderTest.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.awt.image.RenderedImage; import java.awt.image.DataBufferUShort; import org.apache.sis.coverage.grid.GridCoverage; +import org.apache.sis.internal.storage.io.ChannelDataInput; import org.apache.sis.test.TestCase; import org.junit.Test; @@ -49,12 +50,19 @@ public final strictfp class RasterReaderTest extends TestCase { } /** - * Reads the file for the given test enumeration - * and compares with the expected raster. + * Reads the file for the given test enumeration and compares with the expected raster. */ - private void compareReadResult(final TestRaster test) throws Exception { - final RasterReader reader = new RasterReader(null); - final GridCoverage coverage = reader.readAsCoverage(test.input()); + private static void compareReadResult(final TestRaster test) throws Exception { + compareReadResult(test, new RasterReader(null), test.input()); + } + + /** + * Reads the file for the given test enumeration and compares with the expected raster. + * The given reader and input are used for reading the raster. The input will be closed. + */ + static void compareReadResult(final TestRaster test, final RasterReader reader, final ChannelDataInput input) throws Exception { + final GridCoverage coverage = reader.readAsCoverage(input); + input.channel.close(); final RenderedImage image = coverage.render(null); assertEquals(TestRaster.SRID, reader.getSRID()); assertEquals(TestRaster.getGridToCRS(), reader.getGridToCRS()); diff --git a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterWriterTest.java b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterWriterTest.java index b250230..33ffdf6 100644 --- a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterWriterTest.java +++ b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/RasterWriterTest.java @@ -19,7 +19,6 @@ package org.apache.sis.internal.sql.postgis; import java.awt.image.Raster; import java.io.IOException; import java.io.ByteArrayOutputStream; -import org.opengis.util.FactoryException; import org.apache.sis.internal.storage.io.ChannelDataOutput; import org.apache.sis.test.TestCase; import org.junit.Test; @@ -43,10 +42,10 @@ public final strictfp class RasterWriterTest extends TestCase { * the expected sequence of bytes provided by {@code "raster-ushort.wkb"} file. * * @throws IOException if an error occurred while writing the test file. - * @throws FactoryException if an error occurred during the search for SRID code. + * @throws Exception if an error occurred during the search for SRID code. */ @Test - public void testUShort() throws IOException, FactoryException { + public void testUShort() throws Exception { compareWriteResult(TestRaster.USHORT); } @@ -54,7 +53,7 @@ public final strictfp class RasterWriterTest extends TestCase { * Writes the raster for the given test enumeration * and compares with the expected sequence of bytes. */ - private void compareWriteResult(final TestRaster test) throws IOException, FactoryException { + private static void compareWriteResult(final TestRaster test) throws Exception { final Raster raster = test.createRaster(); final RasterWriter writer = new RasterWriter(null); final ByteArrayOutputStream buffer = new ByteArrayOutputStream(test.length); diff --git a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/TestRaster.java b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/TestRaster.java index afe8b83..8ba6aae 100644 --- a/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/TestRaster.java +++ b/storage/sis-sqlstore/src/test/java/org/apache/sis/internal/sql/postgis/TestRaster.java @@ -69,7 +69,7 @@ enum TestRaster { /** * Name of the file where the WKB raster is stored. */ - private final String filename; + final String filename; /** * Expected file size in bytes. 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 094ceb4..b4111b1 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 @@ -61,7 +61,7 @@ public final strictfp class SQLStoreTest extends TestCase { /** * The schema where will be stored the features to test. */ - private static final String SCHEMA = "features"; + public static final String SCHEMA = "features"; /** * Data used in the {@code Features.sql} test file. @@ -163,8 +163,8 @@ public final strictfp class SQLStoreTest extends TestCase { scripts[0] = null; // Omit the "CREATE SCHEMA" statement if the schema already exists. } try (TestDatabase tmp = database) { // TODO: omit `tmp` with JDK16. - tmp.executeSQL(SQLStoreTest.class, scripts); - final StorageConnector connector = new StorageConnector(tmp.source); + database.executeSQL(SQLStoreTest.class, scripts); + final StorageConnector connector = new StorageConnector(database.source); final ResourceDefinition table = ResourceDefinition.table(null, inMemory ? null : SCHEMA, "Cities"); testTableQuery(connector, table); /* diff --git a/storage/sis-sqlstore/src/test/resources/org/apache/sis/internal/sql/postgis/SpatialFeatures.sql b/storage/sis-sqlstore/src/test/resources/org/apache/sis/internal/sql/postgis/SpatialFeatures.sql new file mode 100644 index 0000000..20a1bda --- /dev/null +++ b/storage/sis-sqlstore/src/test/resources/org/apache/sis/internal/sql/postgis/SpatialFeatures.sql @@ -0,0 +1,21 @@ +-- 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. + + +-- Create a temporary database on PostgreSQL for testing geometries and rasters. +-- The "postgis_raster" extension must be installed before to execute this test. + +SET search_path TO public; + +CREATE TABLE features."SpatialData" ( + "filename" VARCHAR(20) NOT NULL, + "image" RASTER NOT NULL, + + CONSTRAINT "PK_SpatialData" PRIMARY KEY ("filename") +); + +INSERT INTO features."SpatialData" ("filename", "image") + VALUES('raster-ushort.wkb', ('0100000200000000000000F43F000000000000044000000000000054C00000000000004EC0000000' + || '00000000000000000000000000E6100000030004000600006F0079008300D300DD00E700370141014B019B01A501AF01060000' + || '70007A008400D400DE00E800380142014C019C01A601B001')::raster);