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 3130e0d Provide a hook for netCDF files to be interpreted according
some specialized convention. https://issues.apache.org/jira/browse/SIS-315
3130e0d is described below
commit 3130e0da912f89c7377de910fdab60137a585f6d
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Jan 16 14:37:11 2019 +0100
Provide a hook for netCDF files to be interpreted according some
specialized convention.
https://issues.apache.org/jira/browse/SIS-315
---
.../org/apache/sis/internal/netcdf/Convention.java | 114 +++++++++++++++++++++
.../org/apache/sis/internal/netcdf/Decoder.java | 43 ++++++++
.../org/apache/sis/internal/netcdf/Variable.java | 34 +++---
.../apache/sis/internal/netcdf/VariableRole.java | 43 ++++++++
.../sis/internal/netcdf/impl/ChannelDecoder.java | 61 ++++++++---
.../sis/internal/netcdf/impl/VariableInfo.java | 14 +--
.../sis/internal/netcdf/ucar/DecoderWrapper.java | 2 +
.../sis/internal/netcdf/ucar/VariableWrapper.java | 7 +-
.../apache/sis/storage/netcdf/GridResource.java | 10 +-
.../apache/sis/storage/netcdf/MetadataReader.java | 3 +-
.../apache/sis/internal/netcdf/VariableTest.java | 24 ++---
11 files changed, 297 insertions(+), 58 deletions(-)
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
new file mode 100644
index 0000000..df8f27c
--- /dev/null
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
@@ -0,0 +1,114 @@
+/*
+ * 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.internal.netcdf;
+
+import java.util.Iterator;
+import org.apache.sis.internal.referencing.LazySet;
+
+
+/**
+ * Extends the CF-Conventions with some conventions particular to a data
producer.
+ * By default, Apache SIS netCDF reader applies the <a
href="http://cfconventions.org">CF conventions</a>.
+ * But some data producers does not provides all necessary information for
allowing Apache SIS to read the
+ * netCDF file. Some information may be missing because considered implicit by
the data producer.
+ * This class provides a mechanism for supplying the implicit values.
+ * Conventions can be registered in a file having this exact path:
+ *
+ *
<blockquote><pre>META-INF/services/org.apache.sis.internal.netcdf.Convention</pre></blockquote>
+ *
+ * <p><b>This is an experimental class for internal usage only (for now).</b>
+ * The API of this class is likely to change in any future Apache SIS version.
+ * This class may become public (in a modified form) in the future if we gain
+ * enough experience about extending netCDF conventions.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/SIS-315">SIS-315</a>
+ *
+ * @since 1.0
+ * @module
+ */
+public abstract class Convention {
+ /**
+ * All conventions found on the classpath.
+ */
+ private static final LazySet<Convention> AVAILABLES = new
LazySet<>(Convention.class);
+
+ /**
+ * For subclass constructors.
+ */
+ protected Convention() {
+ }
+
+ /**
+ * Finds the convention to apply to the file opened by the given decoder,
or {@code null} if none.
+ */
+ static synchronized Convention find(final Decoder decoder) {
+ final Iterator<Convention> it;
+ Convention c;
+ synchronized (AVAILABLES) {
+ it = AVAILABLES.iterator();
+ if (!it.hasNext()) return null;
+ c = it.next();
+ }
+ while (!c.isApplicableTo(decoder)) {
+ synchronized (AVAILABLES) {
+ if (!it.hasNext()) return null;
+ c = it.next();
+ }
+ }
+ return c;
+ }
+
+ /**
+ * Detects if this set of conventions applies to the given netCDF file.
+ *
+ * @param decoder the netCDF file to test.
+ * @return {@code true} if this set of conventions can apply.
+ */
+ protected abstract boolean isApplicableTo(Decoder decoder);
+
+ /**
+ * Returns the role of the given variable. In particular, this method
shall return
+ * {@link VariableRole#AXIS} if the given variable seems to be a
coordinate system axis.
+ *
+ * @param variable the variable for which to get the role.
+ * @return role of the given variable.
+ */
+ protected VariableRole roleOf(final Variable variable) {
+ return variable.getRole();
+ }
+
+ /**
+ * Returns the names of the variables containing data for all dimension of
a variable.
+ * Each netCDF variable can have an arbitrary number of dimensions
identified by their name.
+ * The data for a dimension are usually stored in a variable of the same
name, but not always.
+ * This method gives an opportunity for subclasses to select the axis
variables using other criterion.
+ * This happen for example if a netCDF file defines two grids for the same
dimensions.
+ *
+ * <p>The default implementation returns {@code null}.</p>
+ *
+ * @param variable the variable for which the list of axis variables are
desired.
+ * @return names of the variables containing axis values, or {@code null}
if this
+ * method performs applies no special convention for the given
variable.
+ */
+ protected String[] namesOfAxisVariables(Variable variable) {
+ 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 90756d7..425611b 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
@@ -59,6 +59,11 @@ public abstract class Decoder extends
ReferencingFactoryContainer implements Clo
public Path location;
/**
+ * Customized conventions to apply in addition of netCDF conventions, or
{@code null} if none.
+ */
+ private Convention convention;
+
+ /**
* 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.
@@ -109,6 +114,14 @@ public abstract class Decoder extends
ReferencingFactoryContainer implements Clo
}
/**
+ * Shall be invoked by subclass constructors after the finished their
construction, for completing initialization.
+ * This method checks if an extension to CF-convention applies to the
current file.
+ */
+ protected final void initialize() {
+ convention = Convention.find(this);
+ }
+
+ /**
* Returns a filename for formatting error message and for information
purpose.
* The filename should not contain path, but may contain file extension.
*
@@ -255,4 +268,34 @@ public abstract class Decoder extends
ReferencingFactoryContainer implements Clo
* @throws DataStoreException if a logical error occurred.
*/
public abstract Grid[] getGridGeometries() throws IOException,
DataStoreException;
+
+ /**
+ * Returns the role of the given variable. In particular, this method
shall return
+ * {@link VariableRole#AXIS} if the given variable seems to be a
coordinate system axis.
+ *
+ * @param variable the variable for which to get the role, or {@code
null}.
+ * @return role of the given variable, or {@code null} if the given
variable was null.
+ */
+ public final VariableRole roleOf(final Variable variable) {
+ if (variable == null) {
+ return null;
+ }
+ if (convention != null) {
+ return convention.roleOf(variable);
+ }
+ return variable.getRole();
+ }
+
+ /**
+ * If there is some specialized convention for current file that mandate a
different set of
+ * axes for the given variable, returns the name of the variables for
those axes. Otherwise
+ * (i.e. if the file can be parsed as a standard CF-compliant file),
returns {@code null}.
+ *
+ * @param variable the variable for which the list of axis variables are
desired.
+ * @return names of the variables containing axis values, or {@code null}
if this
+ * method performs applies no special convention for the given
variable.
+ */
+ protected final String[] namesOfAxisVariables(final Variable variable) {
+ return (convention != null) ?
convention.namesOfAxisVariables(variable) : null;
+ }
}
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 62e857a..a363279 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
@@ -295,8 +295,13 @@ public abstract class Variable extends NamedElement {
public abstract boolean isUnlimited();
/**
- * Returns {@code true} if the given variable can be used for generating
an image.
- * This method checks for the following conditions:
+ * Returns whether this variable is used as a coordinate system axis, a
coverage or something else.
+ * In particular this method shall return {@link VariableRole#AXIS} if
this variable seems to be a
+ * coordinate system axis instead than the actual data. By netCDF
convention, coordinate system axes
+ * have the name of one of the dimensions defined in the netCDF header.
+ *
+ * <p>The default implementation returns {@link VariableRole#COVERAGE} if
the given variable can be used
+ * for generating an image, by checking the following conditions:</p>
*
* <ul>
* <li>Images require at least {@value Grid#MIN_DIMENSION} dimensions of
size equals or greater than {@value Grid#MIN_SPAN}.
@@ -308,9 +313,16 @@ public abstract class Variable extends NamedElement {
* to confuse them with images.</li>
* </ul>
*
- * @return {@code true} if the variable can be considered a coverage.
+ * Subclasses shall override this method for checking the {@link
VariableRole#AXIS} case before to delegate
+ * to this method.
+ *
+ * <p>This method has protected access because it should not be invoked
directly except in overridden methods.
+ * Code using variable role should invoke {@link Decoder#roleOf(Variable)}
instead, for allowing specialization
+ * by {@link Convention}.</p>
+ *
+ * @return the role of this variable.
*/
- public final boolean isCoverage() {
+ protected VariableRole getRole() {
int numVectors = 0; // Number of
dimension having more than 1 value.
for (final int length : getShape()) {
if (Integer.toUnsignedLong(length) >= Grid.MIN_SPAN) {
@@ -320,21 +332,13 @@ public abstract class Variable extends NamedElement {
if (numVectors >= Grid.MIN_DIMENSION) {
final DataType dataType = getDataType();
if (dataType.rasterDataType != DataBuffer.TYPE_UNDEFINED) {
- return !isCoordinateSystemAxis();
+ return VariableRole.COVERAGE;
}
}
- return false;
+ return VariableRole.OTHER;
}
/**
- * Returns {@code true} if this variable seems to be a coordinate system
axis instead than the actual data.
- * By netCDF convention, coordinate system axes have the name of one of
the dimensions defined in the netCDF header.
- *
- * @return {@code true} if this variable seems to be a coordinate system
axis.
- */
- 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.
@@ -361,7 +365,7 @@ public abstract class Variable extends NamedElement {
* 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). This method is used by {@link
#isCoverage()} method,
+ * The lower corner is always (0, 0, …, 0). This method is used by {@link
#getRole()} 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).
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/VariableRole.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/VariableRole.java
new file mode 100644
index 0000000..380d30a
--- /dev/null
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/VariableRole.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.netcdf;
+
+
+/**
+ * Specifies whether a variable is used as a coordinate system axis, a
coverage or other purpose.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+public enum VariableRole {
+ /**
+ * The variable is a coordinate system axis.
+ */
+ AXIS,
+
+ /**
+ * The variable is a grid coverage.
+ */
+ COVERAGE,
+
+ /**
+ * Unidentified kind of variable.
+ */
+ OTHER
+}
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 f468756..720b172 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
@@ -277,6 +277,7 @@ public final class ChannelDecoder extends Decoder {
this.attributeMap = attributes;
this.variables = variables;
this.variableMap = toCaseInsensitiveNameMap(variables);
+ initialize();
}
/**
@@ -843,6 +844,33 @@ public final class ChannelDecoder extends Decoder {
}
/**
+ * Adds to the given set all variables of the given names. This operation
is performed when the set of axes is
+ * specified by a {@code "coordinates"} attribute associated to a data
variable, or by customized conventions
+ * specified by {@link
org.apache.sis.internal.netcdf.Convention#namesOfAxisVariables(Variable)}.
+ *
+ * @param names names of variables containing axis data, or {@code
null} if none.
+ * @param axes where to add named variables.
+ * @param dimensions where to report all dimensions used by added axes.
+ * @return whether {@code names} was non-null.
+ */
+ private boolean listAxes(final CharSequence[] names, final
Set<VariableInfo> axes, final Set<Dimension> dimensions) {
+ if (names == null) {
+ return false;
+ }
+ for (int i=names.length; --i >= 0;) {
+ final VariableInfo axis = findVariable(names[i].toString());
+ if (axis == null) {
+ dimensions.clear();
+ axes.clear();
+ break;
+ }
+ axes.add(axis);
+ dimensions.addAll(Arrays.asList(axis.dimensions));
+ }
+ return true;
+ }
+
+ /**
* Returns all grid geometries found in the netCDF file.
* This method returns a direct reference to an internal array - do not
modify.
*
@@ -860,9 +888,18 @@ public final class ChannelDecoder extends Decoder {
*/
final Map<Dimension, List<VariableInfo>> dimToAxes = new
IdentityHashMap<>();
for (final VariableInfo variable : variables) {
- if (variable.isCoordinateSystemAxis()) {
- for (final Dimension dimension : variable.dimensions) {
- CollectionsExt.addToMultiValuesMap(dimToAxes,
dimension, variable);
+ switch (roleOf(variable)) {
+ case COVERAGE: {
+ // If Convention.roleOf(…) overwrote the value
computed by VariableInfo,
+ // remember the new value for avoiding to ask again in
next loops.
+ variable.isCoordinateSystemAxis = false;
+ break;
+ }
+ case AXIS: {
+ variable.isCoordinateSystemAxis = true;
+ for (final Dimension dimension : variable.dimensions) {
+ CollectionsExt.addToMultiValuesMap(dimToAxes,
dimension, variable);
+ }
}
}
}
@@ -874,7 +911,7 @@ public final class ChannelDecoder extends Decoder {
final Set<Dimension> usedDimensions = new HashSet<>(8);
final Map<GridInfo,GridInfo> shared = new LinkedHashMap<>();
nextVar: for (final VariableInfo variable : variables) {
- if (variable.isCoordinateSystemAxis() ||
variable.dimensions.length == 0) {
+ if (variable.isCoordinateSystemAxis ||
variable.dimensions.length == 0) {
continue;
}
/*
@@ -886,21 +923,11 @@ nextVar: for (final VariableInfo variable : variables)
{
*/
axes.clear();
usedDimensions.clear();
- final CharSequence[] coordinates =
variable.getCoordinateVariables();
- if (coordinates.length != 0) {
- for (int i=coordinates.length; --i >= 0;) {
- final VariableInfo axis =
findVariable(coordinates[i].toString());
- if (axis == null) {
- usedDimensions.clear();
- axes.clear();
- break;
- }
- axes.add(axis);
- usedDimensions.addAll(Arrays.asList(axis.dimensions));
- }
+ if (!listAxes(variable.getCoordinateVariables(), axes,
usedDimensions)) {
+ listAxes(namesOfAxisVariables(variable), axes,
usedDimensions);
}
/*
- * In theory the "coordinates" attribute would enumerate all
axis needed for covering all dimensions,
+ * In theory the "coordinates" attribute would enumerate all
axes needed for covering all dimensions,
* and we would not need to check for variables having
dimension names. However in practice there is
* incomplete attributes, so we check for other dimensions
even if the above loop did some work.
*/
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 9250446..fbffe03 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
@@ -34,6 +34,7 @@ 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.VariableRole;
import org.apache.sis.internal.netcdf.Resources;
import org.apache.sis.internal.storage.io.ChannelDataInput;
import org.apache.sis.internal.storage.io.HyperRectangleReader;
@@ -154,10 +155,8 @@ final class VariableInfo extends Variable implements
Comparable<VariableInfo> {
* {@code true} if this variable seems to be a coordinate system axis, as
determined by comparing its name
* with the name of all dimensions in the netCDF file. This information is
computed at construction time
* because requested more than once.
- *
- * @see #isCoordinateSystemAxis()
*/
- private boolean isCoordinateSystemAxis;
+ boolean isCoordinateSystemAxis;
/**
* The values of the whole variable, or {@code null} if not yet read. This
vector should be assigned only
@@ -437,13 +436,13 @@ final class VariableInfo extends Variable implements
Comparable<VariableInfo> {
}
/**
- * Returns {@code true} if this variable seems to be a coordinate system
axis,
+ * Returns {@code AXIS} if this variable seems to be a coordinate system
axis,
* determined by comparing its name with the name of all dimensions in the
netCDF file.
* Also determined by inspection of {@code "coordinates"} attribute on
other variables.
*/
@Override
- public boolean isCoordinateSystemAxis() {
- return isCoordinateSystemAxis;
+ protected VariableRole getRole() {
+ return isCoordinateSystemAxis ? VariableRole.AXIS : super.getRole();
}
/**
@@ -557,6 +556,9 @@ final class VariableInfo extends Variable implements
Comparable<VariableInfo> {
* This method does not search the lower-case variant of the given name
because the argument given to this method
* is usually a hard-coded value from {@link CF} or {@link CDM}
conventions, which are already in lower-cases.
*
+ * <p>All {@code getAttributeValue(…)} methods in this class ultimately
invokes this method.
+ * This provide a single point to override if the functionality needs to
be extended.</p>
+ *
* @param attributeName name of attribute to search, in the expected
case.
* @return variable attribute value of the given name, or {@code null} if
none.
*/
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 edda4ff..acc53b7 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
@@ -108,6 +108,7 @@ public final class DecoderWrapper extends Decoder
implements CancelTask {
public DecoderWrapper(final NetcdfFile file, final GeometryLibrary
geomlib, final WarningListeners<DataStore> listeners) {
super(geomlib, listeners);
this.file = file;
+ initialize();
}
/**
@@ -124,6 +125,7 @@ public final class DecoderWrapper extends Decoder
implements CancelTask {
{
super(geomlib, listeners);
file = NetcdfDataset.openDataset(filename, false, this);
+ initialize();
}
/**
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 abefde8..94da9c7 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
@@ -41,6 +41,7 @@ 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.netcdf.VariableRole;
import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.util.logging.WarningListeners;
import org.apache.sis.storage.DataStoreException;
@@ -206,11 +207,11 @@ final class VariableWrapper extends Variable {
}
/**
- * Returns {@code true} if this variable seems to be a coordinate system
axis.
+ * Returns {@code AXIS} if this variable seems to be a coordinate system
axis.
*/
@Override
- public boolean isCoordinateSystemAxis() {
- return variable.isCoordinateVariable();
+ protected VariableRole getRole() {
+ return variable.isCoordinateVariable() ? VariableRole.AXIS :
super.getRole();
}
/**
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
index 8ea8595..a7c7ccd 100644
---
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
@@ -34,6 +34,7 @@ import org.apache.sis.internal.netcdf.Grid;
import org.apache.sis.internal.netcdf.DataType;
import org.apache.sis.internal.netcdf.Variable;
import org.apache.sis.internal.netcdf.Resources;
+import org.apache.sis.internal.netcdf.VariableRole;
import org.apache.sis.internal.storage.AbstractGridResource;
import org.apache.sis.internal.storage.ResourceOnFileSystem;
import org.apache.sis.coverage.SampleDimension;
@@ -155,8 +156,11 @@ final class GridResource extends AbstractGridResource
implements ResourceOnFileS
final List<Resource> resources = new ArrayList<>();
for (int i=0; i<variables.length; i++) {
final Variable variable = variables[i];
- final Grid grid;
- if (variable == null || !variable.isCoverage() || (grid =
variable.getGridGeometry(decoder)) == null) {
+ if (decoder.roleOf(variable) != VariableRole.COVERAGE) {
+ continue; //
Skip variables that are not grid coverages.
+ }
+ final Grid grid = variable.getGridGeometry(decoder);
+ if (grid == null) {
continue; //
Skip variables that are not grid coverages.
}
siblings.add(variable);
@@ -180,7 +184,7 @@ final class GridResource extends AbstractGridResource
implements ResourceOnFileS
int suffixLength = name.length() - suffixStart;
for (int j=i; ++j < variables.length;) {
final Variable candidate = variables[j];
- if (candidate == null || !candidate.isCoverage()) {
+ if (decoder.roleOf(candidate) !=
VariableRole.COVERAGE) {
variables[j] = null;
// For avoiding to revisit that variable again.
continue;
}
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 d8735a8..db25359 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
@@ -60,6 +60,7 @@ import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.internal.netcdf.Axis;
import org.apache.sis.internal.netcdf.Decoder;
import org.apache.sis.internal.netcdf.Variable;
+import org.apache.sis.internal.netcdf.VariableRole;
import org.apache.sis.internal.netcdf.Grid;
import org.apache.sis.internal.storage.io.IOUtilities;
import org.apache.sis.internal.storage.MetadataBuilder;
@@ -893,7 +894,7 @@ split: while ((start =
CharSequences.skipLeadingWhitespaces(value, start, lengt
private void addContentInfo() {
final Map<List<String>, List<Variable>> contents = new HashMap<>(4);
for (final Variable variable : decoder.getVariables()) {
- if (variable.isCoverage()) {
+ if (decoder.roleOf(variable) == VariableRole.COVERAGE) {
final List<String> dimensions =
Arrays.asList(variable.getGridDimensionNames());
CollectionsExt.addToMultiValuesMap(contents, dimensions,
variable);
}
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 a8bfeb7..019750c 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
@@ -47,7 +47,7 @@ public strictfp class VariableTest extends TestCase {
* Expected number of columns per variables for the {@code expected}
argument
* given to the {@link #assertBasicPropertiesEqual(Object[], Variable[])}
method.
*/
- private static final int NUM_BASIC_PROPERTY_COLUMNS = 6;
+ private static final int NUM_BASIC_PROPERTY_COLUMNS = 5;
/**
* Whether the {@code "runtime"} variable in {@link
TestData#NETCDF_4D_PROJECTED} is considered an axis or not.
@@ -92,8 +92,7 @@ public strictfp class VariableTest extends TestCase {
* <li>{@link Variable#getDescription()}</li>
* <li>{@link Variable#getDataType()}</li>
* <li>{@link Variable#getShape()} length</li>
- * <li>{@link Variable#isCoordinateSystemAxis()}</li>
- * <li>{@link Variable#isCoverage()}</li>
+ * <li>{@link Variable#getRole()}</li>
* </ul>
*
* @throws IOException if an I/O error occurred while opening the file.
@@ -102,14 +101,14 @@ public strictfp class VariableTest extends TestCase {
@Test
public void testBasicProperties() throws IOException, DataStoreException {
assertBasicPropertiesEqual(new Object[] {
- //
__name______________description_____________________datatype_______dim__axis?__raster?
- "grid_mapping_0", null, DataType.INT,
0, false, false,
- "x0", "projection_x_coordinate", DataType.FLOAT,
1, true, false,
- "y0", "projection_y_coordinate", DataType.FLOAT,
1, true, false,
- "z0", "Flight levels in 100s of feet", DataType.FLOAT,
1, true, false,
- "time", "Data time",
DataType.DOUBLE, 1, true, false,
- "runtime", "Data generation time",
DataType.DOUBLE, 1, isRuntimeAnAxis, false,
- "CIP", "Current Icing Product", DataType.FLOAT,
4, false, true
+ //
__name______________description_____________________datatype_______dim__role
+ "grid_mapping_0", null, DataType.INT,
0, VariableRole.OTHER,
+ "x0", "projection_x_coordinate", DataType.FLOAT,
1, VariableRole.AXIS,
+ "y0", "projection_y_coordinate", DataType.FLOAT,
1, VariableRole.AXIS,
+ "z0", "Flight levels in 100s of feet", DataType.FLOAT,
1, VariableRole.AXIS,
+ "time", "Data time",
DataType.DOUBLE, 1, VariableRole.AXIS,
+ "runtime", "Data generation time",
DataType.DOUBLE, 1, isRuntimeAnAxis ? VariableRole.AXIS : VariableRole.OTHER,
+ "CIP", "Current Icing Product", DataType.FLOAT,
4, VariableRole.COVERAGE
}, getVariablesCIP(selectDataset(TestData.NETCDF_4D_PROJECTED)));
}
@@ -129,8 +128,7 @@ public strictfp class VariableTest extends TestCase {
assertEquals(name, expected[propertyIndex++],
variable.getDescription());
assertEquals(name, expected[propertyIndex++], dataType);
assertEquals(name, expected[propertyIndex++],
variable.getShape().length);
- assertEquals(name, expected[propertyIndex++],
variable.isCoordinateSystemAxis());
- assertEquals(name, expected[propertyIndex++],
variable.isCoverage());
+ assertEquals(name, expected[propertyIndex++], variable.getRole());
assertEquals(0, propertyIndex % NUM_BASIC_PROPERTY_COLUMNS);
// Sanity check for VariableTest itself.
}
assertEquals("Expected more variables.",