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 2b9172f57c Provides metadata information about the software used by
`NetcdfStore` for reading a netCDF file. This commit completes the previous
one, which was providing this information for all other stores. The netCDF case
required additional pre-defined metadata and helper methods for fetching
version. This commit also simplifies the way to build that
"formatSpecificationCitation" metadata node.
2b9172f57c is described below
commit 2b9172f57cd57b920ca923d33b9074fa275bc426
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sun Sep 29 15:15:29 2024 +0200
Provides metadata information about the software used by `NetcdfStore` for
reading a netCDF file.
This commit completes the previous one, which was providing this
information for all other stores.
The netCDF case required additional pre-defined metadata and helper methods
for fetching version.
This commit also simplifies the way to build that
"formatSpecificationCitation" metadata node.
---
.../sis/metadata/iso/citation/Citations.java | 2 +-
.../main/org/apache/sis/metadata/sql/Citations.sql | 34 +--
.../apache/sis/metadata/sql/MetadataFallback.java | 24 +-
.../sis/metadata/iso/citation/CitationsTest.java | 2 +-
.../sis/metadata/sql/MetadataFallbackVerifier.java | 3 +-
.../operation/provider/NorthPoleRotation.java | 3 +-
.../operation/provider/SouthPoleRotation.java | 3 +-
.../apache/sis/storage/landsat/LandsatStore.java | 2 +-
.../apache/sis/storage/landsat/MetadataReader.java | 14 +-
.../sis/storage/landsat/MetadataReaderTest.java | 282 +++++++++------------
.../apache/sis/storage/geotiff/GeoTiffStore.java | 11 +-
.../apache/sis/storage/netcdf/MetadataReader.java | 41 +--
.../org/apache/sis/storage/netcdf/NetcdfStore.java | 7 +-
.../sis/storage/netcdf/NetcdfStoreProvider.java | 12 +-
.../apache/sis/storage/netcdf/base/Decoder.java | 15 +-
.../sis/storage/netcdf/classic/ChannelDecoder.java | 16 +-
.../sis/storage/netcdf/ucar/DecoderWrapper.java | 65 ++++-
.../sis/storage/netcdf/MetadataReaderTest.java | 104 ++++----
.../apache/sis/storage/base/MetadataBuilder.java | 80 +++---
.../main/org/apache/sis/storage/csv/Store.java | 32 +--
.../org/apache/sis/storage/esri/RasterStore.java | 11 +-
.../apache/sis/storage/image/WorldFileStore.java | 9 +-
.../main/org/apache/sis/util/Version.java | 53 +++-
.../main/org/apache/sis/util/privy/Constants.java | 6 +
.../test/org/apache/sis/util/VersionTest.java | 9 +
geoapi/snapshot | 2 +-
26 files changed, 454 insertions(+), 388 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/citation/Citations.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/citation/Citations.java
index bdd25d3564..5c3c60ee61 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/citation/Citations.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/citation/Citations.java
@@ -336,7 +336,7 @@ public final class Citations extends Static {
*
* @since 0.4
*/
- public static final IdentifierSpace<String> NETCDF = new
CitationConstant.Authority<>("NetCDF");
+ public static final IdentifierSpace<String> NETCDF = new
CitationConstant.Authority<>(Constants.NETCDF);
/**
* The authority for identifiers of objects defined by the the GeoTIFF
specification.
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/Citations.sql
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/Citations.sql
index 34af3febff..7dd4abb1c4 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/Citations.sql
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/Citations.sql
@@ -36,6 +36,7 @@ CREATE TABLE metadata."OnlineResource" (
INSERT INTO metadata."OnlineResource" ("ID", "linkage") VALUES
('EPSG', 'https://epsg.org/'),
('ESRI', 'https://www.esri.com/'),
+ ('GDAL', 'https://gdal.org/'),
('GeoTIFF', 'https://trac.osgeo.org/geotiff/'),
('IHO', 'https://www.iho.int/'),
('IOGP', 'https://www.iogp.org/'),
@@ -50,7 +51,7 @@ INSERT INTO metadata."OnlineResource" ("ID", "linkage") VALUES
('PostGIS', 'https://postgis.net/'),
('PROJ', 'https://proj.org/'),
('SIS', 'https://sis.apache.org/'),
- ('GDAL', 'https://gdal.org/'),
+ ('Unidata', 'https://www.unidata.ucar.edu/'),
('WMO', 'https://www.wmo.int/'),
('WMS', 'https://www.ogc.org/standards/wms');
@@ -108,6 +109,7 @@ INSERT INTO metadata."Organisation" ("ID", "name") VALUES
('{org}NATO', 'North Atlantic Treaty Organization'),
('{org}OGC', 'Open Geospatial Consortium'),
('{org}OSGeo', 'The Open Source Geospatial Foundation'),
+ ('{org}UCAR', 'University Corporation for Atmospheric Research'),
('{org}WMO', 'World Meteorological Organization');
INSERT INTO metadata."Responsibility" ("ID", "party", "role") VALUES
@@ -122,6 +124,7 @@ INSERT INTO metadata."Responsibility" ("ID", "party",
"role") VALUES
('NATO', '{org}NATO', 'principalInvestigator'),
('OGC', '{org}OGC', 'principalInvestigator'),
('OSGeo', '{org}OSGeo', 'resourceProvider'),
+ ('UCAR', '{org}UCAR', 'resourceProvider'),
('WMO', '{org}WMO', 'principalInvestigator');
@@ -198,19 +201,20 @@ INSERT INTO metadata."Identifier" ("ID", "code",
"codeSpace", "version") VALUES
('SIS', 'SIS', 'Apache', NULL);
INSERT INTO metadata."Citation" ("ID", "onlineResource", "edition",
"citedResponsibleParty", "presentationForm", "alternateTitle" , "title") VALUES
- ('ISBN', 'ISBN', NULL, 'ISBN', NULL,
'ISBN', 'International Standard Book Number'),
- ('ISSN', 'ISSN', NULL, 'ISSN', NULL,
'ISSN', 'International Standard Serial Number'),
- ('ISO 19115-1', NULL, 'ISO 19115-1:2014', 'ISO', 'documentDigital', 'ISO
19115-1', 'Geographic Information — Metadata Part 1: Fundamentals'),
- ('ISO 19115-2', NULL, 'ISO 19115-2:2019', 'ISO', 'documentDigital', 'ISO
19115-2', 'Geographic Information — Metadata Part 2: Extensions for imagery
and gridded data'),
- ('IHO S-57', NULL, '3.1', 'IHO', 'documentDigital',
'S-57', 'IHO transfer standard for digital hydrographic data'),
- ('MGRS', NULL, NULL, 'NATO', 'documentDigital',
NULL, 'Military Grid Reference System'),
- ('WMS', 'WMS', '1.3', 'OGC', 'documentDigital',
'WMS', 'Web Map Server'),
- ('EPSG', 'EPSG', NULL, 'IOGP', 'tableDigital',
'EPSG Dataset', 'EPSG Geodetic Parameter Dataset'),
- ('ArcGIS', 'ESRI', NULL, 'ESRI', NULL,
NULL, 'ArcGIS'),
- ('MapInfo', NULL, NULL, 'MapInfo', NULL,
'MapInfo', 'MapInfo Pro'),
- ('PROJ', 'PROJ', NULL, 'OSGeo', NULL,
'Proj', 'PROJ coordinate transformation software library'),
- ('GDAL', 'GDAL', NULL, 'OSGeo', NULL,
NULL, 'Geospatial Data Abstraction Library'),
- ('SIS', 'SIS', NULL, 'Apache', NULL,
'Apache SIS', 'Apache Spatial Information System');
+ ('ISBN', 'ISBN', NULL, 'ISBN', NULL,
'ISBN', 'International Standard Book Number'),
+ ('ISSN', 'ISSN', NULL, 'ISSN', NULL,
'ISSN', 'International Standard Serial Number'),
+ ('ISO 19115-1', NULL, 'ISO 19115-1:2014', 'ISO', 'documentDigital',
'ISO 19115-1', 'Geographic Information — Metadata Part 1: Fundamentals'),
+ ('ISO 19115-2', NULL, 'ISO 19115-2:2019', 'ISO', 'documentDigital',
'ISO 19115-2', 'Geographic Information — Metadata Part 2: Extensions for
imagery and gridded data'),
+ ('IHO S-57', NULL, '3.1', 'IHO', 'documentDigital',
'S-57', 'IHO transfer standard for digital hydrographic data'),
+ ('MGRS', NULL, NULL, 'NATO', 'documentDigital',
NULL, 'Military Grid Reference System'),
+ ('WMS', 'WMS', '1.3', 'OGC', 'documentDigital',
'WMS', 'Web Map Server'),
+ ('EPSG', 'EPSG', NULL, 'IOGP', 'tableDigital',
'EPSG Dataset', 'EPSG Geodetic Parameter Dataset'),
+ ('ArcGIS', 'ESRI', NULL, 'ESRI', NULL,
NULL, 'ArcGIS'),
+ ('MapInfo', NULL, NULL, 'MapInfo', NULL,
'MapInfo', 'MapInfo Pro'),
+ ('PROJ', 'PROJ', NULL, 'OSGeo', NULL,
'Proj', 'PROJ coordinate transformation software library'),
+ ('GDAL', 'GDAL', NULL, 'OSGeo', NULL,
'GDAL', 'Geospatial Data Abstraction Library'),
+ ('Unidata', 'Unidata', NULL, 'UCAR', NULL,
NULL, 'Unidata netCDF library'),
+ ('SIS', 'SIS', NULL, 'Apache', NULL,
'Apache SIS', 'Apache Spatial Information System');
@@ -233,4 +237,4 @@ INSERT INTO metadata."Citation" ("ID", "onlineResource",
"citedResponsibleParty"
('WMO', 'WMO', 'WMO', 'documentDigital', 'WMO Information System (WIS)'),
('IOGP', 'IOGP', 'IOGP', 'documentDigital', 'IOGP Surveying and Positioning
Guidance Note 7');
-UPDATE metadata."Citation" SET "identifier" = "ID" WHERE "ID"<>'ISBN' AND
"ID"<>'ISSN' AND "ID"<>'MGRS';
+UPDATE metadata."Citation" SET "identifier" = "ID" WHERE "ID"<>'ISBN' AND
"ID"<>'ISSN' AND "ID"<>'MGRS' AND "ID"<>'Unidata';
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataFallback.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataFallback.java
index c275652657..edee1c42fe 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataFallback.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataFallback.java
@@ -110,7 +110,7 @@ final class MetadataFallback extends MetadataSource {
CharSequence title;
CharSequence alternateTitle = null;
CharSequence edition = null;
- String code = null;
+ String code = key;
String codeSpace = null;
String version = null;
CharSequence citedResponsibleParty = null;
@@ -141,29 +141,25 @@ final class MetadataFallback extends MetadataSource {
title = "Web Map Server";
alternateTitle = "WMS";
edition = version = "1.3";
- code = "WMS"; // Note: OGC internal code is
06-042.
codeSpace = "OGC";
copyFrom = "OGC";
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
- case "OGC": {
+ case Constants.OGC: {
title = "OGC Naming Authority";
- code = Constants.OGC;
citedResponsibleParty = "Open Geospatial Consortium";
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
case "WMO": {
title = "WMO Information System (WIS)";
- code = key;
citedResponsibleParty = "World Meteorological Organization";
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
- case "IOGP": { // Not in public API (see Citations.IOGP
javadoc)
+ case Constants.IOGP: { // Not in public API (see Citations.IOGP
javadoc)
title = "IOGP Surveying and Positioning Guidance
Note 7";
- code = Constants.IOGP;
copyFrom = Constants.EPSG;
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
@@ -171,7 +167,6 @@ final class MetadataFallback extends MetadataSource {
case Constants.EPSG: {
title = "EPSG Geodetic Parameter Dataset";
alternateTitle = "EPSG Dataset";
- code = Constants.EPSG;
codeSpace = Constants.IOGP;
citedResponsibleParty = "International Association of Oil &
Gas producers";
presentationForm = PresentationForm.TABLE_DIGITAL;
@@ -179,32 +174,37 @@ final class MetadataFallback extends MetadataSource {
}
case Constants.SIS: {
title = "Apache Spatial Information System";
- code = key;
codeSpace = "Apache";
break;
}
case "ISBN": {
title = "International Standard Book Number";
alternateTitle = key;
+ code = null;
break;
}
case "ISSN": {
title = "International Standard Serial Number";
alternateTitle = key;
+ code = null;
break;
}
case "PROJ": {
title = "PROJ coordinate transformation software library";
- code = "PROJ";
codeSpace = "OSGeo";
break;
}
case Constants.GDAL: {
- title = "Geospatial Data Abstraction Library";
- code = key;
+ title = "Geospatial Data Abstraction Library";
+ alternateTitle = "GDAL";
codeSpace = "OSGeo";
break;
}
+ case "Unidata": {
+ title = "Unidata netCDF library";
+ code = null;
+ break;
+ }
case "IHO S-57": {
title = code = "S-57";
codeSpace = "IHO";
diff --git
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/citation/CitationsTest.java
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/citation/CitationsTest.java
index 8be419e1a4..1e15401bc4 100644
---
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/citation/CitationsTest.java
+++
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/citation/CitationsTest.java
@@ -91,7 +91,7 @@ public final class CitationsTest extends TestCase {
assertSame(IOGP, fromName(Constants.IOGP));
assertSame(IOGP, fromName("OGP"));
assertSame(ESRI, fromName("ESRI")); // Handled in
a way very similar to "OGC".
- assertSame(NETCDF, fromName("NetCDF"));
+ assertSame(NETCDF, fromName(Constants.NETCDF));
assertSame(GEOTIFF, fromName(Constants.GEOTIFF));
assertSame(PROJ4, fromName("Proj.4"));
assertSame(PROJ4, fromName("Proj4"));
diff --git
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
index a1d4ad0cd1..6ff30f8380 100644
---
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
+++
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/sql/MetadataFallbackVerifier.java
@@ -24,6 +24,7 @@ import org.apache.sis.metadata.MetadataStandard;
import org.apache.sis.metadata.internal.CitationConstant;
import org.apache.sis.metadata.iso.citation.Citations;
import static org.apache.sis.util.privy.CollectionsExt.first;
+import org.apache.sis.util.privy.Constants;
// Test dependencies
import org.junit.jupiter.api.Test;
@@ -45,7 +46,7 @@ public final class MetadataFallbackVerifier {
/**
* Identifier for which {@link MetadataFallback} does not provide
hard-coded values.
*/
- private static final Set<String> EXCLUDES = Set.of("NetCDF", "GeoTIFF",
"ArcGIS", "MapInfo");
+ private static final Set<String> EXCLUDES = Set.of(Constants.NETCDF,
Constants.GEOTIFF, "ArcGIS", "MapInfo");
/**
* Creates a new test case.
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NorthPoleRotation.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NorthPoleRotation.java
index 84ab4fecf0..d796a8d838 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NorthPoleRotation.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NorthPoleRotation.java
@@ -30,6 +30,7 @@ import org.apache.sis.parameter.Parameters;
import org.apache.sis.measure.Longitude;
import org.apache.sis.measure.Latitude;
import org.apache.sis.measure.Units;
+import org.apache.sis.util.privy.Constants;
/**
@@ -104,7 +105,7 @@ public final class NorthPoleRotation extends
AbstractProvider {
*/
public static final ParameterDescriptorGroup PARAMETERS;
static {
- final ParameterBuilder builder = new
ParameterBuilder().setCodeSpace(Citations.NETCDF, "NetCDF").setRequired(true);
+ final ParameterBuilder builder = new
ParameterBuilder().setCodeSpace(Citations.NETCDF,
Constants.NETCDF).setRequired(true);
POLE_LATITUDE = builder
.addNameAndIdentifier(Citations.SIS,
SouthPoleRotation.POLE_LATITUDE)
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/SouthPoleRotation.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/SouthPoleRotation.java
index 4720654bef..c945ca7936 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/SouthPoleRotation.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/SouthPoleRotation.java
@@ -30,6 +30,7 @@ import org.apache.sis.parameter.Parameters;
import org.apache.sis.measure.Longitude;
import org.apache.sis.measure.Latitude;
import org.apache.sis.measure.Units;
+import org.apache.sis.util.privy.Constants;
/**
@@ -114,7 +115,7 @@ public final class SouthPoleRotation extends
AbstractProvider {
*/
public static final ParameterDescriptorGroup PARAMETERS;
static {
- final ParameterBuilder builder = new
ParameterBuilder().setCodeSpace(Citations.NETCDF, "NetCDF").setRequired(true);
+ final ParameterBuilder builder = new
ParameterBuilder().setCodeSpace(Citations.NETCDF,
Constants.NETCDF).setRequired(true);
POLE_LATITUDE = builder
.addName(Citations.SIS, "Latitude of rotated pole")
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
index 6f5907a965..6dab2cb236 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/LandsatStore.java
@@ -223,7 +223,7 @@ public class LandsatStore extends DataStore implements
Aggregate {
source = null; // Will be closed at the end of this
try-finally block.
final var parser = new MetadataReader(this, getDisplayName(),
listeners);
parser.read(reader);
- parser.addFormatReader(getProvider());
+ parser.addFormatReaderSIS(LandsatStoreProvider.NAME);
metadata = parser.getMetadata();
/*
* Create the array of components. The resource identifier is the
band name.
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
index ba59a0aa86..a4cf6a0906 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
@@ -48,7 +48,6 @@ import org.apache.sis.metadata.iso.DefaultMetadata;
import org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
import org.apache.sis.metadata.iso.content.DefaultSampleDimension;
import org.apache.sis.metadata.iso.content.DefaultCoverageDescription;
-import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.referencing.CRS;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.storage.DataStoreException;
@@ -469,15 +468,12 @@ final class MetadataReader extends MetadataBuilder {
* Value is "GEOTIFF".
*/
case "OUTPUT_FORMAT": {
- String name = value;
- if (Constants.GEOTIFF.equalsIgnoreCase(name)) try {
- name = Constants.GEOTIFF; // Because
`metadata.setPredefinedFormat(…)` is case-sensitive.
- setPredefinedFormat(name);
- break;
- } catch (MetadataStoreException e) {
- warning(key, null, e);
+ if (Constants.GEOTIFF.equalsIgnoreCase(value)) {
+ setPredefinedFormat(Constants.GEOTIFF, listeners, true);
+ } else {
+ addFormatName(value);
}
- addFormatName(name);
+ // Do not invoke `addFormatReaderSIS(name)`, it will be done
by the caller.
break;
}
/*
diff --git
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
index 954c104830..31099f6d44 100644
---
a/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
+++
b/endorsed/src/org.apache.sis.storage.earthobservation/test/org/apache/sis/storage/landsat/MetadataReaderTest.java
@@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.*;
import org.apache.sis.test.TestCase;
// Specific to the geoapi-3.1 and geoapi-4.0 branches:
+import static java.util.Map.entry;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -55,6 +56,16 @@ import org.opengis.test.dataset.ContentVerifier;
* @author Martin Desruisseaux (Geomatys)
*/
public final class MetadataReaderTest extends TestCase {
+ /**
+ * Helper class for verifying metadata content.
+ */
+ private ContentVerifier verifier;
+
+ /**
+ * A buffer for building paths to expected properties.
+ */
+ private StringBuilder buffer;
+
/**
* Creates a new test case.
*/
@@ -92,180 +103,139 @@ public final class MetadataReaderTest extends TestCase {
reader.read(in);
actual = reader.getMetadata();
}
- final ContentVerifier verifier = new ContentVerifier();
+ verifier = new ContentVerifier();
verifier.addPropertyToIgnore(Metadata.class, "metadataStandard");
// Because hard-coded in SIS.
verifier.addPropertyToIgnore(Metadata.class, "referenceSystemInfo");
// Very verbose and depends on EPSG connection.
verifier.addPropertyToIgnore(TemporalExtent.class, "extent");
// Because currently time-zone sensitive.
verifier.addMetadataToVerify(actual);
verifier.addExpectedValues(
- "defaultLocale+otherLocale[0]",
"en",
- "metadataIdentifier.code",
"LandsatTest",
- "metadataScope[0].resourceScope",
ScopeCode.COVERAGE,
- "dateInfo[0].date",
OffsetDateTime.of(2016, 6, 27, 16, 48, 12, 0,
ZoneOffset.UTC),
- "dateInfo[0].dateType",
DateType.CREATION,
- "identificationInfo[0].topicCategory[0]",
TopicCategory.GEOSCIENTIFIC_INFORMATION,
- "identificationInfo[0].citation.date[0].date",
OffsetDateTime.of(2016, 6, 27, 16, 48, 12, 0,
ZoneOffset.UTC),
- "identificationInfo[0].citation.date[0].dateType",
DateType.CREATION,
- "identificationInfo[0].citation.title",
"LandsatTest",
- "identificationInfo[0].credit[0]",
"Derived from U.S. Geological Survey data",
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.title",
"GeoTIFF Coverage Encoding Profile",
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.alternateTitle[0]",
"GeoTIFF",
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].party[0].name",
"Open Geospatial Consortium",
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].role",
Role.PRINCIPAL_INVESTIGATOR,
-
"identificationInfo[0].extent[0].geographicElement[0].extentTypeCode",
true,
-
"identificationInfo[0].extent[0].geographicElement[0].westBoundLongitude",
108.34,
-
"identificationInfo[0].extent[0].geographicElement[0].eastBoundLongitude",
110.44,
-
"identificationInfo[0].extent[0].geographicElement[0].southBoundLatitude",
10.50,
-
"identificationInfo[0].extent[0].geographicElement[0].northBoundLatitude",
12.62,
- "identificationInfo[0].spatialResolution[0].distance",
15.0,
- "identificationInfo[0].spatialResolution[1].distance",
30.0,
-
- "acquisitionInformation[0].platform[0].identifier.code",
"Pseudo LANDSAT",
-
"acquisitionInformation[0].platform[0].instrument[0].identifier.code", "Pseudo
TIRS",
-
"acquisitionInformation[0].acquisitionRequirement[0].identifier.code",
"Software unit tests",
-
"acquisitionInformation[0].operation[0].significantEvent[0].context",
Context.ACQUISITION,
- "acquisitionInformation[0].operation[0].significantEvent[0].time",
OffsetDateTime.of(2016, 6, 26, 3, 2, 1, 90_000_000, ZoneOffset.UTC),
- "acquisitionInformation[0].operation[0].status",
Progress.COMPLETED,
- "acquisitionInformation[0].operation[0].type",
OperationType.REAL,
-
- "contentInfo[0].processingLevelCode.authority.title",
"Landsat",
- "contentInfo[0].processingLevelCode.codeSpace",
"Landsat",
- "contentInfo[0].processingLevelCode.code",
"Pseudo LT1",
-
- "contentInfo[0].attributeGroup[0].attribute[0].description",
"Coastal Aerosol",
- "contentInfo[0].attributeGroup[0].attribute[1].description",
"Blue",
- "contentInfo[0].attributeGroup[0].attribute[2].description",
"Green",
- "contentInfo[0].attributeGroup[0].attribute[3].description",
"Red",
- "contentInfo[0].attributeGroup[0].attribute[4].description",
"Near-Infrared",
- "contentInfo[0].attributeGroup[0].attribute[5].description",
"Short Wavelength Infrared (SWIR) 1",
- "contentInfo[0].attributeGroup[0].attribute[6].description",
"Short Wavelength Infrared (SWIR) 2",
- "contentInfo[0].attributeGroup[0].attribute[7].description",
"Cirrus",
- "contentInfo[0].attributeGroup[1].attribute[0].description",
"Panchromatic",
- "contentInfo[0].attributeGroup[2].attribute[0].description",
"Thermal Infrared Sensor (TIRS) 1",
- "contentInfo[0].attributeGroup[2].attribute[1].description",
"Thermal Infrared Sensor (TIRS) 2",
+ entry("defaultLocale+otherLocale[0]", "en"),
+ entry("metadataIdentifier.code", "LandsatTest"),
+ entry("metadataScope[0].resourceScope", ScopeCode.COVERAGE),
+ entry("dateInfo[0].date", OffsetDateTime.of(2016, 6,
27, 16, 48, 12, 0, ZoneOffset.UTC)),
+ entry("dateInfo[0].dateType", DateType.CREATION),
- "contentInfo[0].attributeGroup[0].attribute[0].minValue", 1.0,
- "contentInfo[0].attributeGroup[0].attribute[1].minValue", 1.0,
- "contentInfo[0].attributeGroup[0].attribute[2].minValue", 1.0,
- "contentInfo[0].attributeGroup[0].attribute[3].minValue", 1.0,
- "contentInfo[0].attributeGroup[0].attribute[4].minValue", 1.0,
- "contentInfo[0].attributeGroup[0].attribute[5].minValue", 1.0,
- "contentInfo[0].attributeGroup[0].attribute[6].minValue", 1.0,
- "contentInfo[0].attributeGroup[0].attribute[7].minValue", 1.0,
- "contentInfo[0].attributeGroup[1].attribute[0].minValue", 1.0,
- "contentInfo[0].attributeGroup[2].attribute[0].minValue", 1.0,
- "contentInfo[0].attributeGroup[2].attribute[1].minValue", 1.0,
+ entry("identificationInfo[0].topicCategory[0]",
TopicCategory.GEOSCIENTIFIC_INFORMATION),
+ entry("identificationInfo[0].citation.date[0].date",
OffsetDateTime.of(2016, 6, 27, 16, 48, 12, 0, ZoneOffset.UTC)),
+ entry("identificationInfo[0].citation.date[0].dateType",
DateType.CREATION),
+ entry("identificationInfo[0].citation.title",
"LandsatTest"),
+ entry("identificationInfo[0].credit[0]", "Derived from U.S.
Geological Survey data"),
- "contentInfo[0].attributeGroup[0].attribute[0].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[0].attribute[1].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[0].attribute[2].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[0].attribute[3].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[0].attribute[4].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[0].attribute[5].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[0].attribute[6].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[0].attribute[7].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[1].attribute[0].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[2].attribute[0].maxValue",
65535.0,
- "contentInfo[0].attributeGroup[2].attribute[1].maxValue",
65535.0,
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.title",
"GeoTIFF Coverage Encoding Profile"),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.alternateTitle[0]",
"GeoTIFF"),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].party[0].name",
"Open Geospatial Consortium"),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].role",
Role.PRINCIPAL_INVESTIGATOR),
- "contentInfo[0].attributeGroup[0].attribute[0].peakResponse",
433.0,
- "contentInfo[0].attributeGroup[0].attribute[1].peakResponse",
482.0,
- "contentInfo[0].attributeGroup[0].attribute[2].peakResponse",
562.0,
- "contentInfo[0].attributeGroup[0].attribute[3].peakResponse",
655.0,
- "contentInfo[0].attributeGroup[0].attribute[4].peakResponse",
865.0,
- "contentInfo[0].attributeGroup[0].attribute[5].peakResponse",
1610.0,
- "contentInfo[0].attributeGroup[0].attribute[6].peakResponse",
2200.0,
- "contentInfo[0].attributeGroup[0].attribute[7].peakResponse",
1375.0,
- "contentInfo[0].attributeGroup[1].attribute[0].peakResponse",
590.0,
- "contentInfo[0].attributeGroup[2].attribute[0].peakResponse",
10800.0,
- "contentInfo[0].attributeGroup[2].attribute[1].peakResponse",
12000.0,
+
entry("identificationInfo[0].extent[0].geographicElement[0].extentTypeCode",
true),
+
entry("identificationInfo[0].extent[0].geographicElement[0].westBoundLongitude",
108.34),
+
entry("identificationInfo[0].extent[0].geographicElement[0].eastBoundLongitude",
110.44),
+
entry("identificationInfo[0].extent[0].geographicElement[0].southBoundLatitude",
10.50),
+
entry("identificationInfo[0].extent[0].geographicElement[0].northBoundLatitude",
12.62),
+ entry("identificationInfo[0].spatialResolution[0].distance", 15.0),
+ entry("identificationInfo[0].spatialResolution[1].distance", 30.0),
-
"contentInfo[0].attributeGroup[0].attribute[0].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[0].attribute[1].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[0].attribute[2].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[0].attribute[3].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[0].attribute[4].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[0].attribute[5].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[0].attribute[6].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[0].attribute[7].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[1].attribute[0].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[2].attribute[0].transferFunctionType",
TransferFunctionType.LINEAR,
-
"contentInfo[0].attributeGroup[2].attribute[1].transferFunctionType",
TransferFunctionType.LINEAR,
+ entry("acquisitionInformation[0].platform[0].identifier.code",
"Pseudo LANDSAT"),
+
entry("acquisitionInformation[0].platform[0].instrument[0].identifier.code",
"Pseudo TIRS"),
+
entry("acquisitionInformation[0].acquisitionRequirement[0].identifier.code",
"Software unit tests"),
+
entry("acquisitionInformation[0].operation[0].significantEvent[0].context",
Context.ACQUISITION),
+
entry("acquisitionInformation[0].operation[0].significantEvent[0].time",
OffsetDateTime.of(2016, 6, 26, 3, 2, 1, 90_000_000, ZoneOffset.UTC)),
+ entry("acquisitionInformation[0].operation[0].status",
Progress.COMPLETED),
+ entry("acquisitionInformation[0].operation[0].type",
OperationType.REAL),
- "contentInfo[0].attributeGroup[0].attribute[0].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[0].attribute[1].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[0].attribute[2].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[0].attribute[3].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[0].attribute[4].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[0].attribute[5].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[0].attribute[6].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[0].attribute[7].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[1].attribute[0].scaleFactor",
2.0E-5,
- "contentInfo[0].attributeGroup[2].attribute[0].scaleFactor",
0.000334,
- "contentInfo[0].attributeGroup[2].attribute[1].scaleFactor",
0.000334,
+ entry("contentInfo[0].processingLevelCode.authority.title",
"Landsat"),
+ entry("contentInfo[0].processingLevelCode.codeSpace",
"Landsat"),
+ entry("contentInfo[0].processingLevelCode.code",
"Pseudo LT1"),
- "contentInfo[0].attributeGroup[0].attribute[0].offset", -0.1,
- "contentInfo[0].attributeGroup[0].attribute[1].offset", -0.1,
- "contentInfo[0].attributeGroup[0].attribute[2].offset", -0.1,
- "contentInfo[0].attributeGroup[0].attribute[3].offset", -0.1,
- "contentInfo[0].attributeGroup[0].attribute[4].offset", -0.1,
- "contentInfo[0].attributeGroup[0].attribute[5].offset", -0.1,
- "contentInfo[0].attributeGroup[0].attribute[6].offset", -0.1,
- "contentInfo[0].attributeGroup[0].attribute[7].offset", -0.1,
- "contentInfo[0].attributeGroup[1].attribute[0].offset", -0.1,
- "contentInfo[0].attributeGroup[2].attribute[0].offset", 0.1,
- "contentInfo[0].attributeGroup[2].attribute[1].offset", 0.1,
+ entry("contentInfo[0].cloudCoverPercentage", 8.3),
+ entry("contentInfo[0].illuminationAzimuthAngle", 116.9),
+ entry("contentInfo[0].illuminationElevationAngle", 58.8),
- "contentInfo[0].attributeGroup[0].attribute[0].units", "",
- "contentInfo[0].attributeGroup[0].attribute[1].units", "",
- "contentInfo[0].attributeGroup[0].attribute[2].units", "",
- "contentInfo[0].attributeGroup[0].attribute[3].units", "",
- "contentInfo[0].attributeGroup[0].attribute[4].units", "",
- "contentInfo[0].attributeGroup[0].attribute[5].units", "",
- "contentInfo[0].attributeGroup[0].attribute[6].units", "",
- "contentInfo[0].attributeGroup[0].attribute[7].units", "",
- "contentInfo[0].attributeGroup[1].attribute[0].units", "",
+ entry("spatialRepresentationInfo[0].numberOfDimensions", 2),
+ entry("spatialRepresentationInfo[1].numberOfDimensions", 2),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionName",
DimensionNameType.SAMPLE),
+
entry("spatialRepresentationInfo[1].axisDimensionProperties[0].dimensionName",
DimensionNameType.SAMPLE),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionName",
DimensionNameType.LINE),
+
entry("spatialRepresentationInfo[1].axisDimensionProperties[1].dimensionName",
DimensionNameType.LINE),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionSize",
7600),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionSize",
7800),
+
entry("spatialRepresentationInfo[1].axisDimensionProperties[0].dimensionSize",
15000),
+
entry("spatialRepresentationInfo[1].axisDimensionProperties[1].dimensionSize",
15500),
+
entry("spatialRepresentationInfo[0].transformationParameterAvailability",
false),
+
entry("spatialRepresentationInfo[1].transformationParameterAvailability",
false),
+ entry("spatialRepresentationInfo[0].checkPointAvailability",
false),
+ entry("spatialRepresentationInfo[1].checkPointAvailability",
false),
- "contentInfo[0].attributeGroup[0].attribute[0].boundUnits", "nm",
- "contentInfo[0].attributeGroup[0].attribute[1].boundUnits", "nm",
- "contentInfo[0].attributeGroup[0].attribute[2].boundUnits", "nm",
- "contentInfo[0].attributeGroup[0].attribute[3].boundUnits", "nm",
- "contentInfo[0].attributeGroup[0].attribute[4].boundUnits", "nm",
- "contentInfo[0].attributeGroup[0].attribute[5].boundUnits", "nm",
- "contentInfo[0].attributeGroup[0].attribute[6].boundUnits", "nm",
- "contentInfo[0].attributeGroup[0].attribute[7].boundUnits", "nm",
- "contentInfo[0].attributeGroup[1].attribute[0].boundUnits", "nm",
- "contentInfo[0].attributeGroup[2].attribute[0].boundUnits", "nm",
- "contentInfo[0].attributeGroup[2].attribute[1].boundUnits", "nm",
+ entry("resourceLineage[0].source[0].description", "Pseudo GLS"));
- "contentInfo[0].attributeGroup[0].contentType[0]",
CoverageContentType.PHYSICAL_MEASUREMENT,
- "contentInfo[0].attributeGroup[1].contentType[0]",
CoverageContentType.PHYSICAL_MEASUREMENT,
- "contentInfo[0].attributeGroup[2].contentType[0]",
CoverageContentType.PHYSICAL_MEASUREMENT,
-
- "contentInfo[0].cloudCoverPercentage", 8.3,
- "contentInfo[0].illuminationAzimuthAngle", 116.9,
- "contentInfo[0].illuminationElevationAngle", 58.8,
-
- "spatialRepresentationInfo[0].numberOfDimensions",
2,
- "spatialRepresentationInfo[1].numberOfDimensions",
2,
-
"spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionName",
DimensionNameType.SAMPLE,
-
"spatialRepresentationInfo[1].axisDimensionProperties[0].dimensionName",
DimensionNameType.SAMPLE,
-
"spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionName",
DimensionNameType.LINE,
-
"spatialRepresentationInfo[1].axisDimensionProperties[1].dimensionName",
DimensionNameType.LINE,
-
"spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionSize", 7600,
-
"spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionSize", 7800,
-
"spatialRepresentationInfo[1].axisDimensionProperties[0].dimensionSize", 15000,
-
"spatialRepresentationInfo[1].axisDimensionProperties[1].dimensionSize", 15500,
-
"spatialRepresentationInfo[0].transformationParameterAvailability", false,
-
"spatialRepresentationInfo[1].transformationParameterAvailability", false,
- "spatialRepresentationInfo[0].checkPointAvailability",
false,
- "spatialRepresentationInfo[1].checkPointAvailability",
false,
-
- "resourceLineage[0].source[0].description", "Pseudo GLS");
+ /*
+ * The expected values in
"contentInfo[0].attributeGroup[…].attribute[…].*" have a lot of redundancy.
+ * Therefore, we set those expected values by loop instead of
repeating tens of long property paths.
+ */
+ final String[] descriptions = {
+ "Coastal Aerosol",
+ "Blue",
+ "Green",
+ "Red",
+ "Near-Infrared",
+ "Short Wavelength Infrared (SWIR) 1",
+ "Short Wavelength Infrared (SWIR) 2",
+ "Cirrus",
+ "Panchromatic",
+ "Thermal Infrared Sensor (TIRS) 1",
+ "Thermal Infrared Sensor (TIRS) 2"
+ };
+ final short[] peakResponses = {433, 482, 562, 655, 865, 1610, 2200,
1375, 590, 10800, 12000};
+ int band = 0;
+ buffer = new
StringBuilder(80).append("contentInfo[0].attributeGroup[");
+ final int groupBase = buffer.length();
+ final int[] numAttributes = {8, 1, 2};
+ for (int group = 0; group < numAttributes.length; group++) {
+ final boolean mainGroups = (group != 2);
+ /*
+ * contentInfo[0].attributeGroup[0…2].contentType[0]
+ */
+ buffer.setLength(groupBase);
+ buffer.append(group).append("].");
+ addExpectedValue("contentType[0]",
CoverageContentType.PHYSICAL_MEASUREMENT);
+ /*
+ * contentInfo[0].attributeGroup[0…2].attribute[…].minValue
+ * contentInfo[0].attributeGroup[0…2].attribute[…].maxValue
+ * ... etc ...
+ */
+ final int attributeBase = buffer.append("attribute[").length();
+ for (int attribute = 0; attribute < numAttributes[group];
attribute++) {
+ buffer.setLength(attributeBase);
+ buffer.append(attribute).append("].");
+ addExpectedValue("minValue", 1.0);
+ addExpectedValue("maxValue", 65535.0);
+ addExpectedValue("description", descriptions[band]);
+ addExpectedValue("peakResponse", (double)
peakResponses[band++]);
+ addExpectedValue("boundUnits", "nm");
+ addExpectedValue("transferFunctionType",
TransferFunctionType.LINEAR);
+ addExpectedValue("scaleFactor", mainGroups ? 2.0E-5 :
0.000334);
+ addExpectedValue("offset", mainGroups ? -0.1 : 0.1);
+ if (mainGroups) {
+ addExpectedValue("units", "");
+ }
+ }
+ }
+ assertEquals(descriptions.length, band);
+ assertEquals(peakResponses.length, band);
verifier.assertMetadataEquals();
}
+ /**
+ * Adds an expected value for the given property. The path to that
property is the
+ * current content of {@link #buffer}, including a trailing {@code '.'}
separator.
+ * The buffer is reset to its original length after this method call.
+ */
+ private void addExpectedValue(final String tip, Object value) {
+ final int length = buffer.length();
+ verifier.addExpectedValue(buffer.append(tip).toString(), value);
+ buffer.setLength(length);
+ }
+
/**
* Creates a dummy set of store listeners.
* Used only for constructors that require a non-null {@link
StoreListeners} instance.
diff --git
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
index d16c7bd3b5..9ddabf81b3 100644
---
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
+++
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStore.java
@@ -21,7 +21,6 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Optional;
-import java.util.logging.Level;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.net.URI;
@@ -62,7 +61,6 @@ import org.apache.sis.io.stream.ChannelDataInput;
import org.apache.sis.io.stream.ChannelDataOutput;
import org.apache.sis.io.stream.IOUtilities;
import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.coverage.SubspaceNotSpecifiedException;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridGeometry;
@@ -382,13 +380,8 @@ public class GeoTiffStore extends DataStore implements
Aggregate {
* Sets the {@code metadata/identificationInfo/resourceFormat} node to
"GeoTIFF" format.
*/
final void setFormatInfo(final MetadataBuilder builder) {
- try {
- builder.setPredefinedFormat(Constants.GEOTIFF);
- } catch (MetadataStoreException e) {
- builder.addFormatName(Constants.GEOTIFF);
- listeners.warning(Level.FINE, null, e);
- }
- builder.addFormatReader(getProvider());
+ builder.setPredefinedFormat(Constants.GEOTIFF, listeners, true);
+ builder.addFormatReaderSIS(Constants.GEOTIFF);
builder.addLanguage(Locale.ENGLISH, encoding,
MetadataBuilder.Scope.METADATA);
builder.addResourceScope(ScopeCode.COVERAGE, null);
}
diff --git
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
index 1d257bc899..890cf53904 100644
---
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
+++
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -25,7 +25,6 @@ import java.util.LinkedHashSet;
import java.util.LinkedHashMap;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.logging.Level;
import java.io.IOException;
import java.time.temporal.Temporal;
import ucar.nc2.constants.CF; // String constants are copied by the
compiler with no UCAR reference left.
@@ -51,7 +50,6 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.metadata.iso.DefaultMetadata;
import org.apache.sis.metadata.iso.citation.*;
import org.apache.sis.metadata.iso.identification.*;
-import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.base.MetadataBuilder;
import org.apache.sis.storage.event.StoreListeners;
@@ -69,6 +67,7 @@ import org.apache.sis.system.Configuration;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.iso.Types;
import org.apache.sis.util.privy.CollectionsExt;
+import org.apache.sis.util.privy.Constants;
import org.apache.sis.util.privy.CodeLists;
import org.apache.sis.util.privy.Strings;
import org.apache.sis.util.resources.Errors;
@@ -656,22 +655,30 @@ split: while ((start =
CharSequences.skipLeadingWhitespaces(value, start, lengt
addBoundingPolygon(new StoreFormat(null, null, decoder.geomlib,
decoder.listeners).parseGeometry(wkt,
stringValue(GEOSPATIAL_BOUNDS + "_crs"),
stringValue(GEOSPATIAL_BOUNDS + "_vertical_crs")));
}
- final String[] format = decoder.getFormatDescription();
- String id = format[0];
- if (NetcdfStoreProvider.NAME.equalsIgnoreCase(id)) try {
- setPredefinedFormat(NetcdfStoreProvider.NAME);
- id = null;
- } catch (MetadataStoreException e) {
- // Will add `id` at the end of this method.
- decoder.listeners.warning(Level.FINE, null, e);
- }
- if (format.length >= 2) {
- addFormatName(format[1]);
- if (format.length >= 3) {
- setFormatEdition(format[2]);
- }
+ /*
+ * Add a description of the format. The description is determined by
the decoder in use.
+ * That decoder may itself infer that description from another library
such as UCAR.
+ */
+ decoder.addFormatDescription(this);
+ }
+
+ /**
+ * Adds the format description with a check about whether the given format
identifier is recognized.
+ * This is a helper method for {@link
Decoder#addFormatDescription(MetadataBuilder)} implementations.
+ *
+ * @param format format identifier. Recognized value is {@value
NetcdfStoreProvider#NAME}.
+ * @param listeners ignored. Will be replaced by the listeners of the
decoder.
+ * @param fallback whether to use a fallback if the description was not
found.
+ * @return whether the format description has been added.
+ */
+ @Override
+ public boolean setPredefinedFormat(String format, StoreListeners
listeners, boolean fallback) {
+ if (Constants.NETCDF.equalsIgnoreCase(format)) {
+ return super.setPredefinedFormat(format, decoder.listeners,
fallback);
+ } else if (fallback) {
+ addFormatName(format);
}
- addFormatName(id); // Do nothing is `id` is null.
+ return false;
}
/**
diff --git
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStore.java
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStore.java
index 21fb0746c5..39f7c2229b 100644
---
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStore.java
+++
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStore.java
@@ -48,6 +48,7 @@ import org.apache.sis.setup.OptionKey;
import org.apache.sis.util.Version;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.privy.Strings;
+import org.apache.sis.util.privy.Constants;
import org.apache.sis.util.privy.UnmodifiableArrayList;
import org.apache.sis.util.collection.DefaultTreeTable;
import org.apache.sis.util.collection.TableColumn;
@@ -117,7 +118,7 @@ public class NetcdfStore extends DataStore implements
Aggregate {
throw new DataStoreException(e);
}
if (decoder == null) {
- throw new UnsupportedStorageException(super.getLocale(),
NetcdfStoreProvider.NAME,
+ throw new UnsupportedStorageException(super.getLocale(),
Constants.NETCDF,
connector.getStorage(),
connector.getOption(OptionKey.OPEN_OPTIONS));
}
decoder.location = path;
@@ -217,7 +218,7 @@ public class NetcdfStore extends DataStore implements
Aggregate {
public Optional<TreeTable> getNativeMetadata() throws DataStoreException {
final DefaultTreeTable table = new DefaultTreeTable(TableColumn.NAME,
TableColumn.VALUE);
final TreeTable.Node root = table.getRoot();
- root.setValue(TableColumn.NAME, NetcdfStoreProvider.NAME);
+ root.setValue(TableColumn.NAME, Constants.NETCDF);
decoder().addAttributesTo(root);
return Optional.of(table);
}
@@ -294,7 +295,7 @@ public class NetcdfStore extends DataStore implements
Aggregate {
private Decoder decoder() throws DataStoreClosedException {
final Decoder reader = decoder;
if (reader == null) {
- throw new DataStoreClosedException(getLocale(),
NetcdfStoreProvider.NAME, StandardOpenOption.READ);
+ throw new DataStoreClosedException(getLocale(), Constants.NETCDF,
StandardOpenOption.READ);
}
return reader;
}
diff --git
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
index 8acabbcba4..2a37675b3b 100644
---
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
+++
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
@@ -52,6 +52,7 @@ import org.apache.sis.setup.OptionKey;
import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.util.Version;
import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.privy.Constants;
/**
@@ -72,7 +73,7 @@ import org.apache.sis.util.logging.Logging;
*
* @since 0.3
*/
-@StoreMetadata(formatName = NetcdfStoreProvider.NAME,
+@StoreMetadata(formatName = Constants.NETCDF,
fileSuffixes = "nc",
capabilities = Capability.READ,
resourceTypes = {Aggregate.class, FeatureSet.class,
GridCoverageResource.class},
@@ -85,11 +86,6 @@ import org.apache.sis.util.logging.Logging;
* specialized readers to be tested before this generic netCDF reader.
*/
public class NetcdfStoreProvider extends DataStoreProvider {
- /**
- * The format name.
- */
- static final String NAME = "NetCDF";
-
/**
* The MIME type for netCDF files.
*/
@@ -98,7 +94,7 @@ public class NetcdfStoreProvider extends DataStoreProvider {
/**
* The parameter descriptor to be returned by {@link #getOpenParameters()}.
*/
- private static final ParameterDescriptorGroup OPEN_DESCRIPTOR =
URIDataStoreProvider.descriptor(NAME);
+ private static final ParameterDescriptorGroup OPEN_DESCRIPTOR =
URIDataStoreProvider.descriptor(Constants.NETCDF);
/**
* The name of the {@link ucar.nc2.NetcdfFile} class, which is {@value}.
@@ -161,7 +157,7 @@ public class NetcdfStoreProvider extends DataStoreProvider {
*/
@Override
public String getShortName() {
- return NAME;
+ return Constants.NETCDF;
}
/**
diff --git
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/Decoder.java
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/Decoder.java
index 545f8c968b..14bf4b1c2a 100644
---
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/Decoder.java
+++
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/base/Decoder.java
@@ -39,6 +39,7 @@ import org.apache.sis.system.Modules;
import org.apache.sis.setup.GeometryLibrary;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.base.MetadataBuilder;
import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.storage.netcdf.internal.Resources;
import org.apache.sis.util.Utilities;
@@ -233,19 +234,15 @@ public abstract class Decoder extends
ReferencingFactoryContainer {
public abstract String getFilename();
/**
- * Returns an identification of the file format. This method should
returns an array of length 1, 2 or 3 as below:
+ * Adds to the given metadata an identification of the file format.
+ * Subclasses should invoke the following methods:
*
* <ul>
- * <li>One of the following identifier in the first element: {@code
"NetCDF"}, {@code "NetCDF-4"} or other values
- * defined by the UCAR library. If known, it will be used as an
identifier for a more complete description to
- * be provided by {@link
org.apache.sis.metadata.sql.MetadataSource#lookup(Class, String)}.</li>
- * <li>Optionally a human-readable description in the second array
element.</li>
- * <li>Optionally a version in the third array element.</li>
+ * <li>{@link MetadataBuilder#setPredefinedFormat(String,
StoreListeners, boolean)}</li>
+ * <li>{@link MetadataBuilder#addFormatReaderSIS(String)} (if
applicable)</li>
* </ul>
- *
- * @return identification of the file format, human-readable description
and version number.
*/
- public abstract String[] getFormatDescription();
+ public abstract void addFormatDescription(MetadataBuilder builder);
/**
* Defines the groups where to search for named attributes, in preference
order.
diff --git
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/classic/ChannelDecoder.java
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/classic/ChannelDecoder.java
index e920decb07..c8430ff09c 100644
---
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/classic/ChannelDecoder.java
+++
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/classic/ChannelDecoder.java
@@ -45,6 +45,7 @@ import
org.opengis.parameter.InvalidParameterCardinalityException;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.storage.base.MetadataBuilder;
import org.apache.sis.storage.netcdf.base.DataType;
import org.apache.sis.storage.netcdf.base.Decoder;
import org.apache.sis.storage.netcdf.base.Node;
@@ -262,8 +263,9 @@ public final class ChannelDecoder extends Decoder {
* Read the dimension, attribute and variable declarations. We expect
exactly 3 lists,
* where any of them can be flagged as absent by a long (64 bits) 0.
*/
- DimensionInfo[] dimensions = null;
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
VariableInfo[] variables = null;
+ DimensionInfo[] dimensions = null;
List<Map.Entry<String,Object>> attributes = List.of();
for (int i=0; i<3; i++) {
final long tn = input.readLong(); // Combination
of tag and nelems
@@ -676,14 +678,13 @@ public final class ChannelDecoder extends Decoder {
}
/**
- * Returns an identification of the file format. The returned value is a
reference to a database entry
+ * Sets an identification of the file format. This method uses a reference
to a database entry
* known to {@link
org.apache.sis.metadata.sql.MetadataSource#lookup(Class, String)}.
- *
- * @return an identification of the file format in an array of length 1.
*/
@Override
- public String[] getFormatDescription() {
- return new String[] {"NetCDF"};
+ public void addFormatDescription(MetadataBuilder builder) {
+ builder.setPredefinedFormat(Constants.NETCDF, null, true);
+ builder.addFormatReaderSIS(Constants.NETCDF);
}
/**
@@ -719,6 +720,7 @@ public final class ChannelDecoder extends Decoder {
* @return dimension of the given name, or {@code null} if none.
*/
@Override
+ @SuppressWarnings("StringEquality")
protected Dimension findDimension(final String dimName) {
DimensionInfo dim = dimensionMap.get(dimName); // Give
precedence to exact match before to ignore case.
if (dim == null) {
@@ -736,6 +738,7 @@ public final class ChannelDecoder extends Decoder {
* @param name the name of the variable to search, or {@code null}.
* @return the variable of the given name, or {@code null} if none.
*/
+ @SuppressWarnings("StringEquality")
private VariableInfo findVariableInfo(final String name) {
VariableInfo v = variableMap.get(name);
if (v == null && name != null) {
@@ -782,6 +785,7 @@ public final class ChannelDecoder extends Decoder {
*
* @see #getAttributeNames()
*/
+ @SuppressWarnings("StringEquality")
private Object findAttribute(final String name) {
if (name == null) {
return null;
diff --git
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/ucar/DecoderWrapper.java
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/ucar/DecoderWrapper.java
index b62529d2d7..5f813e9e2f 100644
---
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/ucar/DecoderWrapper.java
+++
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/ucar/DecoderWrapper.java
@@ -42,11 +42,19 @@ import ucar.nc2.ft.FeatureDataset;
import ucar.nc2.ft.FeatureDatasetPoint;
import ucar.nc2.ft.FeatureDatasetFactoryManager;
import ucar.nc2.ft.DsgFeatureCollection;
+import org.opengis.metadata.citation.Citation;
+import org.apache.sis.util.Version;
import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.privy.Constants;
import org.apache.sis.util.collection.TreeTable;
import org.apache.sis.util.collection.TableColumn;
+import org.apache.sis.metadata.sql.MetadataSource;
+import org.apache.sis.metadata.sql.MetadataStoreException;
+import org.apache.sis.referencing.ImmutableIdentifier;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.base.MetadataBuilder;
+import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.storage.netcdf.base.Decoder;
import org.apache.sis.storage.netcdf.base.Variable;
import org.apache.sis.storage.netcdf.base.Dimension;
@@ -55,7 +63,6 @@ import org.apache.sis.storage.netcdf.base.Grid;
import org.apache.sis.storage.netcdf.base.Convention;
import org.apache.sis.storage.netcdf.base.DiscreteSampling;
import org.apache.sis.setup.GeometryLibrary;
-import org.apache.sis.storage.event.StoreListeners;
/**
@@ -64,6 +71,17 @@ import org.apache.sis.storage.event.StoreListeners;
* @author Martin Desruisseaux (Geomatys)
*/
public final class DecoderWrapper extends Decoder implements CancelTask {
+ /**
+ * Version of the <abbr>UCAR</abbr> library, fetched when first requested.
+ * May be {@code null} if no version information was found.
+ */
+ private static Version version;
+
+ /**
+ * Whether {@link #version} has been initialized. The result may still be
null.
+ */
+ private static boolean versionInitialized;
+
/**
* The netCDF file to read.
* This file is set at construction time.
@@ -171,21 +189,45 @@ public final class DecoderWrapper extends Decoder
implements CancelTask {
/**
* Returns the file format information provided by the UCAR library.
+ * The information includes:
+ *
+ * <ol>
+ * <li>{@code "NetCDF"}, {@code "NetCDF-4"} or other values defined by
the UCAR library.
+ * If known, it will be used as an identifier for a more complete
description to be
+ * provided by {@link
org.apache.sis.metadata.sql.MetadataSource#lookup(Class, String)}.</li>
+ * <li>Optionally a human-readable description.</li>
+ * <li>Optionally a file format version.</li>
+ * </ol>
*
* @return identification of the file format, human-readable description
and version number.
*/
@Override
- @SuppressWarnings("fallthrough")
- public String[] getFormatDescription() {
- final String version = Utils.nonEmpty(file.getFileTypeVersion());
- final String[] format = new String[version != null ? 3 : 2];
- switch (format.length) {
- default: format[2] = version; //
Fallthrough everywhere.
- case 2: format[1] = file.getFileTypeDescription();
- case 1: format[0] = file.getFileTypeId();
- case 0: break; // As a
matter of principle.
+ public void addFormatDescription(MetadataBuilder builder) {
+ String name = Utils.nonEmpty(file.getFileTypeId());
+ if (builder.setPredefinedFormat(name, null, false)) {
+ name = null;
}
- return format;
+ builder.addFormatName(Utils.nonEmpty(file.getFileTypeDescription()));
+ builder.setFormatEdition(Utils.nonEmpty(file.getFileTypeVersion()));
+ builder.addFormatName(name); // Do nothing if `name` is null.
+ Citation provider;
+ try {
+ provider = MetadataSource.getProvided().lookup(Citation.class,
"Unidata");
+ } catch (MetadataStoreException e) {
+ provider = null;
+ }
+ builder.addFormatReader(new ImmutableIdentifier(provider, "UCAR",
Constants.NETCDF), getVersion());
+ }
+
+ /**
+ * Returns the version number of the netCDF library, or {@code null} if
not found.
+ */
+ private static synchronized Version getVersion() {
+ if (!versionInitialized) {
+ versionInitialized = true;
+ version = Version.ofLibrary(NetcdfFile.class).orElse(null);
+ }
+ return version;
}
/**
@@ -194,6 +236,7 @@ public final class DecoderWrapper extends Decoder
implements CancelTask {
*/
@Override
public void setSearchPath(final String... groupNames) {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final Group[] groups = new Group[groupNames.length];
int count = 0;
for (final String name : groupNames) {
diff --git
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/MetadataReaderTest.java
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/MetadataReaderTest.java
index 3550322273..ceabb95e9e 100644
---
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/MetadataReaderTest.java
+++
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/MetadataReaderTest.java
@@ -22,6 +22,7 @@ import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import org.opengis.metadata.Metadata;
import org.opengis.metadata.citation.Role;
+import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.citation.DateType;
import org.opengis.metadata.extent.TemporalExtent;
import org.opengis.metadata.identification.KeywordType;
@@ -41,6 +42,7 @@ import org.apache.sis.storage.netcdf.base.TestCase;
import org.apache.sis.storage.netcdf.classic.ChannelDecoderTest;
// Specific to the geoapi-3.1 and geoapi-4.0 branches:
+import static java.util.Map.entry;
import org.opengis.test.dataset.ContentVerifier;
import org.opengis.test.dataset.TestData;
@@ -118,66 +120,70 @@ public final class MetadataReaderTest extends TestCase {
* @param ucar whether the UCAR wrapper is used.
*/
static ContentVerifier compareToExpected(final Metadata actual, final
boolean ucar) {
- final ContentVerifier verifier = new ContentVerifier();
+ final var verifier = new ContentVerifier();
verifier.addPropertyToIgnore(Metadata.class, "metadataStandard");
verifier.addPropertyToIgnore(Metadata.class, "referenceSystemInfo");
+ verifier.addPropertyToIgnore(Citation.class, "otherCitationDetails");
// "Read by Foo version XYZ" in format citation.
verifier.addPropertyToIgnore(TemporalExtent.class, "extent");
+ verifier.addPropertyToIgnore((path) ->
path.equals("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.identifier[0].authority"));
verifier.addMetadataToVerify(actual);
verifier.addExpectedValues(
// Hard-coded
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.alternateTitle[0]",
"NetCDF",
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.title",
"NetCDF Classic and 64-bit Offset Format",
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].party[0].name",
"Open Geospatial Consortium",
-
"identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].role",
Role.PRINCIPAL_INVESTIGATOR,
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.alternateTitle[0]",
"NetCDF"),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.title",
"NetCDF Classic and 64-bit Offset Format"),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].party[0].name",
"Open Geospatial Consortium"),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.citedResponsibleParty[0].role",
Role.PRINCIPAL_INVESTIGATOR),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.identifier[0].codeSpace",
ucar ? "UCAR" : "SIS"),
+
entry("identificationInfo[0].resourceFormat[0].formatSpecificationCitation.identifier[0].code",
"NetCDF"),
// Read from the file
- "dateInfo[0].date",
actual(LocalDateTime.of(2018, 5, 15, 13, 1), ucar),
- "dateInfo[0].dateType",
DateType.REVISION,
- "metadataScope[0].resourceScope",
ScopeCode.DATASET,
- "identificationInfo[0].abstract",
"Global, two-dimensional model data",
- "identificationInfo[0].purpose",
"GeoAPI conformance tests",
- "identificationInfo[0].supplementalInformation",
"For testing purpose only.",
- "identificationInfo[0].citation.title",
"Test data from Sea Surface Temperature Analysis Model",
- "identificationInfo[0].descriptiveKeywords[0].keyword[0]",
"EARTH SCIENCE > Oceans > Ocean Temperature > Sea Surface Temperature",
-
"identificationInfo[0].descriptiveKeywords[0].thesaurusName.title",
"GCMD Science Keywords",
- "identificationInfo[0].descriptiveKeywords[0].type",
KeywordType.THEME,
- "identificationInfo[0].pointOfContact[0].role",
Role.POINT_OF_CONTACT,
- "identificationInfo[0].pointOfContact[0].party[0].name",
"NOAA/NWS/NCEP",
- "identificationInfo[0].citation.citedResponsibleParty[0].role",
Role.ORIGINATOR,
-
"identificationInfo[0].citation.citedResponsibleParty[0].party[0].name",
"NOAA/NWS/NCEP",
- "identificationInfo[0].citation.date[0].date",
actual(LocalDateTime.of(2005, 9, 22, 0, 0), ucar),
- "identificationInfo[0].citation.date[1].date",
actual(LocalDateTime.of(2018, 5, 15, 13, 0), ucar),
- "identificationInfo[0].citation.date[0].dateType",
DateType.CREATION,
- "identificationInfo[0].citation.date[1].dateType",
DateType.REVISION,
- "identificationInfo[0].citation.identifier[0].code",
"NCEP/SST/Global_5x2p5deg/SST_Global_5x2p5deg_20050922_0000.nc",
- "identificationInfo[0].citation.identifier[0].authority.title",
"edu.ucar.unidata",
- "identificationInfo[0].resourceConstraints[0].useLimitation[0]",
"Freely available",
-
"identificationInfo[0].extent[0].geographicElement[0].extentTypeCode",
Boolean.TRUE,
-
"identificationInfo[0].extent[0].geographicElement[0].westBoundLongitude",
-180.0,
-
"identificationInfo[0].extent[0].geographicElement[0].eastBoundLongitude",
180.0,
-
"identificationInfo[0].extent[0].geographicElement[0].southBoundLatitude",
-90.0,
-
"identificationInfo[0].extent[0].geographicElement[0].northBoundLatitude",
90.0,
- "identificationInfo[0].extent[0].verticalElement[0].maximumValue",
0.0,
- "identificationInfo[0].extent[0].verticalElement[0].minimumValue",
0.0,
- "identificationInfo[0].spatialRepresentationType[0]",
SpatialRepresentationType.GRID,
- "spatialRepresentationInfo[0].cellGeometry",
CellGeometry.AREA,
- "spatialRepresentationInfo[0].numberOfDimensions",
2,
-
"spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionName",
DimensionNameType.COLUMN,
-
"spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionName",
DimensionNameType.ROW,
-
"spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionSize", 73,
-
"spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionSize", 73,
-
"spatialRepresentationInfo[0].transformationParameterAvailability",
false,
+ entry("dateInfo[0].date",
actual(LocalDateTime.of(2018, 5, 15, 13, 1), ucar)),
+ entry("dateInfo[0].dateType",
DateType.REVISION),
+ entry("metadataScope[0].resourceScope",
ScopeCode.DATASET),
+ entry("identificationInfo[0].abstract",
"Global, two-dimensional model data"),
+ entry("identificationInfo[0].purpose",
"GeoAPI conformance tests"),
+ entry("identificationInfo[0].supplementalInformation",
"For testing purpose only."),
+ entry("identificationInfo[0].citation.title",
"Test data from Sea Surface Temperature Analysis Model"),
+ entry("identificationInfo[0].descriptiveKeywords[0].keyword[0]",
"EARTH SCIENCE > Oceans > Ocean Temperature > Sea Surface
Temperature"),
+
entry("identificationInfo[0].descriptiveKeywords[0].thesaurusName.title",
"GCMD Science Keywords"),
+ entry("identificationInfo[0].descriptiveKeywords[0].type",
KeywordType.THEME),
+ entry("identificationInfo[0].pointOfContact[0].role",
Role.POINT_OF_CONTACT),
+ entry("identificationInfo[0].pointOfContact[0].party[0].name",
"NOAA/NWS/NCEP"),
+
entry("identificationInfo[0].citation.citedResponsibleParty[0].role",
Role.ORIGINATOR),
+
entry("identificationInfo[0].citation.citedResponsibleParty[0].party[0].name",
"NOAA/NWS/NCEP"),
+ entry("identificationInfo[0].citation.date[0].date",
actual(LocalDateTime.of(2005, 9, 22, 0, 0), ucar)),
+ entry("identificationInfo[0].citation.date[1].date",
actual(LocalDateTime.of(2018, 5, 15, 13, 0), ucar)),
+ entry("identificationInfo[0].citation.date[0].dateType",
DateType.CREATION),
+ entry("identificationInfo[0].citation.date[1].dateType",
DateType.REVISION),
+ entry("identificationInfo[0].citation.identifier[0].code",
"NCEP/SST/Global_5x2p5deg/SST_Global_5x2p5deg_20050922_0000.nc"),
+
entry("identificationInfo[0].citation.identifier[0].authority.title",
"edu.ucar.unidata"),
+
entry("identificationInfo[0].resourceConstraints[0].useLimitation[0]",
"Freely available"),
+
entry("identificationInfo[0].extent[0].geographicElement[0].extentTypeCode",
Boolean.TRUE),
+
entry("identificationInfo[0].extent[0].geographicElement[0].westBoundLongitude",
-180.0),
+
entry("identificationInfo[0].extent[0].geographicElement[0].eastBoundLongitude",
180.0),
+
entry("identificationInfo[0].extent[0].geographicElement[0].southBoundLatitude",
-90.0),
+
entry("identificationInfo[0].extent[0].geographicElement[0].northBoundLatitude",
90.0),
+
entry("identificationInfo[0].extent[0].verticalElement[0].maximumValue",
0.0),
+
entry("identificationInfo[0].extent[0].verticalElement[0].minimumValue",
0.0),
+ entry("identificationInfo[0].spatialRepresentationType[0]",
SpatialRepresentationType.GRID),
+ entry("spatialRepresentationInfo[0].cellGeometry",
CellGeometry.AREA),
+ entry("spatialRepresentationInfo[0].numberOfDimensions",
2),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionName",
DimensionNameType.COLUMN),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionName",
DimensionNameType.ROW),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[0].dimensionSize",
73),
+
entry("spatialRepresentationInfo[0].axisDimensionProperties[1].dimensionSize",
73),
+
entry("spatialRepresentationInfo[0].transformationParameterAvailability",
false),
// Variable descriptions (only one in this test).
-
"contentInfo[0].attributeGroup[0].attribute[0].sequenceIdentifier",
"SST",
- "contentInfo[0].attributeGroup[0].attribute[0].description",
"Sea temperature",
- "contentInfo[0].attributeGroup[0].attribute[0].name[0].code",
"sea_water_temperature",
-
"contentInfo[0].attributeGroup[0].attribute[0].transferFunctionType",
TransferFunctionType.LINEAR,
- "contentInfo[0].attributeGroup[0].attribute[0].scaleFactor",
0.0011,
- "contentInfo[0].attributeGroup[0].attribute[0].offset",
-1.85,
- "contentInfo[0].attributeGroup[0].attribute[0].units",
"°C",
+
entry("contentInfo[0].attributeGroup[0].attribute[0].sequenceIdentifier",
"SST"),
+ entry("contentInfo[0].attributeGroup[0].attribute[0].description",
"Sea temperature"),
+
entry("contentInfo[0].attributeGroup[0].attribute[0].name[0].code",
"sea_water_temperature"),
+
entry("contentInfo[0].attributeGroup[0].attribute[0].transferFunctionType",
TransferFunctionType.LINEAR),
+ entry("contentInfo[0].attributeGroup[0].attribute[0].scaleFactor",
0.0011),
+ entry("contentInfo[0].attributeGroup[0].attribute[0].offset",
-1.85),
+ entry("contentInfo[0].attributeGroup[0].attribute[0].units",
"°C"),
- "resourceLineage[0].statement", "Decimated and modified by GeoAPI
for inclusion in conformance test suite.");
+ entry("resourceLineage[0].statement", "Decimated and modified by
GeoAPI for inclusion in conformance test suite."));
return verifier;
}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
index a6acdad992..258a05277a 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
@@ -97,7 +97,6 @@ import org.apache.sis.geometry.AbstractEnvelope;
import org.apache.sis.storage.AbstractResource;
import org.apache.sis.storage.AbstractFeatureSet;
import org.apache.sis.storage.AbstractGridCoverageResource;
-import org.apache.sis.storage.DataStoreProvider;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.storage.internal.Resources;
@@ -1037,34 +1036,34 @@ public class MetadataBuilder {
* </ul>
*
* This method should be invoked <strong>before</strong> any other method
writing in the
- * {@code identificationInfo/resourceFormat} node. If this exception
throws an exception,
- * than that exception should be reported as a warning. Example:
- *
- * {@snippet lang="java" :
- * try {
- * metadata.setPredefinedFormat("MyFormat");
- * } catch (MetadataStoreException e) {
- * metadata.addFormatName("MyFormat");
- * listeners.warning(Level.FINE, null, e);
- * }
- * metadata.addCompression("decompression technique");
- * }
+ * {@code identificationInfo/resourceFormat} node.
*
* @param abbreviation the format short name or abbreviation, or {@code
null} for no-operation.
- * @throws MetadataStoreException if this method cannot connect to the
{@code jdbc/SpatialMetadata} database.
- * Callers should generally handle this exception as a recoverable
one (i.e. log a warning and continue).
+ * @param listeners where to report a failure to connect to the
{@code jdbc/SpatialMetadata} database.
+ * @param fallback whether to fallback on {@link
#addFormatName(String)} if the description was not found.
+ * @return whether the format description has been added.
*
* @see #addCompression(CharSequence)
* @see #addFormatName(CharSequence)
*/
- public final void setPredefinedFormat(final String abbreviation) throws
MetadataStoreException {
+ public boolean setPredefinedFormat(final String abbreviation, final
StoreListeners listeners, boolean fallback) {
if (abbreviation != null && abbreviation.length() != 0) {
- if (format == null) {
+ if (format == null) try {
format = MetadataSource.getProvided().lookup(Format.class,
abbreviation);
- } else {
+ return true;
+ } catch (MetadataStoreException e) {
+ if (listeners != null) {
+ listeners.warning(Level.FINE, null, e);
+ } else {
+ Logging.recoverableException(StoreUtilities.LOGGER, null,
null, e);
+ }
+ }
+ if (fallback) {
addFormatName(abbreviation);
+ return true;
}
}
+ return false;
}
/**
@@ -3028,12 +3027,11 @@ public class MetadataBuilder {
* <li>{@code
metadata/identificationInfo/resourceFormat/formatSpecificationCitation/alternateTitle}</li>
* </ul>
*
- * If this method is used together with {@link
#setPredefinedFormat(String)},
- * then {@code setPredefinedFormat(…)} should be invoked
<strong>before</strong> this method.
+ * If this method is used together with {@link #setPredefinedFormat
setPredefinedFormat(…)},
+ * then the predefined format should be set <strong>before</strong> this
method.
*
* @param value the format name, or {@code null} for no-operation.
*
- * @see #setPredefinedFormat(String)
* @see #setFormatEdition(CharSequence)
* @see #addCompression(CharSequence)
*/
@@ -3073,12 +3071,11 @@ public class MetadataBuilder {
* <li>{@code
metadata/identificationInfo/resourceFormat/formatSpecificationCitation/edition}</li>
* </ul>
*
- * If this method is used together with {@link
#setPredefinedFormat(String)},
- * then {@code setPredefinedFormat(…)} should be invoked
<strong>before</strong> this method.
+ * If this method is used together with {@link #setPredefinedFormat
setPredefinedFormat(…)},
+ * then the predefined format should be set <strong>before</strong> this
method.
*
* @param value the format edition, or {@code null} for no-operation.
*
- * @see #setPredefinedFormat(String)
* @see #addFormatName(CharSequence)
*/
public final void setFormatEdition(final CharSequence value) {
@@ -3097,19 +3094,29 @@ public class MetadataBuilder {
* <li>{@code
metadata/identificationInfo/resourceFormat/formatSpecificationCitation/otherCitationDetails}</li>
* </ul>
*
- * If this method is used together with {@link
#setPredefinedFormat(String)},
- * then {@code setPredefinedFormat(…)} should be invoked
<strong>before</strong> this method.
+ * If this method is used together with {@link #setPredefinedFormat
setPredefinedFormat(…)},
+ * then the predefined format should be set <strong>before</strong> this
method.
*
* @param driver library-specific way to identify the format (mandatory).
* @param version the library version, or {@code null} if unknown.
*/
public final void addFormatReader(final Identifier driver, final Version
version) {
+ CharSequence title = null;
+ Citation authority = driver.getAuthority();
+ if (authority != null) {
+ title = authority.getTitle();
+ if (title != null) {
+ for (CharSequence t : authority.getAlternateTitles()) {
+ if (t.length() < title.length()) {
+ title = t; // Alternate titles are often
abbreviations.
+ }
+ }
+ }
+ }
final DefaultCitation c = getFormatCitation();
addIfNotPresent(c.getIdentifiers(), driver);
addIfNotPresent(c.getOtherCitationDetails(),
- Resources.formatInternational(
- Resources.Keys.ReadBy_2,
- driver.getCodeSpace(),
+ Resources.formatInternational(Resources.Keys.ReadBy_2, (title
!= null) ? title : driver.getCodeSpace(),
(version != null) ? version :
Vocabulary.formatInternational(Vocabulary.Keys.Unspecified)));
}
@@ -3117,13 +3124,11 @@ public class MetadataBuilder {
* Adds a note saying that Apache <abbr>SIS</abbr> has been used for
decoding the format.
* This method should not be invoked before the {@linkplain #addFormatName
format name} has been set.
*
- * @param provider the data store provider, or {@code null} if
unspecified.
+ * @param name the format name, or {@code null} if unspecified.
*/
- public final void addFormatReader(final DataStoreProvider provider) {
- if (provider != null) {
- String name = provider.getShortName();
- var driver = (name != null) ? new
ImmutableIdentifier(Citations.SIS, Constants.SIS, name) : null;
- addFormatReader(driver, Version.SIS);
+ public void addFormatReaderSIS(final String name) {
+ if (name != null) {
+ addFormatReader(new ImmutableIdentifier(Citations.SIS,
Constants.SIS, name), Version.SIS);
}
}
@@ -3135,12 +3140,11 @@ public class MetadataBuilder {
* <li>{@code
metadata/identificationInfo/resourceFormat/fileDecompressionTechnique}</li>
* </ul>
*
- * If this method is used together with {@link
#setPredefinedFormat(String)},
- * then {@code setPredefinedFormat(…)} should be invoked
<strong>before</strong> this method.
+ * If this method is used together with {@link #setPredefinedFormat
setPredefinedFormat(…)},
+ * then the predefined format should be set <strong>before</strong> this
method.
*
* @param value the compression name, or {@code null} for no-operation.
*
- * @see #setPredefinedFormat(String)
* @see #addFormatName(CharSequence)
*/
public final void addCompression(final CharSequence value) {
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/Store.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/Store.java
index 119e835081..c45855411b 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/Store.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/Store.java
@@ -32,7 +32,6 @@ import java.io.BufferedReader;
import java.io.LineNumberReader;
import java.io.IOException;
import java.net.URI;
-import java.nio.charset.Charset;
import javax.measure.Unit;
import javax.measure.quantity.Time;
import org.opengis.util.GenericName;
@@ -71,7 +70,6 @@ import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.geometry.ImmutableEnvelope;
import org.apache.sis.geometry.wrapper.Geometries;
import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.setup.OptionKey;
import org.apache.sis.measure.Units;
@@ -140,13 +138,6 @@ final class Store extends URIDataStore implements
FeatureSet {
*/
private BufferedReader source;
- /**
- * The character encoding, or {@code null} if unspecified (in which case
the platform default is assumed).
- * Note that the default value is different than the moving feature
specification, which requires UTF-8.
- * See "Departures from Moving Features specification" in package javadoc.
- */
- private final Charset encoding;
-
/**
* The metadata object, or {@code null} if not yet created.
*/
@@ -235,9 +226,9 @@ final class Store extends URIDataStore implements
FeatureSet {
source = (r instanceof BufferedReader) ? (BufferedReader) r : new
LineNumberReader(r);
geometries =
Geometries.factory(connector.getOption(OptionKey.GEOMETRY_LIBRARY));
dissociate =
connector.getOption(DataOptionKey.FOLIATION_REPRESENTATION) ==
FoliationRepresentation.FRAGMENTED;
- GeneralEnvelope envelope = null;
- FeatureType featureType = null;
- Foliation foliation = null;
+ @SuppressWarnings("LocalVariableHidesMemberVariable") GeneralEnvelope
envelope = null;
+ @SuppressWarnings("LocalVariableHidesMemberVariable") FeatureType
featureType = null;
+ @SuppressWarnings("LocalVariableHidesMemberVariable") Foliation
foliation = null;
try {
final List<String> elements = new ArrayList<>();
source.mark(StorageConnector.READ_AHEAD_LIMIT);
@@ -296,7 +287,6 @@ final class Store extends URIDataStore implements
FeatureSet {
} catch (IllegalArgumentException | DateTimeException e) {
throw new DataStoreContentException(getLocale(),
StoreProvider.NAME, super.getDisplayName(), source).initCause(e);
}
- this.encoding = connector.getOption(OptionKey.ENCODING);
this.envelope = ImmutableEnvelope.castOrCopy(envelope);
this.featureType = featureType;
this.foliation = foliation;
@@ -349,8 +339,10 @@ final class Store extends URIDataStore implements
FeatureSet {
*/
@SuppressWarnings("fallthrough")
private GeneralEnvelope parseEnvelope(final List<String> elements) throws
DataStoreException, FactoryException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ int spatialDimensionCount = 2; // Another result of this method
to be computed as a side-effect.
+
CoordinateReferenceSystem crs = null;
- int spatialDimensionCount = 2;
boolean isDimExplicit = false;
double[] lowerCorner = ArraysExt.EMPTY_DOUBLE;
double[] upperCorner = ArraysExt.EMPTY_DOUBLE;
@@ -410,7 +402,8 @@ final class Store extends URIDataStore implements
FeatureSet {
* Assumed never part of the authority code. We need to build the
temporal component ourselves
* in order to set the origin to the start time.
*/
- final GeneralEnvelope envelope;
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final GeneralEnvelope envelope; // Value will be assigned to
`this.envelope` by the caller.
if (crs != null) {
int count = 0;
final CoordinateReferenceSystem[] components = new
CoordinateReferenceSystem[3];
@@ -632,13 +625,8 @@ final class Store extends URIDataStore implements
FeatureSet {
if (metadata == null) {
final MetadataBuilder builder = new MetadataBuilder();
final String format = (timeEncoding != null) && hasTrajectories ?
StoreProvider.MOVING : StoreProvider.NAME;
- try {
- builder.setPredefinedFormat(format);
- } catch (MetadataStoreException e) {
- builder.addFormatName(format);
- listeners.warning(Level.FINE, null, e);
- }
- builder.addFormatReader(getProvider());
+ builder.setPredefinedFormat(format, listeners, true);
+ builder.addFormatReaderSIS(format);
builder.addLanguage(Locale.ENGLISH, encoding,
MetadataBuilder.Scope.ALL);
builder.addResourceScope(ScopeCode.FEATURE, null);
builder.addExtent(envelope, listeners);
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java
index e74e6765ad..75e4d8c67f 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RasterStore.java
@@ -21,7 +21,6 @@ import java.util.Arrays;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Optional;
-import java.util.logging.Level;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.nio.file.NoSuchFileException;
@@ -33,7 +32,6 @@ import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import org.opengis.metadata.Metadata;
import org.opengis.metadata.maintenance.ScopeCode;
-import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.coverage.SampleDimension;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridCoverage2D;
@@ -152,13 +150,8 @@ abstract class RasterStore extends PRJDataStore implements
GridCoverageResource
final void createMetadata(final String formatName, final String formatKey)
throws DataStoreException {
final GridGeometry gridGeometry = getGridGeometry(); // May
cause parsing of header.
final MetadataBuilder builder = new MetadataBuilder();
- try {
- builder.setPredefinedFormat(formatKey);
- } catch (MetadataStoreException e) {
- builder.addFormatName(formatName);
- listeners.warning(Level.FINE, null, e);
- }
- builder.addFormatReader(getProvider());
+ builder.setPredefinedFormat(formatKey, listeners, true);
+ builder.addFormatReaderSIS(provider != null ? provider.getShortName()
: null);
builder.addResourceScope(ScopeCode.COVERAGE, null);
builder.addLanguage(Locale.ENGLISH, encoding,
MetadataBuilder.Scope.METADATA);
builder.addSpatialRepresentation(null, gridGeometry, true);
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
index b454c8d45a..692af3ddd9 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
@@ -21,7 +21,6 @@ import java.util.Collection;
import java.util.Map;
import java.util.HashMap;
import java.util.Optional;
-import java.util.logging.Level;
import java.io.Closeable;
import java.io.IOException;
import java.io.EOFException;
@@ -54,7 +53,6 @@ import org.apache.sis.storage.base.PRJDataStore;
import org.apache.sis.storage.base.MetadataBuilder;
import org.apache.sis.storage.base.AuxiliaryContent;
import org.apache.sis.referencing.privy.AffineTransform2D;
-import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.privy.ListOfUnknownSize;
@@ -529,17 +527,14 @@ loop: for (int convention=0;; convention++) {
String format = reader().getFormatName();
for (final String key : KNOWN_FORMATS) {
if (key.equalsIgnoreCase(format)) {
- try {
- builder.setPredefinedFormat(key);
+ if (builder.setPredefinedFormat(key, listeners, false)) {
format = null;
- } catch (MetadataStoreException e) {
- listeners.warning(Level.FINE, null, e);
}
break;
}
}
builder.addFormatName(format); // Does
nothing if `format` is null.
- builder.addFormatReader(getProvider());
+ builder.addFormatReaderSIS(WorldFileStoreProvider.NAME);
builder.addResourceScope(ScopeCode.COVERAGE, null);
builder.addSpatialRepresentation(null,
getGridGeometry(MAIN_IMAGE), true);
if (gridGeometry.isDefined(GridGeometry.ENVELOPE)) {
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Version.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Version.java
index deb39d2408..0dfa8fca6c 100644
--- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Version.java
+++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Version.java
@@ -16,8 +16,18 @@
*/
package org.apache.sis.util;
+import java.net.URI;
+import java.net.URL;
+import java.io.File;
import java.io.Serializable;
+import java.util.Optional;
import java.util.StringTokenizer;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+import java.util.logging.Logger;
+import org.apache.sis.system.Modules;
+import org.apache.sis.util.logging.Logging;
import static org.apache.sis.system.Modules.MAJOR_VERSION;
import static org.apache.sis.system.Modules.MINOR_VERSION;
@@ -39,7 +49,7 @@ import static org.apache.sis.system.Modules.MINOR_VERSION;
* encouraged to make sure that subclasses remain immutable for more
predictable behavior.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.4
+ * @version 1.5
* @since 0.3
*/
public class Version implements CharSequence, Comparable<Version>,
Serializable {
@@ -74,6 +84,8 @@ public class Version implements CharSequence,
Comparable<Version>, Serializable
/**
* The version in string form.
+ *
+ * @see #toString()
*/
private final String version;
@@ -102,6 +114,45 @@ public class Version implements CharSequence,
Comparable<Version>, Serializable
this.version = version;
}
+ /**
+ * Returns the version of the library that provides the given class. This
method reads the
+ * {@code "Implementation-Version"} attribute of the {@code
META-INF/MANIFEST.MF} file of
+ * the <abbr>JAR</abbr> file that contains the given class.
+ *
+ * @param member any public class of the library for which to get the
version.
+ * @return version declared by the library that provides the given class.
+ *
+ * @see Attributes.Name#IMPLEMENTATION_VERSION
+ * @since 1.5
+ */
+ public static Optional<Version> ofLibrary(final Class<?> member) {
+ URL url = member.getResource(member.getSimpleName() + ".class");
+ if ("jar".equalsIgnoreCase(url.getProtocol())) {
+ String path = url.getPath();
+ if (path != null) {
+ int s = path.indexOf('!');
+ if (s >= 0) {
+ path = path.substring(0, s);
+ }
+ try (JarFile jar = new JarFile(new File(new URI(path)))) {
+ final Manifest manifest = jar.getManifest();
+ if (manifest != null) {
+ final Attributes attributes =
manifest.getMainAttributes();
+ if (attributes != null) {
+ String version =
attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+ if (version != null) {
+ return Optional.of(new Version(version));
+ }
+ }
+ }
+ } catch (Exception e) {
+
Logging.recoverableException(Logger.getLogger(Modules.UTILITIES),
Version.class, "ofLibrary", e);
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
/**
* Returns an instance for the given integer values.
* The {@code components} array must contain at least 1 element, where:
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Constants.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Constants.java
index 3afa5e81b8..21595c5d94 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Constants.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Constants.java
@@ -138,6 +138,12 @@ public final class Constants extends Static {
*/
public static final String GDAL = "GDAL";
+ /**
+ * The {@value} code space. Uses upper case "N" in the assumption that
this name is used
+ * in the beginning of sentences. Otherwise, the <abbr>UCAR</abbr> usage
is "netCDF".
+ */
+ public static final String NETCDF = "NetCDF";
+
/**
* The {@value} code space. The project name is {@code "Proj.4"}, but this
constant omits
* the dot because this name is used as a code space and we want to avoid
risk of confusion.
diff --git
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/VersionTest.java
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/VersionTest.java
index c7ae3783bf..3932b77c10 100644
--- a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/VersionTest.java
+++ b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/VersionTest.java
@@ -140,4 +140,13 @@ public final class VersionTest extends TestCase {
final Version version = new Version("1.6.b2");
assertNotSame(version, assertSerializedEquals(version));
}
+
+ /**
+ * Tests {@link Version#ofLibrary(Class)}.
+ */
+ @Test
+ public void testOfLibrary() {
+ Version version =
Version.ofLibrary(javax.measure.Unit.class).orElseThrow();
+ assertEquals(Version.valueOf(2, 1, 3), version);
+ }
}
diff --git a/geoapi/snapshot b/geoapi/snapshot
index 367366e67f..8b993c74d8 160000
--- a/geoapi/snapshot
+++ b/geoapi/snapshot
@@ -1 +1 @@
-Subproject commit 367366e67f7f860e100e0e8dafa3a03f34162e71
+Subproject commit 8b993c74d8f49b215f6b4aa2747e0f362d97d3e3