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 e003c32 Review of the addition of Resource.getIdentifier() method: -
Restore import statements in their original order for easier merges between
branches. - Add "throws DataStoreException" in method signature. - Closer
relationship with DataStore.findResource(String). - Review implementations
computing the value from available informations. - Provide scope information
when applicable.
e003c32 is described below
commit e003c327ff8082467a456ac167965b7a0d60d07e
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Oct 13 15:21:28 2018 +0200
Review of the addition of Resource.getIdentifier() method:
- Restore import statements in their original order for easier merges
between branches.
- Add "throws DataStoreException" in method signature.
- Closer relationship with DataStore.findResource(String).
- Review implementations computing the value from available informations.
- Provide scope information when applicable.
---
.../main/java/org/apache/sis/util/iso/Names.java | 2 +-
.../org/apache/sis/internal/util/Citations.java | 2 +-
.../org/apache/sis/internal/util/Numerics.java | 21 +++
.../org/apache/sis/internal/util/NumericsTest.java | 11 ++
.../sis/storage/earthobservation/LandsatStore.java | 85 ++++-----
.../apache/sis/storage/geotiff/GeoTiffStore.java | 135 ++++++++++----
.../sis/storage/geotiff/ImageFileDirectory.java | 39 ++--
.../org/apache/sis/storage/geotiff/Reader.java | 20 ++-
.../org/apache/sis/internal/netcdf/Decoder.java | 24 ++-
.../sis/internal/netcdf/impl/ChannelDecoder.java | 4 +-
.../sis/internal/netcdf/impl/FeaturesInfo.java | 56 +++---
.../sis/internal/netcdf/ucar/DecoderWrapper.java | 4 +-
.../sis/internal/netcdf/ucar/FeaturesWrapper.java | 12 +-
.../apache/sis/storage/netcdf/MetadataReader.java | 14 +-
.../org/apache/sis/storage/netcdf/NetcdfStore.java | 56 ++++--
.../apache/sis/internal/sql/feature/Database.java | 6 +-
.../org/apache/sis/internal/sql/feature/Table.java | 64 +++----
.../java/org/apache/sis/storage/sql/SQLStore.java | 60 +++++--
.../sis/internal/storage/AbstractResource.java | 81 +++++++--
.../sis/internal/storage/JoinFeatureSet.java | 14 +-
.../sis/internal/storage/MemoryFeatureSet.java | 6 +-
.../sis/internal/storage/StoreUtilities.java | 46 +++--
.../org/apache/sis/internal/storage/csv/Store.java | 93 +++++-----
.../apache/sis/internal/storage/folder/Store.java | 115 +++++++-----
.../sis/internal/storage/folder/WritableStore.java | 8 +-
.../sis/internal/storage/query/FeatureSubset.java | 14 +-
.../org/apache/sis/internal/storage/wkt/Store.java | 35 ++--
.../org/apache/sis/internal/storage/xml/Store.java | 65 ++-----
.../java/org/apache/sis/storage/DataStore.java | 200 +++++++++++++--------
.../apache/sis/storage/IllegalNameException.java | 3 +
.../main/java/org/apache/sis/storage/Resource.java | 20 ++-
.../java/org/apache/sis/storage/DataStoreMock.java | 14 +-
.../org/apache/sis/internal/storage/gpx/Store.java | 51 +++---
33 files changed, 831 insertions(+), 549 deletions(-)
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Names.java
b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Names.java
index 78f8acb..7d3f083 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Names.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/Names.java
@@ -97,7 +97,7 @@ public final class Names extends Static {
* @param factory the factory to use for creating the namespace.
* @param namespace the namespace string, taken as a whole (not parsed).
* @param separator the separator between the namespace and the local
part, or {@code null} for the default.
- * @return the namespace object.
+ * @return the namespace object, or {@code null} if the given {@code
namespace} was null or empty.
*/
private static NameSpace createNameSpace(final NameFactory factory, final
CharSequence namespace, final String separator) {
if (namespace == null || namespace.length() == 0) {
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
index 4ca958c..b756bd9 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
@@ -501,7 +501,7 @@ public final class Citations extends Static {
* we will avoid the StringBuilder creation in the vast majority
of times.
*
* Note that 'µ' and its friends are not ignorable, so we do not
remove them.
- * This method is "getUnicodeIdentifier", not "getXmlIdentifier".
+ * This method is aimed for "getUnicodeIdentifier", not
"getXmlIdentifier".
*/
final int length = identifier.length();
for (int i=0; i<length;) {
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
index 876a9ba..5e50833 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
@@ -308,6 +308,27 @@ public final class Numerics extends Static {
}
/**
+ * Returns {@code true} if the following text is non-null, non-empty
+ * and contains only digits from {@code '0'} to {@code '9'} inclusive.
+ *
+ * @param text the text to verify, or {@code null}.
+ * @return {@code true} if the given text is an unsigned integer.
+ */
+ public static boolean isUnsignedInteger(final String text) {
+ if (text != null) {
+ final int length = text.length();
+ if (length != 0) {
+ char c;
+ int i = 0;
+ while ((c = text.charAt(i)) >= '0' && c <= '9') {
+ if (++i >= length) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Converts an unsigned {@code long} to a {@code float} value.
*
* @param value the unsigned {@code long} value.
diff --git
a/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
b/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
index 017a753..bf2889f 100644
---
a/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
+++
b/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
@@ -78,6 +78,17 @@ public final strictfp class NumericsTest extends TestCase {
}
/**
+ * Tests {@link Numerics#isUnsignedInteger(String)}.
+ */
+ @Test
+ public void testIsUnsignedInteger() {
+ assertFalse(Numerics.isUnsignedInteger(null));
+ assertFalse(Numerics.isUnsignedInteger(""));
+ assertTrue (Numerics.isUnsignedInteger("12345"));
+ assertFalse(Numerics.isUnsignedInteger("123A5"));
+ }
+
+ /**
* Tests the {@link Numerics#epsilonEqual(double, double, ComparisonMode)}
method.
*/
@Test
diff --git
a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
index f59594a..46b94ce 100644
---
a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
+++
b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
@@ -16,24 +16,24 @@
*/
package org.apache.sis.storage.earthobservation;
+import java.io.Reader;
import java.io.BufferedReader;
-import java.io.IOException;
import java.io.LineNumberReader;
-import java.io.Reader;
+import java.io.IOException;
import java.net.URI;
-import org.apache.sis.internal.storage.URIDataStore;
-import org.apache.sis.setup.OptionKey;
+import org.opengis.metadata.Metadata;
+import org.opengis.util.GenericName;
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.DataStoreReferencingException;
-import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.UnsupportedStorageException;
+import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.event.ChangeEvent;
import org.apache.sis.storage.event.ChangeListener;
-import org.opengis.metadata.Metadata;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.util.FactoryException;
-import org.opengis.util.GenericName;
+import org.apache.sis.internal.storage.URIDataStore;
+import org.apache.sis.setup.OptionKey;
/**
@@ -86,6 +86,11 @@ public class LandsatStore extends DataStore {
private Metadata metadata;
/**
+ * The identifier, cached when first requested.
+ */
+ private GenericName identifier;
+
+ /**
* Creates a new Landsat store from the given file, URL, stream or
character reader.
* This constructor invokes {@link
StorageConnector#closeAllExcept(Object)},
* keeping open only the needed resource.
@@ -106,14 +111,37 @@ public class LandsatStore extends DataStore {
}
/**
- * Returns a null value.
- * TODO : implement this method when Coverage API will be finished.
+ * Returns the parameters used to open this Landsat data store.
+ * If non-null, the parameters are described by {@link
LandsatStoreProvider#getOpenParameters()} and contains at
+ * least a parameter named {@value
org.apache.sis.storage.DataStoreProvider#LOCATION} with a {@link URI} value.
+ * This method may return {@code null} if the storage input can not be
described by a URI
+ * (for example a Landsat file reading directly from a {@link
java.nio.channels.ReadableByteChannel}).
+ *
+ * @return parameters used for opening this data store, or {@code null} if
not available.
*
- * @return null.
+ * @since 0.8
*/
@Override
- public GenericName getIdentifier() {
- return null;
+ public ParameterValueGroup getOpenParameters() {
+ return URIDataStore.parameters(provider, location);
+ }
+
+ /**
+ * Returns the value associated to {@code LANDSAT_SCENE_ID} in the Landsat
metadata file.
+ * This value is fetched from
+ * <code>{@linkplain
#getMetadata()}/identificationInfo/citation/identifier</code>.
+ *
+ * @return the identifier fetched from metadata, or {@code null} if none.
+ * @throws DataStoreException if an error occurred while reading the
metadata.
+ *
+ * @since 1.0
+ */
+ @Override
+ public synchronized GenericName getIdentifier() throws DataStoreException {
+ if (identifier == null) {
+ identifier = super.getIdentifier();
+ }
+ return identifier;
}
/**
@@ -122,7 +150,7 @@ public class LandsatStore extends DataStore {
* data quality, usage constraints and more.
*
* @return information about the dataset.
- * @throws DataStoreException if an error occurred while reading the data.
+ * @throws DataStoreException if an error occurred while reading the
metadata.
*/
@Override
public synchronized Metadata getMetadata() throws DataStoreException {
@@ -142,22 +170,6 @@ public class LandsatStore extends DataStore {
}
/**
- * Returns the parameters used to open this Landsat data store.
- * If non-null, the parameters are described by {@link
LandsatStoreProvider#getOpenParameters()} and contains at
- * least a parameter named {@value
org.apache.sis.storage.DataStoreProvider#LOCATION} with a {@link URI} value.
- * This method may return {@code null} if the storage input can not be
described by a URI
- * (for example a Landsat file reading directly from a {@link
java.nio.channels.ReadableByteChannel}).
- *
- * @return parameters used for opening this data store, or {@code null} if
not available.
- *
- * @since 0.8
- */
- @Override
- public ParameterValueGroup getOpenParameters() {
- return URIDataStore.parameters(provider, location);
- }
-
- /**
* Ignored in current implementation, since this resource produces no
events.
*
* @param <T> {@inheritDoc}
@@ -188,15 +200,4 @@ public class LandsatStore extends DataStore {
public synchronized void close() throws DataStoreException {
metadata = null;
}
-
- /**
- * Returns a string representation of this Landsat store for debugging
purpose.
- * The content of the string returned by this method may change in any
future SIS version.
- *
- * @return a string representation of this datastore for debugging purpose.
- */
- @Override
- public String toString() {
- return getClass().getSimpleName() + '[' + getDisplayName() + ']';
- }
}
diff --git
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
index ade5c9f..cd8f677 100644
---
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
+++
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
@@ -16,34 +16,40 @@
*/
package org.apache.sis.storage.geotiff;
+import java.util.Locale;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
+import java.util.logging.LogRecord;
import java.nio.charset.StandardCharsets;
import java.nio.file.StandardOpenOption;
-import java.util.Locale;
-import java.util.logging.LogRecord;
-import org.apache.sis.internal.storage.MetadataBuilder;
-import org.apache.sis.internal.storage.URIDataStore;
-import org.apache.sis.internal.storage.io.ChannelDataInput;
-import org.apache.sis.internal.storage.io.IOUtilities;
-import org.apache.sis.internal.util.Constants;
-import org.apache.sis.metadata.sql.MetadataStoreException;
+import org.opengis.util.NameSpace;
+import org.opengis.util.NameFactory;
+import org.opengis.util.GenericName;
+import org.opengis.util.FactoryException;
+import org.opengis.metadata.Metadata;
+import org.opengis.metadata.maintenance.ScopeCode;
+import org.opengis.parameter.ParameterValueGroup;
import org.apache.sis.setup.OptionKey;
+import org.apache.sis.storage.Resource;
import org.apache.sis.storage.DataStore;
-import org.apache.sis.storage.DataStoreClosedException;
-import org.apache.sis.storage.DataStoreContentException;
-import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.UnsupportedStorageException;
+import org.apache.sis.storage.DataStoreClosedException;
+import org.apache.sis.storage.IllegalNameException;
import org.apache.sis.storage.event.ChangeEvent;
import org.apache.sis.storage.event.ChangeListener;
+import org.apache.sis.internal.storage.io.ChannelDataInput;
+import org.apache.sis.internal.storage.io.IOUtilities;
+import org.apache.sis.internal.storage.MetadataBuilder;
+import org.apache.sis.internal.storage.StoreUtilities;
+import org.apache.sis.internal.storage.URIDataStore;
+import org.apache.sis.internal.util.Constants;
+import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.util.resources.Errors;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.maintenance.ScopeCode;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.util.FactoryException;
-import org.opengis.util.GenericName;
/**
@@ -70,10 +76,19 @@ public class GeoTiffStore extends DataStore {
/**
* The {@link GeoTiffStoreProvider#LOCATION} parameter value, or {@code
null} if none.
+ * This is used for information purpose only, not for actual reading
operations.
+ *
+ * @see #getOpenParameters()
*/
private final URI location;
/**
+ * The data store identifier created from the filename, or {@code null} if
none.
+ * Defined as a namespace for use as the scope of children resources (the
images).
+ */
+ final NameSpace identifier;
+
+ /**
* The metadata, or {@code null} if not yet created.
*
* @see #getMetadata()
@@ -105,17 +120,46 @@ public class GeoTiffStore extends DataStore {
} catch (IOException e) {
throw new DataStoreException(e);
}
+ if (location != null) {
+ final NameFactory f = reader.nameFactory;
+ String filename =
IOUtilities.filenameWithoutExtension(input.filename);
+ if (Numerics.isUnsignedInteger(filename)) filename += ".tiff";
+ identifier = f.createNameSpace(f.createLocalName(null, filename),
null);
+ } else {
+ // Location not convertible to URI. The string representation is
probably a class name, which is not useful.
+ identifier = null;
+ }
+ }
+
+ /**
+ * Returns the parameters used to open this GeoTIFF data store.
+ * If non-null, the parameters are described by {@link
GeoTiffStoreProvider#getOpenParameters()} and contains at
+ * least a parameter named {@value
org.apache.sis.storage.DataStoreProvider#LOCATION} with a {@link URI} value.
+ * This method may return {@code null} if the storage input can not be
described by a URI
+ * (for example a GeoTIFF file reading directly from a {@link
java.nio.channels.ReadableByteChannel}).
+ *
+ * @return parameters used for opening this data store, or {@code null} if
not available.
+ *
+ * @since 0.8
+ */
+ @Override
+ public ParameterValueGroup getOpenParameters() {
+ return URIDataStore.parameters(provider, location);
}
/**
- * Returns a null value.
- * TODO : implement this method when Coverage API will be finished.
+ * Returns an identifier constructed from the name of the TIFF file.
+ * An identifier is available only if the storage input specified at
construction time was something convertible to
+ * {@link java.net.URI}, for example an {@link java.net.URL}, {@link
java.io.File} or {@link java.nio.file.Path}.
*
- * @return null.
+ * @return the identifier derived from the filename, or {@code null} if
none.
+ * @throws DataStoreException if an error occurred while fetching the
identifier.
+ *
+ * @since 1.0
*/
@Override
- public GenericName getIdentifier() {
- return null;
+ public GenericName getIdentifier() throws DataStoreException {
+ return (identifier != null) ? identifier.name() : null;
}
/**
@@ -147,7 +191,7 @@ public class GeoTiffStore extends DataStore {
dir.completeMetadata(builder, locale);
}
} catch (IOException e) {
- throw new
DataStoreException(errors().getString(Errors.Keys.CanNotRead_1,
reader.input.filename), e);
+ throw errorIO(e);
} catch (FactoryException | ArithmeticException e) {
throw new DataStoreContentException(getLocale(),
Constants.GEOTIFF, reader.input.filename, null).initCause(e);
}
@@ -157,8 +201,9 @@ public class GeoTiffStore extends DataStore {
* file did not specified any ImageDescription tag, then we will
had the filename as a title instead than an
* identifier because the title is mandatory in ISO 19115 metadata.
*/
- if (location != null) {
-
builder.addTitleOrIdentifier(IOUtilities.filenameWithoutExtension(reader.input.filename),
MetadataBuilder.Scope.ALL);
+ final GenericName id = getIdentifier();
+ if (id != null) {
+ builder.addTitleOrIdentifier(id.toString(),
MetadataBuilder.Scope.ALL);
}
metadata = builder.build(true);
}
@@ -166,19 +211,10 @@ public class GeoTiffStore extends DataStore {
}
/**
- * Returns the parameters used to open this GeoTIFF data store.
- * If non-null, the parameters are described by {@link
GeoTiffStoreProvider#getOpenParameters()} and contains at
- * least a parameter named {@value
org.apache.sis.storage.DataStoreProvider#LOCATION} with a {@link URI} value.
- * This method may return {@code null} if the storage input can not be
described by a URI
- * (for example a GeoTIFF file reading directly from a {@link
java.nio.channels.ReadableByteChannel}).
- *
- * @return parameters used for opening this data store, or {@code null} if
not available.
- *
- * @since 0.8
+ * Returns the exception to throw when an I/O error occurred.
*/
- @Override
- public ParameterValueGroup getOpenParameters() {
- return URIDataStore.parameters(provider, location);
+ private DataStoreException errorIO(final IOException e) {
+ return new
DataStoreException(errors().getString(Errors.Keys.CanNotRead_1,
reader.input.filename), e);
}
/**
@@ -193,6 +229,33 @@ public class GeoTiffStore extends DataStore {
}
/**
+ * Returns the image at the given index. Images numbering starts at 1.
+ *
+ * @param sequence string representation of the image index, starting at
1.
+ * @return image at the given index.
+ * @throws DataStoreException if the requested image can not be obtained.
+ */
+ @Override
+ public Resource findResource(final String sequence) throws
DataStoreException {
+ Exception cause;
+ int index;
+ try {
+ index = Integer.parseInt(sequence);
+ cause = null;
+ } catch (NumberFormatException e) {
+ index = 0;
+ cause = e;
+ }
+ if (index > 0) try {
+ ImageFileDirectory image = reader().getImageFileDirectory(index -
1);
+ if (image != null) return image;
+ } catch (IOException e) {
+ throw errorIO(e);
+ }
+ throw new IllegalNameException(StoreUtilities.resourceNotFound(this,
sequence), cause);
+ }
+
+ /**
* Ignored in current implementation, since this resource produces no
events.
*
* @param <T> {@inheritDoc}
diff --git
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index 2e991c3..16e57b2 100644
---
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -17,29 +17,29 @@
package org.apache.sis.storage.geotiff;
import java.io.IOException;
-import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.LogRecord;
+import java.nio.charset.Charset;
import javax.measure.Unit;
import javax.measure.quantity.Length;
-import org.apache.sis.coverage.grid.GridExtent;
-import org.apache.sis.coverage.grid.GridGeometry;
+import org.opengis.metadata.Metadata;
+import org.opengis.metadata.citation.DateType;
+import org.opengis.util.FactoryException;
+import org.opengis.util.GenericName;
import org.apache.sis.internal.geotiff.Resources;
import org.apache.sis.internal.storage.AbstractResource;
import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.internal.storage.io.ChannelDataInput;
-import org.apache.sis.math.Vector;
-import org.apache.sis.measure.Units;
-import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.GridCoverageResource;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.citation.DateType;
-import org.opengis.util.FactoryException;
-import org.opengis.util.GenericName;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.math.Vector;
+import org.apache.sis.measure.Units;
/**
@@ -78,6 +78,14 @@ final class ImageFileDirectory extends AbstractResource
implements GridCoverageR
private final Reader reader;
/**
+ * The identifier as a sequence number in the namespace of the {@link
GeoTiffStore}.
+ * The first image has the sequence number "1".
+ *
+ * @see #getIdentifier()
+ */
+ private final GenericName identifier;
+
+ /**
* {@code true} if this {@code ImageFileDirectory} has not yet read all
deferred entries.
* When this flag is {@code true}, the {@code ImageFileDirectory} is not
yet ready for use.
*/
@@ -339,10 +347,12 @@ final class ImageFileDirectory extends AbstractResource
implements GridCoverageR
* Creates a new image file directory.
*
* @param reader information about the input stream to read, the metadata
and the character encoding.
+ * @param index the image index as a sequence number starting with 0 for
the first image.
*/
- ImageFileDirectory(final Reader reader) {
+ ImageFileDirectory(final Reader reader, final int index) {
super(reader.owner);
this.reader = reader;
+ identifier =
reader.nameFactory.createLocalName(reader.owner.identifier,
String.valueOf(index + 1));
}
/**
@@ -367,13 +377,14 @@ final class ImageFileDirectory extends AbstractResource
implements GridCoverageR
}
/**
- * Datastore root resource has no identifier.
+ * Returns the identifier as a sequence number in the namespace of the
{@link GeoTiffStore}.
+ * The first image has the sequence number "1".
*
- * @return null
+ * @see #getMetadata()
*/
@Override
public GenericName getIdentifier() {
- return null;
+ return identifier;
}
/**
diff --git
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
index 1385a75..8302217 100644
---
a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
+++
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
@@ -25,11 +25,13 @@ import java.util.Iterator;
import java.io.IOException;
import java.nio.ByteOrder;
import java.text.ParseException;
+import org.opengis.util.NameFactory;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.internal.storage.io.ChannelDataInput;
import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.internal.geotiff.Resources;
+import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.util.resources.Errors;
@@ -48,7 +50,7 @@ import org.apache.sis.util.resources.Errors;
* @author Alexis Manin (Geomatys)
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.8
* @module
*/
@@ -124,6 +126,11 @@ final class Reader extends GeoTIFF {
final MetadataBuilder metadata;
/**
+ * The factory to use for creating image identifiers.
+ */
+ final NameFactory nameFactory;
+
+ /**
* Creates a new GeoTIFF reader which will read data from the given input.
* The input must be at the beginning of the GeoTIFF file.
*
@@ -132,10 +139,11 @@ final class Reader extends GeoTIFF {
*/
Reader(final GeoTiffStore owner, final ChannelDataInput input) throws
IOException, DataStoreException {
super(owner);
- this.input = input;
- this.origin = input.getStreamPosition();
- this.metadata = new MetadataBuilder();
- this.doneIFD = new HashSet<>();
+ this.input = input;
+ this.origin = input.getStreamPosition();
+ this.metadata = new MetadataBuilder();
+ this.doneIFD = new HashSet<>();
+ this.nameFactory = DefaultFactories.forBuildin(NameFactory.class);
/*
* A TIFF file begins with either "II" (0x4949) or "MM" (0x4D4D)
characters.
* Those characters identify the byte order. Note that we do not need
to care
@@ -252,7 +260,7 @@ final class Reader extends GeoTIFF {
* to get the pointer to the next IFD.
*/
final int offsetSize = Integer.BYTES << intSizeExpansion;
- final ImageFileDirectory dir = new ImageFileDirectory(this);
+ final ImageFileDirectory dir = new ImageFileDirectory(this, index);
for (long remaining = readUnsignedShort(); --remaining >= 0;) {
/*
* Each entry in the Image File Directory has the following
format:
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
index 45dd2ae..7256bc3 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
@@ -21,10 +21,13 @@ import java.util.Objects;
import java.util.Collection;
import java.io.Closeable;
import java.io.IOException;
+import org.opengis.util.NameSpace;
+import org.opengis.util.NameFactory;
import org.apache.sis.setup.GeometryLibrary;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.util.logging.WarningListeners;
+import org.apache.sis.internal.system.DefaultFactories;
/**
@@ -40,6 +43,18 @@ import org.apache.sis.util.logging.WarningListeners;
*/
public abstract class Decoder implements Closeable {
/**
+ * The data store identifier created from the global attributes, or {@code
null} if none.
+ * Defined as a namespace for use as the scope of children resources (the
variables).
+ * This is set by netCDF store constructor and shall not be modified
afterward.
+ */
+ public NameSpace namespace;
+
+ /**
+ * The factory to use for creating variable identifiers.
+ */
+ public final NameFactory nameFactory;
+
+ /**
* The library for geometric objects, or {@code null} for the default.
* This will be used only if there is geometric objects to create.
* If the netCDF file contains only raster data, this value is ignored.
@@ -65,15 +80,16 @@ public abstract class Decoder implements Closeable {
*/
protected Decoder(final GeometryLibrary geomlib, final
WarningListeners<DataStore> listeners) {
Objects.requireNonNull(listeners);
- this.geomlib = geomlib;
- this.listeners = listeners;
+ this.geomlib = geomlib;
+ this.listeners = listeners;
+ this.nameFactory = DefaultFactories.forBuildin(NameFactory.class);
}
/**
* Returns a filename for formatting error message and for information
purpose.
- * The filename should not contain path.
+ * The filename should not contain path, but may contain file extension.
*
- * @return a filename to report in warning or error messages.
+ * @return a filename to include in warnings or error messages.
*/
public abstract String getFilename();
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
index b393bd3..e63d5fa 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
@@ -578,9 +578,9 @@ public final class ChannelDecoder extends Decoder {
/**
* Returns a filename for formatting error message and for information
purpose.
- * The filename does not contain path.
+ * The filename does not contain path, but may contain file extension.
*
- * @return a filename to report in warning or error messages.
+ * @return a filename to include in warnings or error messages.
*/
@Override
public final String getFilename() {
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java
index 232f3c0..d3b9fa2 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java
@@ -16,36 +16,35 @@
*/
package org.apache.sis.internal.netcdf.impl;
-import java.io.IOException;
+import java.util.Map;
+import java.util.List;
+import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
import java.util.Spliterator;
-import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
-import org.apache.sis.feature.DefaultAttributeType;
-import org.apache.sis.feature.DefaultFeatureType;
-import org.apache.sis.internal.feature.MovingFeature;
+import java.util.function.Consumer;
+import java.io.IOException;
+import org.opengis.util.GenericName;
+import org.apache.sis.math.Vector;
import org.apache.sis.internal.netcdf.DataType;
import org.apache.sis.internal.netcdf.DiscreteSampling;
import org.apache.sis.internal.netcdf.Resources;
-import org.apache.sis.math.Vector;
-import org.apache.sis.setup.GeometryLibrary;
-import org.apache.sis.storage.DataStore;
+import org.apache.sis.internal.feature.MovingFeature;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.feature.DefaultFeatureType;
+import org.apache.sis.feature.DefaultAttributeType;
import org.apache.sis.util.collection.BackingStoreException;
-import org.apache.sis.util.logging.WarningListeners;
-import org.opengis.feature.AttributeType;
+import ucar.nc2.constants.CF;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.feature.PropertyType;
-import org.opengis.util.GenericName;
-import ucar.nc2.constants.CF;
+import org.opengis.feature.AttributeType;
/**
@@ -53,7 +52,7 @@ import ucar.nc2.constants.CF;
* netCDF files encoded as specified in the OGC 16-114 (OGC Moving Features
Encoding Extension: netCDF) specification.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.8
* @module
*/
@@ -75,7 +74,7 @@ final class FeaturesInfo extends DiscreteSampling {
private final VariableInfo time;
/**
- * The variable that contains <var>x</var> and <var>y</var> ordinate
values (typically longitudes and latitudes).
+ * The variable that contains <var>x</var> and <var>y</var> coordinate
values (typically longitudes and latitudes).
* All variables in this array shall have the same length, and that length
shall be the same than {@link #time}.
*/
private final VariableInfo[] coordinates;
@@ -93,18 +92,20 @@ final class FeaturesInfo extends DiscreteSampling {
/**
* Creates a new discrete sampling parser for features identified by the
given variable.
*
+ * @param decoder the source of the features to create.
* @param counts the count of instances per feature.
* @param identifiers the feature identifiers.
- * @param library the library for geometric objects, or {@code null}
for the default.
- * @param listeners the set of registered warning listeners for the
data store.
+ * @param time the variable that contains time.
+ * @param coordinates the variable that contains <var>x</var> and
<var>y</var> coordinate values.
+ * @param properties the variables that contain custom properties.
* @throws IllegalArgumentException if the given library is non-null but
not available.
*/
@SuppressWarnings("rawtypes") // Because of
generic array creation.
- private FeaturesInfo(final Vector counts, final VariableInfo identifiers,
final VariableInfo time,
- final Collection<VariableInfo> coordinates, final
Collection<VariableInfo> properties,
- final GeometryLibrary library, final WarningListeners<DataStore>
listeners)
+ private FeaturesInfo(final ChannelDecoder decoder,
+ final Vector counts, final VariableInfo identifiers, final
VariableInfo time,
+ final Collection<VariableInfo> coordinates, final
Collection<VariableInfo> properties)
{
- super(library, listeners);
+ super(decoder.geomlib, decoder.listeners);
this.counts = counts;
this.identifiers = identifiers;
this.coordinates = coordinates.toArray(new
VariableInfo[coordinates.size()]);
@@ -146,13 +147,13 @@ final class FeaturesInfo extends DiscreteSampling {
// TODO: add description.
pt[i] = new DefaultAttributeType<>(info, valueClass, minOccurs,
maxOccurs, null, characteristics);
}
- info.put(DefaultAttributeType.NAME_KEY, "Feature"); // TODO: find
a better name.
+ String name = "Features"; // TODO: find a better name.
+ info.put(DefaultAttributeType.NAME_KEY,
decoder.nameFactory.createLocalName(decoder.namespace, name));
type = new DefaultFeatureType(info, false, null, pt);
}
/**
- *
- * @return type name.
+ * Returns an identifier for the collection of features in the netCDF file.
*/
@Override
public GenericName getIdentifier() {
@@ -283,8 +284,7 @@ search: for (final VariableInfo counts : decoder.variables)
{
}
final VariableInfo time = coordinates.remove("T");
if (time != null) {
- features.add(new FeaturesInfo(counts.read(),
identifiers, time, coordinates.values(),
- properties, decoder.geomlib,
decoder.listeners));
+ features.add(new FeaturesInfo(decoder, counts.read(),
identifiers, time, coordinates.values(), properties));
}
}
}
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
index 62486b5..1f4c7e0 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
@@ -128,9 +128,9 @@ public final class DecoderWrapper extends Decoder
implements CancelTask {
/**
* Returns a filename for formatting error message and for information
purpose.
- * The filename should not contain path.
+ * The filename should not contain path, but may contain file extension.
*
- * @return a filename to report in warning or error messages.
+ * @return a filename to include in warnings or error messages.
*/
@Override
public String getFilename() {
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java
index a8db9f2..226c977 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java
@@ -17,21 +17,23 @@
package org.apache.sis.internal.netcdf.ucar;
import java.util.stream.Stream;
-import org.apache.sis.internal.netcdf.DiscreteSampling;
-import org.apache.sis.setup.GeometryLibrary;
+import org.opengis.util.GenericName;
import org.apache.sis.storage.DataStore;
+import org.apache.sis.setup.GeometryLibrary;
+import org.apache.sis.internal.netcdf.DiscreteSampling;
import org.apache.sis.util.logging.WarningListeners;
+import ucar.nc2.ft.FeatureCollection;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
-import org.opengis.util.GenericName;
-import ucar.nc2.ft.FeatureCollection;
/**
* A wrapper around the UCAR {@code ucar.nc2.ft} package.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.8
* @module
*/
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
index 0493dcc..8ddd1e1 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -63,7 +63,6 @@ import org.apache.sis.internal.netcdf.GridGeometry;
import org.apache.sis.internal.storage.io.IOUtilities;
import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.internal.storage.wkt.StoreFormat;
-import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.internal.util.CollectionsExt;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.CharSequences;
@@ -169,11 +168,6 @@ final class MetadataReader extends MetadataBuilder {
private final String[] searchPath;
/**
- * The name factory, created when first needed.
- */
- private transient NameFactory nameFactory;
-
- /**
* The contact, used at metadata creation time for avoiding to construct
identical objects
* more than once.
*
@@ -932,12 +926,8 @@ split: while ((start =
CharSequences.skipLeadingWhitespaces(value, start, lengt
newSampleDimension();
final String name = trim(variable.getName());
if (name != null) {
- if (nameFactory == null) {
- nameFactory = DefaultFactories.forBuildin(NameFactory.class);
- // Real dependency injection to be used in a future version.
- }
- setBandIdentifier(nameFactory.createMemberName(null, name,
- nameFactory.createTypeName(null,
variable.getDataTypeName())));
+ final NameFactory f = decoder.nameFactory;
+ setBandIdentifier(f.createMemberName(null, name,
f.createTypeName(null, variable.getDataTypeName())));
}
Object[] v = variable.getAttributeValues(CF.STANDARD_NAME, false);
final String id = (v.length == 1) ? trim((String) v[0]) : null;
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
index 35bf5f7..3629377 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
@@ -18,26 +18,29 @@ package org.apache.sis.storage.netcdf;
import java.io.IOException;
import java.net.URI;
-import java.util.Collection;
import java.util.List;
+import java.util.Collection;
+import org.opengis.util.NameSpace;
+import org.opengis.util.NameFactory;
+import org.opengis.util.GenericName;
+import org.opengis.metadata.Metadata;
+import org.opengis.parameter.ParameterValueGroup;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.UnsupportedStorageException;
+import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.Aggregate;
import org.apache.sis.internal.netcdf.Decoder;
import org.apache.sis.internal.storage.URIDataStore;
import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.metadata.ModifiableMetadata;
import org.apache.sis.setup.OptionKey;
-import org.apache.sis.storage.Aggregate;
-import org.apache.sis.storage.DataStore;
-import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.Resource;
-import org.apache.sis.storage.StorageConnector;
-import org.apache.sis.storage.UnsupportedStorageException;
import org.apache.sis.storage.event.ChangeEvent;
import org.apache.sis.storage.event.ChangeListener;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.Version;
-import org.opengis.metadata.Metadata;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.util.GenericName;
+import ucar.nc2.constants.ACDD;
import ucar.nc2.constants.CDM;
@@ -62,6 +65,9 @@ public class NetcdfStore extends DataStore implements
Aggregate {
/**
* The {@link NetcdfStoreProvider#LOCATION} parameter value, or {@code
null} if none.
+ * This is used for information purpose only, not for actual reading
operations.
+ *
+ * @see #getOpenParameters()
*/
private final URI location;
@@ -100,6 +106,14 @@ public class NetcdfStore extends DataStore implements
Aggregate {
throw new UnsupportedStorageException(super.getLocale(),
NetcdfStoreProvider.NAME,
connector.getStorage(),
connector.getOption(OptionKey.OPEN_OPTIONS));
}
+ String id = decoder.stringValue(ACDD.id);
+ if (id == null || (id = id.trim()).isEmpty()) {
+ id = decoder.getFilename();
+ }
+ if (id != null) {
+ final NameFactory f = decoder.nameFactory;
+ decoder.namespace = f.createNameSpace(f.createLocalName(null, id),
null);
+ }
}
/**
@@ -119,16 +133,6 @@ public class NetcdfStore extends DataStore implements
Aggregate {
}
/**
- * SQL Datastore root resource has no identifier.
- *
- * @return null
- */
- @Override
- public GenericName getIdentifier() {
- return null;
- }
-
- /**
* Returns the version number of the Climate and Forecast (CF) conventions
used in the netCDF file.
* The use of CF convention is mandated by the OGC 11-165r2 standard
* (<cite>CF-netCDF3 Data Model Extension standard</cite>).
@@ -148,6 +152,20 @@ public class NetcdfStore extends DataStore implements
Aggregate {
}
/**
+ * Returns an identifier constructed from global attributes or the
filename of the netCDF file.
+ *
+ * @return the identifier fetched from global attributes or the filename,
or {@code null} if none.
+ * @throws DataStoreException if an error occurred while fetching the
identifier.
+ *
+ * @since 1.0
+ */
+ @Override
+ public GenericName getIdentifier() throws DataStoreException {
+ final NameSpace namespace = decoder.namespace;
+ return (namespace != null) ? namespace.name() : null;
+ }
+
+ /**
* Returns information about the dataset as a whole. The returned metadata
object can contain information
* such as the spatiotemporal extent of the dataset, contact information
about the creator or distributor,
* data quality, usage constraints and more.
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 7996149..67f5ec3 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
@@ -152,8 +152,8 @@ public final class Database {
tablesByNames.add(store, table.featureType.getName(), table);
hasGeometry |= table.hasGeometry;
}
- this.tables = tableList.toArray(new Table[tableList.size()]);
- this.functions = analyzer.functions;
+ this.tables = tableList.toArray(new Table[tableList.size()]);
+ this.functions = analyzer.functions;
this.hasGeometry = hasGeometry;
}
@@ -175,7 +175,7 @@ public final class Database {
/**
* Stores information about tables in the given metadata.
- * Only tables explicitely requested by the user are listed.
+ * Only tables explicitly requested by the user are listed.
*
* @param metadata information about the database.
* @param builder where to add information about the tables.
diff --git
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java
index fd0be5f..e41af4e 100644
---
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java
+++
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java
@@ -16,45 +16,46 @@
*/
package org.apache.sis.internal.sql.feature;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import java.sql.DatabaseMetaData;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
import javax.sql.DataSource;
-import org.apache.sis.feature.builder.AssociationRoleBuilder;
+import org.opengis.util.GenericName;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.feature.builder.AttributeRole;
import org.apache.sis.feature.builder.AttributeTypeBuilder;
+import org.apache.sis.feature.builder.AssociationRoleBuilder;
import org.apache.sis.feature.builder.FeatureTypeBuilder;
import org.apache.sis.internal.feature.Geometries;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.storage.InternalDataStoreException;
import org.apache.sis.internal.metadata.sql.Reflection;
import org.apache.sis.internal.metadata.sql.SQLUtilities;
import org.apache.sis.internal.storage.AbstractFeatureSet;
import org.apache.sis.internal.util.CollectionsExt;
-import org.apache.sis.storage.DataStoreContentException;
-import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.InternalDataStoreException;
+import org.apache.sis.util.collection.WeakValueHashMap;
+import org.apache.sis.util.collection.TreeTable;
import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.Classes;
-import org.apache.sis.util.Debug;
import org.apache.sis.util.Exceptions;
+import org.apache.sis.util.Classes;
import org.apache.sis.util.Numbers;
-import org.apache.sis.util.collection.TreeTable;
-import org.apache.sis.util.collection.WeakValueHashMap;
-import org.apache.sis.util.iso.Names;
-import org.opengis.feature.AttributeType;
+import org.apache.sis.util.Debug;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureAssociationRole;
import org.opengis.feature.FeatureType;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.util.GenericName;
+import org.opengis.feature.AttributeType;
+import org.opengis.feature.FeatureAssociationRole;
/**
@@ -416,21 +417,6 @@ final class Table extends AbstractFeatureSet {
}
/**
- *
- * @return table identifier composed of catalog, schema and table name.
- */
- @Override
- public GenericName getIdentifier() {
- if (name.catalog != null && name.schema != null) {
- return Names.createGenericName(null, null, name.catalog,
name.schema, name.table);
- } else if (name.schema != null) {
- return Names.createGenericName(null, null, name.schema,
name.table);
- } else {
- return Names.createLocalName(null, null, name.table);
- }
- }
-
- /**
* Returns the given relations as an array, or {@code null} if none.
*/
private static Relation[] toArray(final Collection<Relation> relations) {
@@ -530,6 +516,14 @@ final class Table extends AbstractFeatureSet {
/**
+ * Returns the table identifier composed of catalog, schema and table name.
+ */
+ @Override
+ public final GenericName getIdentifier() {
+ return featureType.getName().toFullyQualifiedName();
+ }
+
+ /**
* Returns the feature type inferred from the database structure analysis.
*/
@Override
diff --git
a/storage/sis-sqlstore/src/main/java/org/apache/sis/storage/sql/SQLStore.java
b/storage/sis-sqlstore/src/main/java/org/apache/sis/storage/sql/SQLStore.java
index 72d5073..0de338b 100644
---
a/storage/sis-sqlstore/src/main/java/org/apache/sis/storage/sql/SQLStore.java
+++
b/storage/sis-sqlstore/src/main/java/org/apache/sis/storage/sql/SQLStore.java
@@ -16,27 +16,28 @@
*/
package org.apache.sis.storage.sql;
-import java.sql.Connection;
-import java.sql.SQLException;
import java.util.Collection;
import javax.sql.DataSource;
-import org.apache.sis.internal.sql.feature.Database;
-import org.apache.sis.internal.sql.feature.Resources;
-import org.apache.sis.internal.storage.MetadataBuilder;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.lang.reflect.Method;
+import org.opengis.util.GenericName;
+import org.opengis.metadata.Metadata;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.metadata.spatial.SpatialRepresentationType;
+import org.apache.sis.storage.Resource;
import org.apache.sis.storage.Aggregate;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.IllegalNameException;
-import org.apache.sis.storage.Resource;
import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.event.ChangeEvent;
import org.apache.sis.storage.event.ChangeListener;
+import org.apache.sis.internal.sql.feature.Database;
+import org.apache.sis.internal.sql.feature.Resources;
+import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.Exceptions;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.spatial.SpatialRepresentationType;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.util.GenericName;
/**
@@ -53,6 +54,17 @@ import org.opengis.util.GenericName;
*/
public class SQLStore extends DataStore implements Aggregate {
/**
+ * Names of possible public getter methods for data source title, in
preference order.
+ */
+ private static final String[] NAME_GETTERS = {
+ "getDescription", // PostgreSQL, SQL Server
+ "getDataSourceName", // Derby
+ "getDatabaseName", // Derby, PostgreSQL, SQL Server
+ "getUrl", // PostgreSQL
+ "getURL" // SQL Server
+ };
+
+ /**
* The data source to use for obtaining connections to the database.
*/
private final DataSource source;
@@ -132,12 +144,12 @@ public class SQLStore extends DataStore implements
Aggregate {
}
/**
- * SQL Datastore root resource has no identifier.
+ * SQL data store root resource has no identifier.
*
- * @return null
+ * @return {@code null}.
*/
@Override
- public GenericName getIdentifier() {
+ public GenericName getIdentifier() throws DataStoreException {
return null;
}
@@ -158,10 +170,11 @@ public class SQLStore extends DataStore implements
Aggregate {
/**
* Returns the database model, analyzing the database schema when first
needed.
* This method performs the same work than {@link #model()}, but using an
existing connection.
+ * Callers must own a synchronization lock on {@code this}.
*
* @param c connection to the database.
*/
- private synchronized Database model(final Connection c) throws
DataStoreException, SQLException {
+ private Database model(final Connection c) throws DataStoreException,
SQLException {
if (model == null) {
model = new Database(this, c, source, tableNames, listeners);
}
@@ -189,6 +202,25 @@ public class SQLStore extends DataStore implements
Aggregate {
} catch (SQLException e) {
throw new DataStoreException(Exceptions.unwrap(e));
}
+ /*
+ * Try to find a title from the data source description.
+ */
+ for (final String c : NAME_GETTERS) {
+ try {
+ final Method method = source.getClass().getMethod(c);
+ if (method.getReturnType() == String.class) {
+ String name = (String) method.invoke(source);
+ if (name != null && !(name = name.trim()).isEmpty()) {
+ builder.addTitle(name);
+ break;
+ }
+ }
+ } catch (NoSuchMethodException | SecurityException e) {
+ // Ignore - try the next method.
+ } catch (ReflectiveOperationException e) {
+ throw new DataStoreException(Exceptions.unwrap(e));
+ }
+ }
metadata = builder.build(true);
}
return metadata;
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java
index 9b74787..511d86a 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java
@@ -17,12 +17,16 @@
package org.apache.sis.internal.storage;
import java.util.Locale;
+import org.opengis.util.GenericName;
import org.opengis.geometry.Envelope;
import org.opengis.metadata.Metadata;
+import org.opengis.metadata.Identifier;
+import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.extent.Extent;
import org.opengis.metadata.extent.GeographicBoundingBox;
import org.opengis.metadata.extent.GeographicExtent;
import org.opengis.metadata.identification.Identification;
+import org.apache.sis.referencing.NamedIdentifier;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.util.Localized;
import org.apache.sis.util.logging.WarningListeners;
@@ -35,6 +39,9 @@ import org.apache.sis.storage.event.ChangeListener;
/**
* Base implementation of resources contained in data stores.
+ * This class provides default implementation of {@link #getIdentifier()} and
{@link #getEnvelope()}
+ * methods which extract their information from the value returned by {@link
#getMetadata()}.
+ * Subclasses should override those methods if they can provide those
information more efficiently.
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.0
@@ -90,6 +97,58 @@ public abstract class AbstractResource implements Resource,
Localized {
}
/**
+ * Returns an identifier for this resource. The default implementation
returns the first identifier
+ * of {@code Metadata/identificationInfo/citation}, provided that
exactly one such citation is found.
+ * If more than one citation is found, then this method returns {@code
null} since the identification
+ * is considered ambiguous. This is the same default implementation than
{@link DataStore#getIdentifier()}.
+ *
+ * @return the resource identifier inferred from metadata, or {@code null}
if none or ambiguous.
+ * @throws DataStoreException if an error occurred while fetching the
identifier.
+ *
+ * @see DataStore#getIdentifier()
+ */
+ @Override
+ public GenericName getIdentifier() throws DataStoreException {
+ return identifier(getMetadata());
+ }
+
+ /**
+ * Implementation of {@link #getIdentifier()}, provided as a separated
method for implementations
+ * that do not extend {@code AbstractResource}.
+ *
+ * @param metadata the metadata from which to infer the identifier, or
{@code null}.
+ * @return the resource identifier inferred from metadata, or {@code null}
if none or ambiguous.
+ *
+ * @see StoreUtilities#getAnyIdentifier(Metadata, boolean)
+ */
+ public static GenericName identifier(final Metadata metadata) {
+ if (metadata != null) {
+ Citation citation = null;
+ for (final Identification id : metadata.getIdentificationInfo()) {
+ final Citation c = id.getCitation();
+ if (c != null) {
+ if (citation != null && citation != c) return null;
// Ambiguity.
+ citation = c;
+ }
+ }
+ if (citation != null) {
+ Identifier first = null;
+ for (final Identifier c : citation.getIdentifiers()) {
+ if (c instanceof GenericName) {
+ return (GenericName) c;
+ } else if (first == null) {
+ first = c;
+ }
+ }
+ if (first != null) {
+ return new NamedIdentifier(first);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the spatio-temporal envelope of this resource.
* The default implementation computes the union of all {@link
GeographicBoundingBox} in the resource metadata,
* assuming the {@linkplain
org.apache.sis.referencing.CommonCRS#defaultGeographic() default geographic CRS}
@@ -97,6 +156,8 @@ public abstract class AbstractResource implements Resource,
Localized {
*
* @return the spatio-temporal resource extent, or {@code null} if none.
* @throws DataStoreException if an error occurred while reading or
computing the envelope.
+ *
+ * @see org.apache.sis.storage.DataSet#getEnvelope()
*/
public Envelope getEnvelope() throws DataStoreException {
return envelope(getMetadata());
@@ -113,18 +174,14 @@ public abstract class AbstractResource implements
Resource, Localized {
GeneralEnvelope bounds = null;
if (metadata != null) {
for (final Identification identification :
metadata.getIdentificationInfo()) {
- if (identification != null) {
// Paranoiac check.
- for (final Extent extent : identification.getExtents()) {
- if (extent != null) {
// Paranoiac check.
- for (final GeographicExtent ge :
extent.getGeographicElements()) {
- if (ge instanceof GeographicBoundingBox) {
- final GeneralEnvelope env = new
GeneralEnvelope((GeographicBoundingBox) ge);
- if (bounds == null) {
- bounds = env;
- } else {
- bounds.add(env);
- }
- }
+ for (final Extent extent : identification.getExtents()) {
+ for (final GeographicExtent ge :
extent.getGeographicElements()) {
+ if (ge instanceof GeographicBoundingBox) {
+ final GeneralEnvelope env = new
GeneralEnvelope((GeographicBoundingBox) ge);
+ if (bounds == null) {
+ bounds = env;
+ } else {
+ bounds.add(env);
}
}
}
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/JoinFeatureSet.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/JoinFeatureSet.java
index e7e9434..f7e6e7f 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/JoinFeatureSet.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/JoinFeatureSet.java
@@ -16,16 +16,17 @@
*/
package org.apache.sis.internal.storage;
-import java.util.Collections;
import java.util.Map;
+import java.util.Collections;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
-import org.apache.sis.feature.DefaultAssociationRole;
-import org.apache.sis.feature.DefaultFeatureType;
+import org.opengis.util.GenericName;
+import org.opengis.geometry.Envelope;
import org.apache.sis.feature.FeatureOperations;
-import org.apache.sis.filter.DefaultFilterFactory;
+import org.apache.sis.feature.DefaultFeatureType;
+import org.apache.sis.feature.DefaultAssociationRole;
import org.apache.sis.internal.feature.AttributeConvention;
import org.apache.sis.internal.storage.query.SimpleQuery;
import org.apache.sis.storage.DataStore;
@@ -35,6 +36,8 @@ import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.collection.BackingStoreException;
import org.apache.sis.util.collection.Containers;
import org.apache.sis.util.logging.WarningListeners;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.feature.Operation;
@@ -43,8 +46,7 @@ import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.PropertyIsEqualTo;
import org.opengis.filter.expression.Expression;
-import org.opengis.geometry.Envelope;
-import org.opengis.util.GenericName;
+import org.apache.sis.filter.DefaultFilterFactory;
/**
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
index e62217a..6757d43 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
@@ -18,13 +18,15 @@ package org.apache.sis.internal.storage;
import java.util.Collection;
import java.util.stream.Stream;
+import org.opengis.util.GenericName;
+import org.opengis.metadata.Metadata;
import org.apache.sis.storage.DataStore;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.WarningListeners;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
-import org.opengis.metadata.Metadata;
-import org.opengis.util.GenericName;
/**
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java
index b52d702..2b08ef4 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/StoreUtilities.java
@@ -20,6 +20,7 @@ import java.util.EnumSet;
import java.util.stream.Stream;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
+import org.opengis.util.GenericName;
import org.opengis.metadata.Metadata;
import org.opengis.metadata.identification.Identification;
import org.opengis.metadata.identification.DataIdentification;
@@ -85,22 +86,16 @@ public final class StoreUtilities extends Static {
* Returns an identifier for a resource having the given metadata, or
{@code null} if none.
* This method checks the information returned by {@link
Metadata#getIdentificationInfo()},
* with precedence to {@link DataIdentification} over other kinds of
{@link Identification}.
- *
- * @param metadata the metadata from which to get a data identifier, or
{@code null}.
- * @return a data identifier, or {@code null} if none.
- */
- public static String getIdentifier(final Metadata metadata) {
- return Citations.removeIgnorableCharacters(getIdentifier(metadata,
true));
- }
-
- /**
- * Implementation of {@link #getIdentifier(Metadata)} to be shared with
{@link #getLabel(Resource)}.
+ * This method does not check for ambiguity (if there is more than one
identification info).
*
* @param metadata the metadata from which to get a data identifier, or
{@code null}.
* @param unicode whether to restrict to valid Unicode identifiers.
* @return a data identifier, or {@code null} if none.
+ *
+ * @see AbstractResource#identifier(Metadata)
+ * @see Citations#removeIgnorableCharacters(String)
*/
- private static String getIdentifier(final Metadata metadata, final boolean
unicode) {
+ private static String getAnyIdentifier(final Metadata metadata, final
boolean unicode) {
String fallback = null;
if (metadata != null) {
for (final Identification md : metadata.getIdentificationInfo()) {
@@ -118,9 +113,9 @@ public final class StoreUtilities extends Static {
}
/**
- * Returns a short label for the given resource. This method returns an
identifier if possible,
- * or the title otherwise. If neither an identifier or title can be found,
then this method returns
- * the kind of resource implemented by the given object.
+ * Returns a short label for the given resource. This method returns the
display name if possible,
+ * or the identifier otherwise. If neither a display name, identifier or
title can be found, then
+ * this method returns the kind of resource implemented by the given
object.
*
* @param resource the resource for which to get a label.
* @return a human-readable label for the given resource (not to be used
as an identifier).
@@ -132,9 +127,14 @@ public final class StoreUtilities extends Static {
title = ((DataStore) resource).getDisplayName();
}
if (title == null) {
- title = getIdentifier(resource.getMetadata(), false);
- if (title == null) {
- title =
Classes.getShortName(getInterface(resource.getClass()));
+ final GenericName identifier = resource.getIdentifier();
+ if (identifier != null) {
+ title = identifier.toString();
+ } else {
+ title = getAnyIdentifier(resource.getMetadata(), false);
+ if (title == null) {
+ title =
Classes.getShortName(getInterface(resource.getClass()));
+ }
}
}
return title;
@@ -296,4 +296,16 @@ public final class StoreUtilities extends Static {
target.add(stream.iterator());
}
}
+
+ /**
+ * Returns an error message for a resource not found. This is used for
exception to be thrown
+ * as {@link org.apache.sis.storage.IllegalNameException}.
+ *
+ * @param store the store for which a resource has not been found.
+ * @param identifier the requested identifier.
+ * @return error message for the exception to be thrown.
+ */
+ public static String resourceNotFound(final DataStore store, final String
identifier) {
+ return
Resources.forLocale(store.getLocale()).getString(Resources.Keys.ResourceNotFound_2,
store.getDisplayName(), identifier);
+ }
}
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
index 1f940b0..7604a22 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
@@ -16,68 +16,70 @@
*/
package org.apache.sis.internal.storage.csv;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.LineNumberReader;
-import java.io.Reader;
-import java.net.URI;
-import java.nio.charset.Charset;
-import java.time.DateTimeException;
-import java.time.Instant;
+import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
-import java.util.List;
import java.util.Locale;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.time.Instant;
+import java.time.DateTimeException;
+import java.io.Reader;
+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;
+import org.opengis.util.FactoryException;
+import org.opengis.geometry.Envelope;
+import org.opengis.metadata.Metadata;
+import org.opengis.metadata.maintenance.ScopeCode;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.TemporalCRS;
+import org.opengis.referencing.operation.TransformException;
import org.apache.sis.feature.DefaultAttributeType;
import org.apache.sis.feature.DefaultFeatureType;
import org.apache.sis.feature.FoliationRepresentation;
-import org.apache.sis.geometry.GeneralEnvelope;
-import org.apache.sis.geometry.ImmutableEnvelope;
-import org.apache.sis.internal.feature.Geometries;
-import org.apache.sis.internal.feature.MovingFeature;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.internal.storage.MetadataBuilder;
-import org.apache.sis.internal.storage.Resources;
-import org.apache.sis.internal.storage.URIDataStore;
import org.apache.sis.internal.storage.io.IOUtilities;
import org.apache.sis.internal.storage.io.RewindableLineReader;
-import org.apache.sis.internal.util.UnmodifiableArrayList;
-import org.apache.sis.io.InvalidSeekException;
-import org.apache.sis.measure.Units;
+import org.apache.sis.internal.feature.Geometries;
+import org.apache.sis.internal.feature.MovingFeature;
+import org.apache.sis.internal.storage.Resources;
+import org.apache.sis.internal.storage.URIDataStore;
+import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.geometry.ImmutableEnvelope;
import org.apache.sis.metadata.iso.DefaultMetadata;
import org.apache.sis.metadata.sql.MetadataStoreException;
-import org.apache.sis.referencing.CRS;
-import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.setup.OptionKey;
import org.apache.sis.storage.DataOptionKey;
-import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.DataStoreReferencingException;
-import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.StorageConnector;
import org.apache.sis.storage.UnsupportedStorageException;
+import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.FeatureSet;
+import org.apache.sis.setup.OptionKey;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Errors;
-import org.opengis.feature.AttributeType;
+import org.apache.sis.io.InvalidSeekException;
+import org.apache.sis.measure.Units;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.feature.PropertyType;
-import org.opengis.geometry.Envelope;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.maintenance.ScopeCode;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.crs.TemporalCRS;
-import org.opengis.referencing.operation.TransformException;
-import org.opengis.util.FactoryException;
-import org.opengis.util.GenericName;
+import org.opengis.feature.AttributeType;
/**
@@ -310,16 +312,6 @@ final class Store extends URIDataStore implements
FeatureSet {
}
/**
- * CSV Identifier is identical to it's feature type name.
- *
- * @return CSV feature type name.
- */
- @Override
- public GenericName getIdentifier() {
- return featureType.getName();
- }
-
- /**
* Moves the reader position to beginning of file, if possible. We try to
use the mark defined by the constructor,
* which is set after the last header line. If the mark is no longer
valid, then we have to create a new line reader.
* In this later case, we have to skip the header lines (i.e. we reproduce
the constructor loop, but without parsing
@@ -627,6 +619,17 @@ final class Store extends URIDataStore implements
FeatureSet {
}
/**
+ * Returns an identifier for this CSV data store.
+ * This method returns the {@link #getType() type} name, which is itself
derived from the file name.
+ *
+ * @return identifier for this CSV data store.
+ */
+ @Override
+ public GenericName getIdentifier() throws DataStoreException {
+ return featureType.getName();
+ }
+
+ /**
* Returns the metadata associated to the CSV file, or {@code null} if
none.
*
* @return the metadata associated to the CSV file, or {@code null} if
none.
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java
index dbf864e..61e1842 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/Store.java
@@ -16,43 +16,46 @@
*/
package org.apache.sis.internal.storage.folder;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryIteratorException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
+import java.util.Map;
+import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
+import java.util.Collections;
import java.util.Locale;
-import java.util.Map;
import java.util.TimeZone;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
-import org.apache.sis.internal.storage.MetadataBuilder;
-import org.apache.sis.internal.storage.Resources;
-import org.apache.sis.internal.storage.StoreResource;
-import org.apache.sis.internal.storage.StoreUtilities;
-import org.apache.sis.internal.util.UnmodifiableArrayList;
+import java.util.concurrent.ConcurrentHashMap;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.DirectoryStream;
+import java.nio.file.DirectoryIteratorException;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import org.opengis.util.GenericName;
+import org.opengis.util.NameFactory;
+import org.opengis.util.NameSpace;
+import org.opengis.metadata.Metadata;
+import org.opengis.metadata.maintenance.ScopeCode;
+import org.opengis.parameter.ParameterValueGroup;
import org.apache.sis.setup.OptionKey;
+import org.apache.sis.storage.Resource;
import org.apache.sis.storage.Aggregate;
import org.apache.sis.storage.DataStore;
-import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.DataStoreProvider;
import org.apache.sis.storage.DataStores;
-import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.DataStoreProvider;
import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.UnsupportedStorageException;
+import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
+import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.storage.MetadataBuilder;
+import org.apache.sis.internal.storage.StoreUtilities;
+import org.apache.sis.internal.storage.StoreResource;
+import org.apache.sis.internal.storage.Resources;
import org.apache.sis.storage.event.ChangeEvent;
import org.apache.sis.storage.event.ChangeListener;
-import org.apache.sis.util.collection.BackingStoreException;
-import org.apache.sis.util.iso.Names;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.maintenance.ScopeCode;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.util.GenericName;
/**
@@ -80,15 +83,24 @@ import org.opengis.util.GenericName;
class Store extends DataStore implements StoreResource, Aggregate,
DirectoryStream.Filter<Path> {
/**
* The data store for the root directory specified by the user.
+ * May be {@code this} if this store instance is for the root directory.
*/
- private final DataStore originator;
+ private final Store originator;
/**
- * The {@link FolderStoreProvider#LOCATION} parameter value, or {@code
null} if none.
+ * The {@link FolderStoreProvider#LOCATION} parameter value.
*/
protected final Path location;
/**
+ * An identifier for this folder, or {@code null} if this folder is the
root specified by the user.
+ * Shall never be null for sub-folders found in the root folder.
+ *
+ * @see #identifier(NameFactory)
+ */
+ private GenericName identifier;
+
+ /**
* Formatting conventions of dates and numbers, or {@code null} if
unspecified.
*/
protected final Locale locale;
@@ -172,7 +184,7 @@ class Store extends DataStore implements StoreResource,
Aggregate, DirectoryStre
* @param connector information about the storage (URL, stream,
<i>etc</i>).
* @throws DataStoreException if an error occurred while opening the
stream.
*/
- private Store(final Store parent, final StorageConnector connector) throws
DataStoreException {
+ private Store(final Store parent, final StorageConnector connector, final
NameFactory nameFactory) throws DataStoreException {
super(parent, connector);
originator = parent;
location = connector.getStorageAs(Path.class);
@@ -181,13 +193,7 @@ class Store extends DataStore implements StoreResource,
Aggregate, DirectoryStre
encoding = connector.getOption(OptionKey.ENCODING);
children = parent.children;
componentProvider = parent.componentProvider;
- }
-
- @Override
- public GenericName getIdentifier() {
- final String displayName = getDisplayName();
- if (displayName != null) return Names.createLocalName(null, null,
displayName);
- return null;
+ identifier =
nameFactory.createLocalName(parent.identifier(nameFactory).scope(),
super.getDisplayName());
}
/**
@@ -222,6 +228,32 @@ class Store extends DataStore implements StoreResource,
Aggregate, DirectoryStre
}
/**
+ * Returns the name of this folder.
+ */
+ @Override
+ public GenericName getIdentifier() {
+ return identifier(null);
+ }
+
+ /**
+ * Returns the name of this folder, creating it if needed.
+ * Only the root folder may have its creation delayed.
+ *
+ * @param nameFactory the factory to use for creating the root folder,
or {@code null} for the default.
+ */
+ private synchronized GenericName identifier(NameFactory nameFactory) {
+ if (identifier == null) {
+ if (nameFactory == null) {
+ nameFactory = DefaultFactories.forBuildin(NameFactory.class);
+ }
+ GenericName name = nameFactory.createLocalName(null,
super.getDisplayName());
+ NameSpace ns = nameFactory.createNameSpace(name,
Collections.singletonMap("separator", "/"));
+ identifier = nameFactory.createLocalName(ns, ".");
+ }
+ return identifier;
+ }
+
+ /**
* Returns information about the data store as a whole.
* Those metadata contains the directory name in the resource title.
*
@@ -231,11 +263,10 @@ class Store extends DataStore implements StoreResource,
Aggregate, DirectoryStre
public synchronized Metadata getMetadata() {
if (metadata == null) {
final MetadataBuilder mb = new MetadataBuilder();
- final String name = getDisplayName();
- mb.addResourceScope(ScopeCode.COLLECTION,
Resources.formatInternational(Resources.Keys.DirectoryContent_1, name));
+ mb.addResourceScope(ScopeCode.COLLECTION,
Resources.formatInternational(Resources.Keys.DirectoryContent_1,
getDisplayName()));
mb.addLanguage(locale, MetadataBuilder.Scope.RESOURCE);
mb.addEncoding(encoding, MetadataBuilder.Scope.RESOURCE);
- mb.addTitleOrIdentifier(name, MetadataBuilder.Scope.ALL);
+ mb.addTitleOrIdentifier(identifier.toString(),
MetadataBuilder.Scope.RESOURCE);
metadata = mb.build(true);
}
return metadata;
@@ -244,13 +275,17 @@ class Store extends DataStore implements StoreResource,
Aggregate, DirectoryStre
/**
* Returns all resources found in the folder given at construction time.
* Only the resources recognized by a {@link DataStore} will be included.
- * This includes sub-folders. Resources are in no particular order.
+ * Sub-folders are represented by other folder {@code Store} instances;
+ * their resources are available by invoking {@link Aggregate#components()}
+ * on them (this method does not traverse sub-folders recursively by
itself).
+ * Resources are in no particular order.
*/
@Override
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public synchronized Collection<Resource> components() throws
DataStoreException {
if (components == null) {
final List<DataStore> resources = new ArrayList<>();
+ final NameFactory nameFactory =
DefaultFactories.forBuildin(NameFactory.class);
try (DirectoryStream<Path> stream =
Files.newDirectoryStream(location, this)) {
for (final Path candidate : stream) {
/*
@@ -281,7 +316,7 @@ class Store extends DataStore implements StoreResource,
Aggregate, DirectoryStre
} else if
(componentProvider.probeContent(connector).isSupported()) {
next = componentProvider.open(connector); //
Open a file of specified format.
} else if (Files.isDirectory(candidate)) {
- next = new Store(this, connector); //
Open a sub-directory.
+ next = new Store(this, connector,
nameFactory); // Open a sub-directory.
} else {
connector.closeAllExcept(null); //
Not the format specified at construction time.
continue;
@@ -292,7 +327,7 @@ class Store extends DataStore implements StoreResource,
Aggregate, DirectoryStre
listeners.warning(Level.FINE, null, ex);
continue;
}
- next = new Store(this, connector);
+ next = new Store(this, connector, nameFactory);
} catch (DataStoreException ex) {
try {
connector.closeAllExcept(null);
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/WritableStore.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/WritableStore.java
index 54fd103..24808e9 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/WritableStore.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/WritableStore.java
@@ -23,6 +23,7 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.io.IOException;
+import org.opengis.util.GenericName;
import org.apache.sis.setup.OptionKey;
import org.apache.sis.storage.Resource;
import org.apache.sis.storage.DataStore;
@@ -91,11 +92,14 @@ final class WritableStore extends Store implements
WritableAggregate {
/*
* Infer a filename from the resource identifier, if one can be found.
* A suffix is added to the filename if available (some formats may
have no suffix at all).
+ *
+ * TODO: find a more specific metadata property for this informtion.
*/
- String filename = StoreUtilities.getIdentifier(resource.getMetadata());
- if (filename == null) {
+ final GenericName identifier = resource.getIdentifier();
+ if (identifier == null) {
throw new
DataStoreException(message(Resources.Keys.MissingResourceIdentifier_1,
StoreUtilities.getLabel(resource)));
}
+ String filename = identifier.toString();
final String[] suffixes =
StoreUtilities.getFileSuffixes(componentProvider.getClass());
if (suffixes.length != 0) {
filename += '.' + suffixes[0];
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
index 14a2798..cc65820 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
@@ -18,17 +18,19 @@ package org.apache.sis.internal.storage.query;
import java.util.List;
import java.util.stream.Stream;
+import org.opengis.util.GenericName;
+import org.opengis.geometry.Envelope;
import org.apache.sis.internal.feature.FeatureUtilities;
import org.apache.sis.internal.storage.AbstractFeatureSet;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.FeatureSet;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.filter.Filter;
-import org.opengis.filter.expression.Expression;
import org.opengis.filter.sort.SortBy;
-import org.opengis.geometry.Envelope;
-import org.opengis.util.GenericName;
+import org.opengis.filter.expression.Expression;
/**
@@ -70,13 +72,11 @@ final class FeatureSubset extends AbstractFeatureSet {
}
/**
- * Inherit parent FeatureSet identifier.
- *
- * @return parent FeatureSet identifier.
+ * Returns {@code null} since this resource is a computation result.
*/
@Override
public GenericName getIdentifier() {
- return source.getIdentifier();
+ return null;
}
/**
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
index 91f221e..af7a0d9 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
@@ -16,27 +16,26 @@
*/
package org.apache.sis.internal.storage.wkt;
-import java.io.IOException;
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
import java.io.Reader;
-import java.text.ParseException;
+import java.io.IOException;
import java.text.ParsePosition;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import org.apache.sis.internal.storage.MetadataBuilder;
+import java.text.ParseException;
+import org.opengis.metadata.Metadata;
+import org.opengis.referencing.ReferenceSystem;
import org.apache.sis.internal.storage.Resources;
+import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.storage.UnsupportedStorageException;
+import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.internal.storage.URIDataStore;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.setup.GeometryLibrary;
import org.apache.sis.setup.OptionKey;
-import org.apache.sis.storage.DataStoreContentException;
-import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.StorageConnector;
-import org.apache.sis.storage.UnsupportedStorageException;
import org.apache.sis.util.CharSequences;
-import org.opengis.metadata.Metadata;
-import org.opengis.referencing.ReferenceSystem;
-import org.opengis.util.GenericName;
/**
@@ -96,16 +95,6 @@ final class Store extends URIDataStore {
}
/**
- * WKT files have no unique identifiers.
- *
- * @return null
- */
- @Override
- public GenericName getIdentifier() {
- return null;
- }
-
- /**
* Parses the objects, if not already done. Note that {@link #objects} may
still be empty
* if an exception has been thrown at this invocation time or in previous
invocation.
*
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
index db4851a..76b9f55 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
@@ -16,36 +16,31 @@
*/
package org.apache.sis.internal.storage.xml;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.util.Collections;
import java.util.Map;
+import java.util.Collections;
import java.util.logging.LogRecord;
+import java.io.Closeable;
+import java.io.Reader;
+import java.io.InputStream;
+import java.io.IOException;
import javax.xml.bind.JAXBException;
import javax.xml.transform.stream.StreamSource;
-import org.apache.sis.internal.referencing.DefinitionVerifier;
-import org.apache.sis.internal.storage.MetadataBuilder;
-import org.apache.sis.internal.storage.URIDataStore;
-import org.apache.sis.internal.system.Loggers;
-import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.referencing.NamedIdentifier;
-import org.apache.sis.setup.OptionKey;
-import org.apache.sis.storage.DataStoreException;
+import org.opengis.metadata.Metadata;
+import org.opengis.util.FactoryException;
+import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.xml.XML;
import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.UnsupportedStorageException;
+import org.apache.sis.metadata.iso.DefaultMetadata;
import org.apache.sis.util.logging.WarningListener;
import org.apache.sis.util.resources.Errors;
-import org.apache.sis.xml.XML;
-import org.opengis.metadata.Identifier;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.identification.Identification;
-import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.util.FactoryException;
-import org.opengis.util.GenericName;
+import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.internal.storage.URIDataStore;
+import org.apache.sis.internal.storage.MetadataBuilder;
+import org.apache.sis.internal.referencing.DefinitionVerifier;
+import org.apache.sis.setup.OptionKey;
/**
@@ -109,32 +104,6 @@ final class Store extends URIDataStore {
}
/**
- * Returns the first identifier in the metadata.
- *
- * @return first metadata identifier or null if parsing fails or if there
are
- * no identifiers.
- */
- @Override
- public GenericName getIdentifier() {
- try {
- Metadata metadata = getMetadata();
- if (metadata != null) {
- for (Identification idt : metadata.getIdentificationInfo()) {
- Citation citation = idt.getCitation();
- if (citation != null) {
- for (Identifier id : citation.getIdentifiers()) {
- return NamedIdentifier.castOrCopy(id);
- }
- }
- }
- }
- } catch (DataStoreException ex) {
- return null;
- }
- return null;
- }
-
- /**
* Returns the input stream or reader set in the given source, or {@code
null} if none.
*/
private static Closeable input(final StreamSource source) {
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java
b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java
index 4543e89..510ea56 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java
@@ -16,19 +16,21 @@
*/
package org.apache.sis.storage;
-import java.util.IdentityHashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.IdentityHashMap;
import java.util.NoSuchElementException;
-import org.apache.sis.internal.storage.Resources;
-import org.apache.sis.internal.util.Citations;
-import org.apache.sis.util.ArgumentChecks;
+import org.opengis.util.ScopedName;
+import org.opengis.util.GenericName;
+import org.opengis.metadata.Metadata;
+import org.opengis.parameter.ParameterValueGroup;
import org.apache.sis.util.Localized;
+import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.WarningListener;
import org.apache.sis.util.logging.WarningListeners;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.identification.Identification;
-import org.opengis.parameter.ParameterValueGroup;
+import org.apache.sis.internal.storage.AbstractResource;
+import org.apache.sis.internal.storage.StoreUtilities;
+import org.apache.sis.internal.storage.Resources;
/**
@@ -163,6 +165,58 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
}
/**
+ * Returns the parameters used to open this data store.
+ * The collection of legal parameters is implementation-dependent
+ * ({@linkplain
org.apache.sis.parameter.DefaultParameterValue#getDescriptor() their
description}
+ * is given by {@link DataStoreProvider#getOpenParameters()}),
+ * but should contain at least a parameter named {@value
org.apache.sis.storage.DataStoreProvider#LOCATION}
+ * with a {@link java.net.URI}, {@link java.nio.file.Path} or {@link
javax.sql.DataSource} value.
+ *
+ * <p>In the event a data store must be closed and reopened later, those
parameters can be stored in a file or
+ * database and used for {@linkplain
DataStoreProvider#open(ParameterValueGroup) creating a new store} later.</p>
+ *
+ * <p>In some cases, for stores reading in-memory data or other inputs
that can not fit with
+ * {@code ParameterDescriptorGroup} requirements (for example an {@link
java.io.InputStream}
+ * connected to unknown or no {@link java.net.URL}), this method may
return null.</p>
+ *
+ * @return parameters used for opening this {@code DataStore}, or {@code
null} if not available.
+ *
+ * @see DataStoreProvider#getOpenParameters()
+ *
+ * @since 0.8
+ */
+ public abstract ParameterValueGroup getOpenParameters();
+
+ /**
+ * Sets the locale to use for formatting warnings and other messages.
+ * In a client-server architecture, it should be the locale on the
<em>client</em> side.
+ *
+ * <p>This locale is used on a <cite>best-effort</cite> basis; whether
messages will honor this locale or not
+ * depends on the code that logged warnings or threw exceptions. In Apache
SIS implementation, this locale has
+ * better chances to be honored by the {@link
DataStoreException#getLocalizedMessage()} method rather than
+ * {@code getMessage()}. See {@code getLocalizedMessage()} javadoc for
more information.</p>
+ *
+ * @param locale the new locale to use.
+ *
+ * @see DataStoreException#getLocalizedMessage()
+ */
+ public synchronized void setLocale(final Locale locale) {
+ ArgumentChecks.ensureNonNull("locale", locale);
+ this.locale = locale;
+ }
+
+ /**
+ * The locale to use for formatting warnings and other messages. This
locale if for user interfaces
+ * only – it has no effect on the data to be read or written from/to the
data store.
+ *
+ * <p>The default value is the {@linkplain Locale#getDefault() system
default locale}.</p>
+ */
+ @Override
+ public synchronized Locale getLocale() {
+ return locale;
+ }
+
+ /**
* Returns a short name or label for this data store.
* The returned name can be used in user interfaces or in error messages.
* It may be a title in natural language, but should be relatively short.
@@ -177,13 +231,17 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
* <p>This method should never throw an exception since it may be invoked
for producing error
* messages, in which case throwing an exception here would mask the
original exception.</p>
*
- * <p>Default implementation returns the {@link
StorageConnector#getStorageName()} value,
+ * <p>This method differs from {@link #getIdentifier()} in that it is
typically a file name
+ * known at construction time instead than a property read from metadata.
+ * Default implementation returns the {@link
StorageConnector#getStorageName()} value,
* or {@code null} if this data store has been created by the no-argument
constructor.
- * Note that this default value may change in any future SIS version.
Subclasses should
- * override this method if they can provide a better name.</p>
+ * Subclasses should override this method if they can provide a better
name.</p>
*
* @return a short name of label for this data store, or {@code null} if
unknown.
*
+ * @see #getIdentifier()
+ * @see #getLocale()
+ *
* @since 0.8
*/
public String getDisplayName() {
@@ -191,56 +249,51 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
}
/**
- * The locale to use for formatting warnings and other messages. This
locale if for user interfaces
- * only – it has no effect on the data to be read or written from/to the
data store.
+ * Returns an identifier for the root resource of this data store, or
{@code null} if none.
+ * If this data store contains many resources (as in an {@link Aggregate}),
+ * the returned identifier shall be different than the identifiers of
those child resources.
+ * In other words, the following equality shall hold without ambiguity:
*
- * <p>The default value is the {@linkplain Locale#getDefault() system
default locale}.</p>
- */
- @Override
- public synchronized Locale getLocale() {
- return locale;
- }
-
- /**
- * Sets the locale to use for formatting warnings and other messages.
- * In a client-server architecture, it should be the locale on the
<em>client</em> side.
+ * {@preformat java
+ * findResource(getIdentifier().toString()) == this
+ * }
*
- * <p>This locale is used on a <cite>best-effort</cite> basis; whether
messages will honor this locale or not
- * depends on the code that logged warnings or threw exceptions. In Apache
SIS implementation, this locale has
- * better chances to be honored by the {@link
DataStoreException#getLocalizedMessage()} method rather than
- * {@code getMessage()}. See {@code getLocalizedMessage()} javadoc for
more information.</p>
+ * Note that this identifier is not guaranteed to be unique between
different {@code DataStore} instances;
+ * it only needs to be unique among the resources provided by this data
store instance.
*
- * @param locale the new locale to use.
+ * <div class="section">Default implementation</div>
+ * <p>The default implementation searches for an identifier in the
metadata,
+ * at the location shown below, provided that conditions are met:</p>
*
- * @see DataStoreException#getLocalizedMessage()
- */
- public synchronized void setLocale(final Locale locale) {
- ArgumentChecks.ensureNonNull("locale", locale);
- this.locale = locale;
- }
-
- /**
- * Returns the parameters used to open this data store.
- * The collection of legal parameters is implementation-dependent
- * ({@linkplain
org.apache.sis.parameter.DefaultParameterValue#getDescriptor() their
description}
- * is given by {@link DataStoreProvider#getOpenParameters()}),
- * but should contain at least a parameter named {@value
org.apache.sis.storage.DataStoreProvider#LOCATION}
- * with a {@link java.net.URI}, {@link java.nio.file.Path} or {@link
javax.sql.DataSource} value.
+ * <blockquote>
+ * <p><b>Path:</b> {@link Resource#getMetadata() metadata} /
+ * {@link
org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo()
identificationInfo} /
+ * {@link
org.apache.sis.metadata.iso.identification.AbstractIdentification#getCitation()
citation} /
+ * {@link
org.apache.sis.metadata.iso.citation.DefaultCitation#getIdentifiers()
identifier}</p>
*
- * <p>In the event a data store must be closed and reopened later, those
parameters can be stored in a file or
- * database and used for {@linkplain
DataStoreProvider#open(ParameterValueGroup) creating a new store} later.</p>
+ * <p><b>Condition:</b> default implementation returns a non-null
identifier only if exactly one
+ * {@code citation} is found at above path. If two or more {@code
citation} instances are found,
+ * the identification is considered ambiguous and {@code null} is
returned.</p>
*
- * <p>In some cases, for stores reading in-memory data or other inputs
that can not fit with
- * {@code ParameterDescriptorGroup} requirements (for example an {@link
java.io.InputStream}
- * connected to unknown or no {@link java.net.URL}), this method may
return null.</p>
+ * <p><b>Selection:</b> the first identifier implementing the {@code
GenericName} interface is returned.
+ * If there is no such identifier, then a {@link
org.apache.sis.referencing.NamedIdentifier} is created
+ * from the first identifier. If there is no identifier at all, then
{@code null} is returned.</p>
+ * </blockquote>
*
- * @return parameters used for opening this {@code DataStore}, or {@code
null} if not available.
+ * Subclasses are encouraged to override this method with more efficient
implementations.
*
- * @see DataStoreProvider#getOpenParameters()
+ * @return an identifier for the root resource of this data store, or
{@code null} if none.
+ * @throws DataStoreException if an error occurred while fetching the
identifier.
*
- * @since 0.8
+ * @see #getMetadata()
+ * @see #getDisplayName()
+ *
+ * @since 1.0
*/
- public abstract ParameterValueGroup getOpenParameters();
+ @Override
+ public GenericName getIdentifier() throws DataStoreException {
+ return AbstractResource.identifier(getMetadata());
+ }
/**
* Returns information about the data store as a whole. The returned
metadata object can contain
@@ -251,20 +304,14 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
* @return information about resources in the data store, or {@code null}
if none.
* @throws DataStoreException if an error occurred while reading the data.
*
- * @see Resource#getMetadata()
+ * @see #getIdentifier()
*/
@Override
public abstract Metadata getMetadata() throws DataStoreException;
/**
- * Searches for a resource identified by the given identifier.
- * The given identifier should match the following metadata element of a
resource:
- *
- * <blockquote>{@link Resource#getMetadata() metadata} /
- * {@link
org.apache.sis.metadata.iso.DefaultMetadata#getIdentificationInfo()
identificationInfo} /
- * {@link
org.apache.sis.metadata.iso.identification.AbstractIdentification#getCitation()
citation} /
- * {@link
org.apache.sis.metadata.iso.citation.DefaultCitation#getIdentifiers()
identifier}</blockquote>
- *
+ * Searches for a resource identified by the given identifier. The given
identifier should be the string
+ * representation of the return value of {@link Resource#getIdentifier()}
on the desired resource.
* Implementation may also accept aliases for convenience. For example if
the full name of a resource
* is {@code "foo:bar"}, then this method may accept {@code "bar"} as a
synonymous of {@code "foo:bar"}
* provided that it does not introduce ambiguity.
@@ -272,14 +319,16 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
* <p>The default implementation verifies if above criterion matches to
this {@code DataStore}
* (which is itself a resource), then iterates recursively over {@link
Aggregate} components
* if this data store is an aggregate.
- * If a match is found without ambiguity, the associated resource is
returned.
- * Otherwise an exception is thrown. Subclasses are encouraged to override
this method with a more efficient
- * implementation.</p>
+ * If a match is found without ambiguity, the associated resource is
returned. Otherwise an exception is thrown.
+ * Subclasses are encouraged to override this method with a more efficient
implementation.</p>
*
* @param identifier identifier of the resource to fetch. Must be
non-null.
* @return resource associated to the given identifier (never {@code
null}).
* @throws IllegalNameException if no resource is found for the given
identifier, or if more than one resource is found.
* @throws DataStoreException if another kind of error occurred while
searching resources.
+ *
+ * @see Resource#getIdentifier()
+ * @see FeatureNaming
*/
public Resource findResource(final String identifier) throws
DataStoreException {
ArgumentChecks.ensureNonEmpty("identifier", identifier);
@@ -287,8 +336,7 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
if (resource != null) {
return resource;
}
- throw new IllegalNameException(Resources.forLocale(getLocale())
- .getString(Resources.Keys.ResourceNotFound_2,
getDisplayName(), identifier));
+ throw new IllegalNameException(StoreUtilities.resourceNotFound(this,
identifier));
}
/**
@@ -304,15 +352,12 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
final Map<Resource,Boolean> visited) throws DataStoreException
{
if (candidate != null && visited.put(candidate, Boolean.TRUE) == null)
{
- final Metadata metadata = candidate.getMetadata();
- if (metadata != null) {
- for (final Identification identification :
metadata.getIdentificationInfo()) {
- if (identification != null) {
// Paranoiac check.
- if
(Citations.identifierMatches(identification.getCitation(), null, identifier)) {
- return candidate;
- }
- }
+ GenericName name = candidate.getIdentifier();
+ if (name != null) {
+ do if (identifier.equals(name.toString())) {
+ return candidate;
}
+ while ((name instanceof ScopedName) && name != (name =
((ScopedName) name).tail()));
}
if (candidate instanceof Aggregate) {
Resource result = null;
@@ -384,4 +429,15 @@ public abstract class DataStore implements Resource,
Localized, AutoCloseable {
*/
@Override
public abstract void close() throws DataStoreException;
+
+ /**
+ * Returns a string representation of this data store for debugging
purpose.
+ * The content of the string returned by this method may change in any
future SIS version.
+ *
+ * @return a string representation of this data store for debugging
purpose.
+ */
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + '[' + getDisplayName() + ']';
+ }
}
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java
b/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java
index d854510..d12951e 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java
@@ -30,6 +30,9 @@ import org.apache.sis.util.resources.Vocabulary;
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
+ *
+ * @see DataStore#findResource(String)
+ *
* @version 0.8
* @since 0.8
* @module
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/storage/Resource.java
b/storage/sis-storage/src/main/java/org/apache/sis/storage/Resource.java
index f29ce87..5a62011 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/Resource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/Resource.java
@@ -53,27 +53,29 @@ import org.apache.sis.storage.event.ChangeListener;
*/
public interface Resource {
/**
- * Returns the resource primary identifier.
+ * Returns the resource persistent identifier.
* This identifier can be used to uniquely identify a resource in the
containing {@link DataStore}.
* For this identifier to be reliable the following conditions must hold:
*
* <ul>
- * <li>It must be unique in the {@link DataStore} which contains it, if
there is one.</li>
- * <li>It's value must not change after closing and reopening the {@link
DataStore} on the same data.</li>
- * <li>This identifier must be consistent with the value returned by
{@link #getMetadata()}
- * in the field at path {@literal
identificationInfo/citation/identifier}.
- * </li>
+ * <li>It shall be unique in the {@link DataStore} which contains it, if
there is one.</li>
+ * <li>It's value shall not change after closing and reopening the
{@link DataStore} on the same data.</li>
+ * <li>It should be consistent with the <code>{@linkplain
#getMetadata()}/identificationInfo/citation/identifier</code> value.</li>
* </ul>
*
- * If any of the above conditions is not met, this identifier should be
null.
+ * If any of above conditions is not met, then this identifier should be
{@code null}.
* This case may happen when a resource is an intermediate result of an
ongoing process
* or is a temporary resource generated on-the-fly, for example a sensor
event.
*
- * @return an identifier unique within the data store, or {@code null} if
the resource has no reliable identifier.
+ * @return a persistent identifier unique within the data store, or {@code
null} if this resource has no such identifier.
+ * @throws DataStoreException if an error occurred while fetching the
identifier.
+ *
+ * @see DataStore#getIdentifier()
+ * @see DataStore#findResource(String)
*
* @since 1.0
*/
- GenericName getIdentifier();
+ GenericName getIdentifier() throws DataStoreException;
/**
* Returns information about this resource.
diff --git
a/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoreMock.java
b/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoreMock.java
index 93815d5..77cf42f 100644
---
a/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoreMock.java
+++
b/storage/sis-storage/src/test/java/org/apache/sis/storage/DataStoreMock.java
@@ -16,11 +16,10 @@
*/
package org.apache.sis.storage;
-import org.apache.sis.storage.event.ChangeEvent;
-import org.apache.sis.storage.event.ChangeListener;
import org.opengis.metadata.Metadata;
import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.util.GenericName;
+import org.apache.sis.storage.event.ChangeEvent;
+import org.apache.sis.storage.event.ChangeListener;
/**
@@ -45,15 +44,6 @@ final strictfp class DataStoreMock extends DataStore {
}
/**
- * Mock data store has no identifier.
- * @return null
- */
- @Override
- public GenericName getIdentifier() {
- return null;
- }
-
- /**
* Returns the display name specified at construction time.
*/
@Override
diff --git
a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java
b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java
index fc6aae2..7c8db04 100644
---
a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java
+++
b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java
@@ -16,36 +16,37 @@
*/
package org.apache.sis.internal.storage.gpx;
-import java.io.UncheckedIOException;
-import java.net.URISyntaxException;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
-import org.apache.sis.internal.storage.AbstractResource;
-import org.apache.sis.internal.storage.xml.stream.StaxDataStore;
-import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.metadata.iso.citation.DefaultCitation;
-import org.apache.sis.metadata.iso.distribution.DefaultFormat;
-import org.apache.sis.setup.GeometryLibrary;
-import org.apache.sis.setup.OptionKey;
-import org.apache.sis.storage.ConcurrentReadException;
-import org.apache.sis.storage.DataStoreContentException;
-import org.apache.sis.storage.DataStoreException;
+import java.io.UncheckedIOException;
+import java.net.URISyntaxException;
+import org.opengis.util.NameFactory;
+import org.opengis.util.FactoryException;
+import org.opengis.geometry.Envelope;
+import org.opengis.metadata.Metadata;
+import org.opengis.metadata.distribution.Format;
import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.IllegalNameException;
import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.storage.ConcurrentReadException;
+import org.apache.sis.storage.IllegalNameException;
+import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.storage.AbstractResource;
+import org.apache.sis.internal.storage.xml.stream.StaxDataStore;
+import org.apache.sis.util.collection.BackingStoreException;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.Version;
-import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.setup.OptionKey;
+import org.apache.sis.setup.GeometryLibrary;
import org.apache.sis.util.iso.DefaultNameFactory;
import org.apache.sis.util.iso.SimpleInternationalString;
+import org.apache.sis.metadata.iso.citation.DefaultCitation;
+import org.apache.sis.metadata.iso.distribution.DefaultFormat;
+
+// Branch-dependent imports
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
-import org.opengis.geometry.Envelope;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.distribution.Format;
-import org.opengis.util.FactoryException;
-import org.opengis.util.GenericName;
-import org.opengis.util.NameFactory;
/**
@@ -147,16 +148,6 @@ public final class Store extends StaxDataStore implements
FeatureSet {
}
/**
- * Returns GPX parent feature type name.
- *
- * @return feature type name.
- */
- @Override
- public GenericName getIdentifier() {
- return types.parent.getName();
- }
-
- /**
* Returns information about the dataset as a whole.
*
* @return information about the dataset, or {@code null} if none.