You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2018/11/19 18:40:20 UTC
[sis] branch geoapi-4.0 updated: NetcdfStore.components() now
include GridCoverageResources.
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 16c8dca NetcdfStore.components() now include GridCoverageResources.
16c8dca is described below
commit 16c8dcae3cef957b391e6c43adf4732ed6665563
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Mon Nov 19 16:38:36 2018 +0100
NetcdfStore.components() now include GridCoverageResources.
---
.../internal/referencing/ServicesForMetadata.java | 2 +
.../sis/storage/geotiff/ImageFileDirectory.java | 5 +-
.../org/apache/sis/internal/netcdf/Decoder.java | 8 ++
.../java/org/apache/sis/internal/netcdf/Grid.java | 2 +
.../org/apache/sis/internal/netcdf/Variable.java | 31 ++++--
.../sis/internal/netcdf/impl/FeaturesInfo.java | 10 ++
.../sis/internal/netcdf/impl/VariableInfo.java | 24 ++++-
.../sis/internal/netcdf/ucar/GridWrapper.java | 2 +-
.../sis/internal/netcdf/ucar/VariableWrapper.java | 30 +++++-
.../apache/sis/storage/netcdf/GridResource.java | 118 +++++++++++++++++++++
.../org/apache/sis/storage/netcdf/NetcdfStore.java | 11 +-
.../apache/sis/internal/netcdf/VariableTest.java | 12 +--
.../org/apache/sis/internal/sql/feature/Table.java | 4 +-
.../sis/internal/storage/AbstractFeatureSet.java | 39 ++++++-
.../sis/internal/storage/AbstractGridResource.java | 14 +++
.../sis/internal/storage/AbstractResource.java | 76 ++++++++-----
.../sis/internal/storage/MemoryFeatureSet.java | 21 ++--
.../sis/internal/storage/MetadataBuilder.java | 5 +
.../apache/sis/storage/GridCoverageResource.java | 2 +-
.../sis/internal/storage/JoinFeatureSetTest.java | 4 +-
.../internal/storage/query/SimpleQueryTest.java | 2 +-
21 files changed, 360 insertions(+), 62 deletions(-)
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
index b563dd4..1dba7a3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
@@ -371,6 +371,8 @@ public final class ServicesForMetadata extends ReferencingServices {
* @param envelope the source envelope.
* @param target the target extent where to store envelope information.
* @throws TransformException if a coordinate transformation was required and failed.
+ * @throws UnsupportedOperationException if this method requires an Apache SIS module
+ * which has been found on the classpath.
*/
@Override
public void addElements(final Envelope envelope, final DefaultExtent target) throws TransformException {
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 4cc3df0..a0be1a4 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
@@ -25,7 +25,6 @@ import java.util.logging.LogRecord;
import java.nio.charset.Charset;
import javax.measure.Unit;
import javax.measure.quantity.Length;
-import org.opengis.metadata.Metadata;
import org.opengis.metadata.citation.DateType;
import org.opengis.util.FactoryException;
import org.opengis.util.GenericName;
@@ -1210,7 +1209,8 @@ final class ImageFileDirectory extends AbstractGridResource {
}
@Override
- public Metadata getMetadata() throws DataStoreContentException {
+ protected void createMetadata(final MetadataBuilder metadata) throws DataStoreException {
+ super.createMetadata(metadata);
/*
* TODO:
* - Modify ImageFileDirectory.completeMetadata(…) with the addition of a boolean telling that
@@ -1222,7 +1222,6 @@ final class ImageFileDirectory extends AbstractGridResource {
* - Invoke that method from here if GeoTiffStore already has a metadata, or conversely from
* GeoTiffStore if ImageResource already has a metadata.
*/
- return null;
}
/**
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 0d72170..90756d7 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,6 +21,7 @@ import java.util.Objects;
import java.util.Collection;
import java.io.Closeable;
import java.io.IOException;
+import java.nio.file.Path;
import org.opengis.util.NameSpace;
import org.opengis.util.NameFactory;
import org.opengis.referencing.datum.Datum;
@@ -51,6 +52,13 @@ public abstract class Decoder extends ReferencingFactoryContainer implements Clo
public static final String FORMAT_NAME = "netCDF";
/**
+ * The path to the netCDF file, or {@code null} if unknown.
+ * This is set by netCDF store constructor and shall not be modified afterward.
+ * This is used for information purpose only, not for actual reading operation.
+ */
+ public Path location;
+
+ /**
* 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.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
index 9583249..073dd59 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
@@ -111,6 +111,8 @@ public abstract class Grid extends NamedElement {
* This method may return {@code null} if the grid shape can not be determined.
*
* @return number of cells along each source dimension, in "natural" (opposite of netCDF) order, or {@code null}.
+ *
+ * @see Variable#getShape()
*/
protected abstract long[] getShape();
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
index 0c334d5..24c82c1 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
@@ -166,7 +166,7 @@ public abstract class Variable extends NamedElement {
public final String getDataTypeName() {
final StringBuilder buffer = new StringBuilder(20);
buffer.append(getDataType().name().toLowerCase());
- final int[] shape = getGridEnvelope();
+ final int[] shape = getShape();
for (int i=shape.length; --i>=0;) {
buffer.append('[').append(Integer.toUnsignedLong(shape[i])).append(']');
}
@@ -203,7 +203,7 @@ public abstract class Variable extends NamedElement {
*/
public final boolean isCoverage(final int minSpan) {
int numVectors = 0; // Number of dimension having more than 1 value.
- for (final int length : getGridEnvelope()) {
+ for (final int length : getShape()) {
if (Integer.toUnsignedLong(length) >= minSpan) {
numVectors++;
}
@@ -226,8 +226,21 @@ public abstract class Variable extends NamedElement {
public abstract boolean isCoordinateSystemAxis();
/**
+ * Returns the grid geometry for this variable, or {@code null} if this variable is not a data cube.
+ * Not all variables have a grid geometry. For example collections of features do not have such grid.
+ * The same grid geometry may be shared by many variables.
+ *
+ * @param decoder the decoder to use for constructing the grid geometry if needed.
+ * @return the grid geometry for this variable, or {@code null} if none.
+ * @throws IOException if an error occurred while reading the data.
+ * @throws DataStoreException if a logical error occurred.
+ */
+ public abstract Grid getGridGeometry(Decoder decoder) throws IOException, DataStoreException;
+
+ /**
* Returns the names of the dimensions of this variable, in the order they are declared in the netCDF file.
* The dimensions are those of the grid, not the dimensions of the coordinate system.
+ * This information is used for completing ISO 19115 metadata.
*
* @return the names of all dimension of the grid, in netCDF order (reverse of "natural" order).
*/
@@ -236,13 +249,17 @@ public abstract class Variable extends NamedElement {
/**
* Returns the length (number of cells) of each grid dimension, in the order they are declared in the netCDF file.
* The length of this array shall be equals to the length of the {@link #getGridDimensionNames()} array.
+ * Values shall be handled as unsigned 32 bits integers.
*
* <p>In ISO 19123 terminology, this method returns the upper corner of the grid envelope plus one.
- * The lower corner is always (0, 0, …, 0).</p>
+ * The lower corner is always (0, 0, …, 0). This method is used by {@link #isCoverage(int)} method,
+ * or for building string representations of this variable.</p>
+ *
+ * @return the number of grid cells for each dimension, as unsigned integer in netCDF order (reverse of "natural" order).
*
- * @return the number of grid cells for each dimension, in netCDF order (reverse of "natural" order).
+ * @see Grid#getShape()
*/
- public abstract int[] getGridEnvelope();
+ public abstract int[] getShape();
/**
* Returns the names of all attributes associated to this variable.
@@ -310,7 +327,7 @@ public abstract class Variable extends NamedElement {
* Constraints on the argument values are:
*
* <ul>
- * <li>All arrays length shall be equal to the length of the {@link #getGridEnvelope()} array.</li>
+ * <li>All arrays length shall be equal to the length of the {@link #getShape()} array.</li>
* <li>For each index <var>i</var>, value of {@code area[i]} shall be in the range from 0 inclusive
* to {@code Integer.toUnsignedLong(getGridEnvelope()[i])} exclusive.</li>
* </ul>
@@ -418,7 +435,7 @@ public abstract class Variable extends NamedElement {
@Override
public String toString() {
final StringBuilder buffer = new StringBuilder(getName()).append(" : ").append(getDataType());
- final int[] shape = getGridEnvelope();
+ final int[] shape = getShape();
for (int i=shape.length; --i>=0;) {
buffer.append('[').append(Integer.toUnsignedLong(shape[i])).append(']');
}
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 dbc84e1..149443c 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
@@ -293,6 +293,16 @@ search: for (final VariableInfo counts : decoder.variables) {
}
/**
+ * Returns the number of features in this set.
+ *
+ * @return the number of features.
+ */
+ @Override
+ protected Integer getFeatureCount() {
+ return counts.size();
+ }
+
+ /**
* Returns the stream of features.
*
* @param parallel ignored, since current version does not support parallelism.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
index 8712326..524716c 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
@@ -28,12 +28,14 @@ import ucar.nc2.constants.CDM;
import ucar.nc2.constants._Coordinate;
import org.apache.sis.internal.netcdf.Decoder;
import org.apache.sis.internal.netcdf.DataType;
+import org.apache.sis.internal.netcdf.Grid;
import org.apache.sis.internal.netcdf.Variable;
import org.apache.sis.internal.netcdf.Resources;
import org.apache.sis.internal.storage.io.ChannelDataInput;
import org.apache.sis.internal.storage.io.HyperRectangleReader;
import org.apache.sis.internal.storage.io.Region;
import org.apache.sis.internal.util.StandardDateFormat;
+import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.DataStoreContentException;
import org.apache.sis.storage.netcdf.AttributeNames;
import org.apache.sis.util.logging.WarningListeners;
@@ -137,6 +139,8 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo> {
* The grid geometry associated to this variable,
* computed by {@link ChannelDecoder#getGridGeometries()} when first needed.
* May stay {@code null} if the variable is not a data cube.
+ *
+ * @see #getGridGeometry(Decoder)
*/
GridInfo gridGeometry;
@@ -416,8 +420,25 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo> {
}
/**
+ * Returns the grid geometry for this variable, or {@code null} if this variable is not a data cube.
+ * The grid geometries are opportunistically cached in {@code VariableInfo} instances after they have
+ * been computed by {@link ChannelDecoder#getGridGeometries()}.
+ * The same grid geometry may be shared by many variables.
+ *
+ * @see ChannelDecoder#getGridGeometries()
+ */
+ @Override
+ public Grid getGridGeometry(final Decoder decoder) throws IOException, DataStoreException {
+ if (gridGeometry == null) {
+ decoder.getGridGeometries(); // Force calculation of grid geometries if not already done.
+ }
+ return gridGeometry;
+ }
+
+ /**
* Returns the names of the dimensions of this variable.
* The dimensions are those of the grid, not the dimensions of the coordinate system.
+ * This information is used for completing ISO 19115 metadata.
*/
@Override
public String[] getGridDimensionNames() {
@@ -431,11 +452,12 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo> {
/**
* Returns the length (number of cells) of each grid dimension. In ISO 19123 terminology, this method
* returns the upper corner of the grid envelope plus one. The lower corner is always (0,0,…,0).
+ * This method is used mostly for building string representations of this variable.
*
* @return the number of grid cells for each dimension, as unsigned integers.
*/
@Override
- public int[] getGridEnvelope() {
+ public int[] getShape() {
final int[] shape = new int[dimensions.length];
for (int i=0; i<shape.length; i++) {
shape[i] = dimensions[i].length;
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
index 8e34bf5..2787b3b 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridWrapper.java
@@ -52,7 +52,7 @@ final class GridWrapper extends Grid {
/**
* The netCDF coordinate system to wrap.
*/
- private final CoordinateSystem netcdfCS;
+ final CoordinateSystem netcdfCS;
/**
* Creates a new grid geometry for the given netCDF coordinate system.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
index 560594e..10bde94 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
@@ -27,6 +27,7 @@ import ucar.ma2.InvalidRangeException;
import ucar.nc2.Attribute;
import ucar.nc2.Dimension;
import ucar.nc2.VariableIF;
+import ucar.nc2.dataset.Enhancements;
import ucar.nc2.dataset.VariableEnhanced;
import ucar.nc2.dataset.CoordinateAxis1D;
import ucar.nc2.units.SimpleUnit;
@@ -34,11 +35,14 @@ import ucar.nc2.units.DateUnit;
import org.opengis.referencing.operation.Matrix;
import org.apache.sis.math.Vector;
import org.apache.sis.internal.netcdf.DataType;
+import org.apache.sis.internal.netcdf.Decoder;
+import org.apache.sis.internal.netcdf.Grid;
import org.apache.sis.internal.netcdf.Variable;
import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.util.logging.WarningListeners;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.measure.Units;
+import ucar.nc2.dataset.CoordinateSystem;
/**
@@ -198,8 +202,31 @@ final class VariableWrapper extends Variable {
}
/**
+ * Returns the grid geometry for this variable, or {@code null} if this variable is not a data cube.
+ * This method searches for a grid previously computed by {@link DecoderWrapper#getGridGeometries()}.
+ * The same grid geometry may be shared by many variables.
+ *
+ * @see DecoderWrapper#getGridGeometries()
+ */
+ @Override
+ public Grid getGridGeometry(final Decoder decoder) throws IOException, DataStoreException {
+ if (variable instanceof Enhancements) {
+ final List<CoordinateSystem> cs = ((Enhancements) variable).getCoordinateSystems();
+ if (cs != null && !cs.isEmpty()) {
+ for (final Grid grid : decoder.getGridGeometries()) {
+ if (cs.contains(((GridWrapper) grid).netcdfCS)) {
+ return grid;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the names of the dimensions of this variable.
* The dimensions are those of the grid, not the dimensions of the coordinate system.
+ * This information is used for completing ISO 19115 metadata.
*/
@Override
public String[] getGridDimensionNames() {
@@ -214,9 +241,10 @@ final class VariableWrapper extends Variable {
/**
* Returns the length (number of cells) of each grid dimension. In ISO 19123 terminology, this method
* returns the upper corner of the grid envelope plus one. The lower corner is always (0,0,…,0).
+ * This method is used mostly for building string representations of this variable.
*/
@Override
- public int[] getGridEnvelope() {
+ public int[] getShape() {
return variable.getShape();
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/GridResource.java b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/GridResource.java
new file mode 100644
index 0000000..30b2a28
--- /dev/null
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/GridResource.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.netcdf;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.io.IOException;
+import java.nio.file.Path;
+import org.opengis.util.GenericName;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.internal.netcdf.Decoder;
+import org.apache.sis.internal.netcdf.Grid;
+import org.apache.sis.internal.netcdf.Variable;
+import org.apache.sis.internal.storage.AbstractGridResource;
+import org.apache.sis.internal.storage.ResourceOnFileSystem;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.Resource;
+
+
+/**
+ * A grid coverage in a netCDF file.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+final class GridResource extends AbstractGridResource implements ResourceOnFileSystem {
+ /**
+ * The identifier of this grid resource.
+ * This is the variable name.
+ */
+ private final GenericName identifier;
+
+ /**
+ * The grid geometry (size, CRS…) of the {@linkplain #data} cube.
+ */
+ private final GridGeometry gridGeometry;
+
+ /**
+ * The netCDF variable wrapped by this resource.
+ */
+ private final Variable data;
+
+ /**
+ * Path to the netCDF file for information purpose, or {@code null} if unknown.
+ */
+ private final Path location;
+
+ /**
+ * Creates a new resource.
+ *
+ * @param decoder the implementation used for decoding the netCDF file.
+ * @param grid the grid geometry (size, CRS…) of the {@linkplain #data} cube.
+ * @param data the variable providing actual data.
+ */
+ private GridResource(final Decoder decoder, final Grid grid, final Variable data) throws IOException, DataStoreException {
+ super(decoder.listeners);
+ this.data = data;
+ gridGeometry = grid.getGridGeometry(decoder);
+ identifier = decoder.nameFactory.createLocalName(decoder.namespace, data.getName());
+ location = decoder.location;
+ }
+
+ /**
+ * Returns a list of all grid resources found in the netCDF file opened by the given decoder.
+ * This method should be invoked only once and the result cached. The returned list is modifiable;
+ * caller is free to add other elements.
+ */
+ static List<Resource> list(final Decoder decoder) throws IOException, DataStoreException {
+ final List<Resource> resources = new ArrayList<>();
+ for (final Variable variable : decoder.getVariables()) {
+ final Grid grid = variable.getGridGeometry(decoder);
+ if (grid != null) {
+ resources.add(new GridResource(decoder, grid, variable));
+ }
+ }
+ return resources;
+ }
+
+ /**
+ * Returns the variable name as an identifier of this resource.
+ */
+ @Override
+ public GenericName getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Returns an object containing the grid size, the CRS and the conversion from grid indices to CRS coordinates.
+ */
+ @Override
+ public GridGeometry getGridGeometry() throws DataStoreException {
+ return gridGeometry;
+ }
+
+ /**
+ * Gets the paths to files used by this resource, or an empty array if unknown.
+ */
+ @Override
+ public Path[] getComponentFiles() throws DataStoreException {
+ return (location != null) ? new Path[] {location} : new Path[0];
+ }
+}
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 8176dca..5b4c071 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
@@ -17,6 +17,7 @@
package org.apache.sis.storage.netcdf;
import java.io.IOException;
+import java.nio.file.Path;
import java.net.URI;
import java.util.List;
import java.util.Collection;
@@ -97,6 +98,7 @@ public class NetcdfStore extends DataStore implements Aggregate {
public NetcdfStore(final NetcdfStoreProvider provider, final StorageConnector connector) throws DataStoreException {
super(provider, connector);
location = connector.getStorageAs(URI.class);
+ final Path path = connector.getStorageAs(Path.class);
try {
decoder = NetcdfStoreProvider.decoder(listeners, connector);
} catch (IOException | ArithmeticException e) {
@@ -106,6 +108,7 @@ public class NetcdfStore extends DataStore implements Aggregate {
throw new UnsupportedStorageException(super.getLocale(), NetcdfStoreProvider.NAME,
connector.getStorage(), connector.getOption(OptionKey.OPEN_OPTIONS));
}
+ decoder.location = path;
String id = decoder.stringValue(ACDD.id);
if (id == null || (id = id.trim()).isEmpty()) {
id = decoder.getFilename();
@@ -199,7 +202,13 @@ public class NetcdfStore extends DataStore implements Aggregate {
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public synchronized Collection<Resource> components() throws DataStoreException {
if (components == null) try {
- components = UnmodifiableArrayList.wrap(decoder.getDiscreteSampling());
+ Resource[] resources = decoder.getDiscreteSampling();
+ final List<Resource> list = GridResource.list(decoder);
+ if (!list.isEmpty()) {
+ list.addAll(UnmodifiableArrayList.wrap(resources));
+ resources = list.toArray(new Resource[list.size()]);
+ }
+ components = UnmodifiableArrayList.wrap(resources);
} catch (IOException e) {
throw new DataStoreException(e);
}
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java
index 7782f4c..8ebdb20 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java
@@ -89,7 +89,7 @@ public strictfp class VariableTest extends TestCase {
* <li>{@link Variable#getName()}</li>
* <li>{@link Variable#getDescription()}</li>
* <li>{@link Variable#getDataType()}</li>
- * <li>{@link Variable#getGridEnvelope()} length</li>
+ * <li>{@link Variable#getShape()} length</li>
* <li>{@link Variable#isCoordinateSystemAxis()}</li>
* <li>{@link Variable#isCoverage(int)}</li>
* </ul>
@@ -126,7 +126,7 @@ public strictfp class VariableTest extends TestCase {
assertEquals(name, expected[propertyIndex++], name);
assertEquals(name, expected[propertyIndex++], variable.getDescription());
assertEquals(name, expected[propertyIndex++], dataType);
- assertEquals(name, expected[propertyIndex++], variable.getGridEnvelope().length);
+ assertEquals(name, expected[propertyIndex++], variable.getShape().length);
assertEquals(name, expected[propertyIndex++], variable.isCoordinateSystemAxis());
assertEquals(name, expected[propertyIndex++], variable.isCoverage(2));
assertEquals(0, propertyIndex % NUM_BASIC_PROPERTY_COLUMNS); // Sanity check for VariableTest itself.
@@ -137,7 +137,7 @@ public strictfp class VariableTest extends TestCase {
}
/**
- * Tests {@link Variable#getGridDimensionNames()} and {@link Variable#getGridEnvelope()}
+ * Tests {@link Variable#getGridDimensionNames()} and {@link Variable#getShape()}
* on a simple two-dimensional dataset.
*
* @throws IOException if an I/O error occurred while opening the file.
@@ -154,11 +154,11 @@ public strictfp class VariableTest extends TestCase {
assertArrayEquals("getGridEnvelope()", new int[] {
73, 73
- }, variable.getGridEnvelope());
+ }, variable.getShape());
}
/**
- * Tests {@link Variable#getGridDimensionNames()} and {@link Variable#getGridEnvelope()}
+ * Tests {@link Variable#getGridDimensionNames()} and {@link Variable#getShape()}
* on a compound four-dimensional dataset.
*
* @throws IOException if an I/O error occurred while opening the file.
@@ -175,7 +175,7 @@ public strictfp class VariableTest extends TestCase {
assertArrayEquals("getGridEnvelope()", new int[] {
1, 4, 19, 38
- }, variable.getGridEnvelope());
+ }, variable.getShape());
}
/**
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 e41af4e..1589506 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
@@ -570,8 +570,8 @@ final class Table extends AbstractFeatureSet {
* change at any time.
*
* @param metadata information about the database.
- * @param approximate whether approximative or outdated values are acceptable.
- * @return number of rows (may be approximative), or -1 if unknown.
+ * @param approximate whether approximate or outdated values are acceptable.
+ * @return number of rows (may be approximate), or -1 if unknown.
*/
final long countRows(final DatabaseMetaData metadata, final boolean approximate) throws SQLException {
long count = -1;
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
index e386c4e..fe7ad8c 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
@@ -30,7 +30,20 @@ import org.opengis.feature.FeatureType;
/**
- * Base implementation of feature sets contained in data stores.
+ * Base implementation of feature sets contained in data stores. This class provides a {@link #getMetadata()}
+ * which extracts information from other methods. Subclasses shall or should override the following methods:
+ *
+ * <ul>
+ * <li>{@link #getType()} (mandatory)</li>
+ * <li>{@link #getFeatureCount()} (recommended)</li>
+ * <li>{@link #getEnvelope()} (recommended)</li>
+ * <li>{@link #createMetadata(MetadataBuilder)} (optional)</li>
+ * <li>{@link #features(boolean parallel)} (mandatory)</li>
+ * </ul>
+ *
+ * {@section Thread safety}
+ * Default methods of this abstract class are thread-safe.
+ * Synchronization, when needed, uses {@code this} lock.
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
@@ -76,6 +89,30 @@ public abstract class AbstractFeatureSet extends AbstractResource implements Fea
}
/**
+ * Returns an estimation of the number of features in this set, or {@code null} if unknown.
+ * The default implementation returns {@code null}.
+ *
+ * @return estimation of the number of features, or {@code null}.
+ */
+ protected Integer getFeatureCount() {
+ return null;
+ }
+
+ /**
+ * Invoked the first time that {@link #getMetadata()} is invoked. The default implementation populates metadata
+ * based on information provided by {@link #getType()}, {@link #getIdentifier()} and {@link #getEnvelope()}.
+ * Subclasses should override if they can provide more information.
+ *
+ * @param metadata the builder where to set metadata properties.
+ * @throws DataStoreException if an error occurred while reading metadata from the data store.
+ */
+ @Override
+ protected void createMetadata(final MetadataBuilder metadata) throws DataStoreException {
+ super.createMetadata(metadata);
+ metadata.addFeatureType(getType(), getFeatureCount());
+ }
+
+ /**
* Requests a subset of features and/or feature properties from this resource.
* The default implementation try to execute the queries by filtering the
* {@linkplain #features(boolean) stream of features}, which may be inefficient.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java
index 9d967bb..5590872 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractGridResource.java
@@ -68,4 +68,18 @@ public abstract class AbstractGridResource extends AbstractResource implements G
}
return null;
}
+
+ /**
+ * Invoked the first time that {@link #getMetadata()} is invoked. The default implementation populates
+ * metadata based on information provided by {@link #getIdentifier()} and {@link #getGridGeometry()}.
+ * Subclasses should override if they can provide more information.
+ *
+ * @param metadata the builder where to set metadata properties.
+ * @throws DataStoreException if an error occurred while reading metadata from the data store.
+ */
+ @Override
+ protected void createMetadata(final MetadataBuilder metadata) throws DataStoreException {
+ super.createMetadata(metadata);
+ metadata.addSpatialRepresentation(null, getGridGeometry(), false);
+ }
}
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 69f973f..d482384 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
@@ -20,6 +20,7 @@ import java.util.Locale;
import org.opengis.util.GenericName;
import org.opengis.metadata.Metadata;
import org.opengis.geometry.Envelope;
+import org.opengis.referencing.operation.TransformException;
import org.apache.sis.util.Localized;
import org.apache.sis.util.logging.WarningListeners;
import org.apache.sis.storage.Resource;
@@ -27,16 +28,21 @@ import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.event.ChangeEvent;
import org.apache.sis.storage.event.ChangeListener;
-import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.iso.citation.DefaultCitation;
-import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
/**
- * 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.
+ * Base implementation of resources contained in data stores. This class provides a {@link #getMetadata()}
+ * which extracts information from other methods. Subclasses shall or should override the following methods:
+ *
+ * <ul>
+ * <li>{@link #getIdentifier()} (mandatory)</li>
+ * <li>{@link #getEnvelope()} (recommended)</li>
+ * <li>{@link #createMetadata(MetadataBuilder)} (optional)</li>
+ * </ul>
+ *
+ * {@section Thread safety}
+ * Default methods of this abstract class are thread-safe.
+ * Synchronization, when needed, uses {@code this} lock.
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.0
@@ -47,17 +53,14 @@ public abstract class AbstractResource implements Resource, Localized {
/**
* A description of this resource as an unmodifiable metadata, or {@code null} if not yet computed.
* If non-null, this metadata shall contain at least the resource {@linkplain #getIdentifier() identifier}.
- *
- * <p>Those metadata are created by {@link #getMetadata()} when first needed.
- * Subclasses can set a value to this field directly if they wish to bypass the
- * default metadata creation process.</p>
+ * Those metadata are created by {@link #getMetadata()} when first needed.
*/
- protected Metadata metadata;
+ private Metadata metadata;
/**
* The set of registered warning listeners for the data store, or {@code null} if none.
*/
- protected final WarningListeners<DataStore> listeners;
+ private final WarningListeners<DataStore> listeners;
/**
* Creates a new resource.
@@ -102,11 +105,11 @@ public abstract class AbstractResource implements Resource, Localized {
}
/**
- * Returns the spatio-temporal envelope of this resource.
- * The default implementation returns {@code null}.
+ * Returns the spatio-temporal envelope of this resource. This information is part of API only in some kind of resources
+ * like {@link org.apache.sis.storage.FeatureSet}. But the method is provided in this base class for convenience and for
+ * allowing {@link #getMetadata()} to use this information if available. The default implementation returns {@code null}.
*
* @return the spatio-temporal resource extent, or {@code null} if none.
- *
* @throws DataStoreException if an error occurred while reading or computing the envelope.
*/
public Envelope getEnvelope() throws DataStoreException {
@@ -114,26 +117,43 @@ public abstract class AbstractResource implements Resource, Localized {
}
/**
- * Returns a description of this set of features.
- * Current implementation sets only the resource name; this may change in any future Apache SIS version.
+ * Returns a description of this resource. This method invokes {@link #createMetadata(MetadataBuilder)}
+ * the first time it is invoked, then cache the result.
+ *
+ * @return information about this resource (never {@code null} in this implementation).
+ * @throws DataStoreException if an error occurred while reading or computing the envelope.
*/
@Override
- public synchronized Metadata getMetadata() throws DataStoreException {
+ public final synchronized Metadata getMetadata() throws DataStoreException {
if (metadata == null) {
- final DefaultMetadata metadata = new DefaultMetadata();
- final GenericName name = getIdentifier();
- if (name != null) { // Paranoiac check (should never be null).
- final DefaultCitation citation = new DefaultCitation(name.toInternationalString());
- final DefaultDataIdentification identification = new DefaultDataIdentification();
- identification.setCitation(citation);
- }
- metadata.transition(DefaultMetadata.State.FINAL);
- this.metadata = metadata;
+ final MetadataBuilder builder = new MetadataBuilder();
+ createMetadata(builder);
+ metadata = builder.build(true);
}
return metadata;
}
/**
+ * Invoked the first time that {@link #getMetadata()} is invoked. The default implementation populates
+ * metadata based on information provided by {@link #getIdentifier()} and {@link #getEnvelope()}.
+ * Subclasses should override if they can provide more information.
+ *
+ * @param metadata the builder where to set metadata properties.
+ * @throws DataStoreException if an error occurred while reading metadata from the data store.
+ */
+ protected void createMetadata(final MetadataBuilder metadata) throws DataStoreException {
+ final GenericName name = getIdentifier();
+ if (name != null) {
+ metadata.addTitle(name.toInternationalString());
+ }
+ try {
+ metadata.addExtent(getEnvelope());
+ } catch (TransformException | UnsupportedOperationException e) {
+ listeners.warning(null, e);
+ }
+ }
+
+ /**
* Ignored in current implementation, on the assumption that most resources produce no events.
*
* @param <T> {@inheritDoc}
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 32a911d..fb21125 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,7 +18,6 @@ package org.apache.sis.internal.storage;
import java.util.Collection;
import java.util.stream.Stream;
-import org.opengis.metadata.Metadata;
import org.apache.sis.storage.DataStore;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.WarningListeners;
@@ -29,8 +28,8 @@ import org.opengis.feature.FeatureType;
/**
- * Set of features stored in memory.
- * Metadata and features are specified at construction time.
+ * Set of features stored in memory. Features are specified at construction time.
+ * Metadata can be specified by overriding {@link #createMetadata(MetadataBuilder)}.
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
@@ -38,7 +37,7 @@ import org.opengis.feature.FeatureType;
* @since 1.0
* @module
*/
-public final class MemoryFeatureSet extends AbstractFeatureSet {
+public class MemoryFeatureSet extends AbstractFeatureSet {
/**
* The type specified at construction time and returned by {@link #getType()}.
*/
@@ -56,11 +55,10 @@ public final class MemoryFeatureSet extends AbstractFeatureSet {
* (this is not verified).
*
* @param listeners the set of registered warning listeners for the data store, or {@code null} if none.
- * @param metadata information about this resource, or {@code null} for inferring default metadata.
* @param type the type of all features in the given collection.
* @param features collection of stored features. This collection will not be copied.
*/
- public MemoryFeatureSet(final WarningListeners<DataStore> listeners, Metadata metadata,
+ public MemoryFeatureSet(final WarningListeners<DataStore> listeners,
final FeatureType type, final Collection<Feature> features)
{
super(listeners);
@@ -68,7 +66,6 @@ public final class MemoryFeatureSet extends AbstractFeatureSet {
ArgumentChecks.ensureNonNull("features", features);
this.type = type;
this.features = features;
- this.metadata = metadata;
}
/**
@@ -82,6 +79,16 @@ public final class MemoryFeatureSet extends AbstractFeatureSet {
}
/**
+ * Returns the number of features in this set.
+ *
+ * @return the number of features.
+ */
+ @Override
+ protected Integer getFeatureCount() {
+ return features.size();
+ }
+
+ /**
* Returns a stream of all features contained in this dataset.
*
* @param parallel {@code true} for a parallel stream (if supported), or {@code false} for a sequential stream.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
index 336302c..2ff8150 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
@@ -1910,7 +1910,12 @@ parse: for (int i = 0; i < length;) {
* <li>{@code metadata/referenceSystemInfo}</li>
* </ul>
*
+ * This method does not add the envelope provided by {@link GridGeometry#getEnvelope()}.
+ * That envelope appears in a separated node, which can be added by {@link #addExtent(Envelope)}.
+ * This separation is required by {@link AbstractGridResource} for instance.
+ *
* @param description a general description of the "grid to CRS" transformation, or {@code null} if none.
+ * Can also be specified later by a call to {@link #setGridToCRS(CharSequence)}.
* @param grid the grid extent, "grid to CRS" transform and target CRS, or {@code null} if none.
* @param addResolution whether to declare the resolutions. Callers should set this argument to {@code false} if they intend
* to provide the resolution themselves, or if grid axes are not in the same order than CRS axes.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java
index 903c341..4945014 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java
@@ -28,7 +28,7 @@ import org.apache.sis.coverage.grid.GridGeometry;
* @since 1.0
* @module
*/
-public interface GridCoverageResource extends Resource {
+public interface GridCoverageResource extends DataSet {
/**
* Returns the valid extent of grid coordinates together with the transform
* from those grid coordinates to real world coordinates.
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/JoinFeatureSetTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/JoinFeatureSetTest.java
index 8234b50..fada5a1 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/JoinFeatureSetTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/JoinFeatureSetTest.java
@@ -70,7 +70,7 @@ public final strictfp class JoinFeatureSetTest extends TestCase {
builder.addAttribute( String.class).setName("myNameSpace", "att1");
builder.addAttribute(Integer.class).setName("myNameSpace", "att2");
final FeatureType type1 = builder.build();
- featureSet1 = new MemoryFeatureSet(null, null, type1, Arrays.asList(
+ featureSet1 = new MemoryFeatureSet(null, type1, Arrays.asList(
newFeature1(type1, "fid_1_0", "str1", 1),
newFeature1(type1, "fid_1_1", "str2", 2),
newFeature1(type1, "fid_1_2", "str3", 3),
@@ -82,7 +82,7 @@ public final strictfp class JoinFeatureSetTest extends TestCase {
builder.addAttribute(Integer.class).setName("otherNameSpace", "att3");
builder.addAttribute( Double.class).setName("otherNameSpace", "att4");
final FeatureType type2 = builder.build();
- featureSet2 = new MemoryFeatureSet(null, null, type2, Arrays.asList(
+ featureSet2 = new MemoryFeatureSet(null, type2, Arrays.asList(
newFeature2(type2, "fid_2_0", 1, 10),
newFeature2(type2, "fid_2_1", 2, 20),
newFeature2(type2, "fid_2_2", 2, 30),
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java
index 4f7ba90..f29bb82 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java
@@ -80,7 +80,7 @@ public final strictfp class SimpleQueryTest extends TestCase {
feature(type, 1, 1),
feature(type, 4, 1)
};
- featureSet = new MemoryFeatureSet(null, null, type, Arrays.asList(features));
+ featureSet = new MemoryFeatureSet(null, type, Arrays.asList(features));
query = new SimpleQuery();
}