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

commit c8abdcf8f0663bfabf3832893bda4cbc274ab0f7
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Feb 22 16:19:44 2019 +0100

    Move Variable.getNodataValues() implementation into Convention for allowing 
overriding. This move forces us to retain a reference to Decoder into Variable 
in order to get the conventions.
---
 .../java/org/apache/sis/measure/NumberRange.java   |  4 +-
 .../java/org/apache/sis/internal/netcdf/Axis.java  |  4 +-
 .../org/apache/sis/internal/netcdf/Convention.java | 46 ++++++++++++++
 .../org/apache/sis/internal/netcdf/Dimension.java  |  2 +-
 .../java/org/apache/sis/internal/netcdf/Grid.java  |  4 +-
 .../org/apache/sis/internal/netcdf/Variable.java   | 70 ++++++++++------------
 .../sis/internal/netcdf/impl/ChannelDecoder.java   |  4 +-
 .../apache/sis/internal/netcdf/impl/GridInfo.java  |  4 +-
 .../sis/internal/netcdf/impl/VariableInfo.java     | 39 ++++++------
 .../sis/internal/netcdf/ucar/DecoderWrapper.java   |  4 +-
 .../sis/internal/netcdf/ucar/GridWrapper.java      |  2 +-
 .../sis/internal/netcdf/ucar/VariableWrapper.java  | 15 +++--
 .../apache/sis/storage/netcdf/GridResource.java    | 37 +++++++-----
 13 files changed, 139 insertions(+), 96 deletions(-)

diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/NumberRange.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/NumberRange.java
index 77be12c..6010bd1 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/NumberRange.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/NumberRange.java
@@ -309,7 +309,7 @@ public class NumberRange<E extends Number & Comparable<? 
super E>> extends Range
 
     /**
      * Constructs a range using the smallest type of {@link Number} that can 
hold the given values.
-     * The given numbers don't need to be of the same type since they will
+     * The given numbers do not need to be of the same type since they will
      * be {@linkplain Numbers#cast(Number, Class) casted} as needed.
      * More specifically this method returns:
      *
@@ -322,7 +322,7 @@ public class NumberRange<E extends Number & Comparable<? 
super E>> extends Range
      *       {@value java.lang.Integer#MIN_VALUE} and {@value 
java.lang.Integer#MAX_VALUE} inclusive.</li>
      *   <li>{@code NumberRange<Long>} if the given values are integers in the 
range of {@code long} values.</li>
      *   <li>{@code NumberRange<Float>} if the given values can be casted to 
{@code float} values without data lost.</li>
-     *   <li>{@code NumberRange<Double>} If none of the above types is 
suitable.</li>
+     *   <li>{@code NumberRange<Double>} if none of the above types is 
suitable.</li>
      * </ul>
      *
      * This method may return a shared instance, at implementation choice.
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
index 65f139f..f9ca69b 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
@@ -656,8 +656,8 @@ main:   switch (getDimension()) {
     /**
      * Reports a non-fatal error that occurred while constructing the grid 
geometry. This method is invoked
      * by methods that are themselves invoked (indirectly) by {@link 
Grid#getGridGeometry(Decoder)}, which
-     * is invoked by {@link Variable#getGridGeometry(Decoder)}. We pretend 
that the warning come from the
-     * later since it is a bit closer to a public API.
+     * is invoked by {@link Variable#getGridGeometry()}. We pretend that the 
warning come from the later
+     * since it is a bit closer to a public API.
      *
      * @param  exception  the exception that occurred, or {@code null} if none.
      * @param  key        one or {@link Errors.Keys} constants.
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
index 29a745e..8cfa6e6 100644
--- 
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
@@ -16,7 +16,9 @@
  */
 package org.apache.sis.internal.netcdf;
 
+import java.util.Map;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.awt.image.DataBuffer;
 import org.apache.sis.internal.referencing.LazySet;
 import org.apache.sis.referencing.operation.transform.TransferFunction;
@@ -36,6 +38,7 @@ import ucar.nc2.constants.CDM;
  *
  * 
<blockquote><pre>META-INF/services/org.apache.sis.internal.netcdf.Convention</pre></blockquote>
  *
+ * Instances of this class must be immutable and thread-safe.
  * This class does not encapsulate all conventions needed for understanding a 
netCDF file,
  * but only conventions that are more likely to need to be overridden for some 
data producers.
  *
@@ -86,6 +89,15 @@ public class Convention {
     };
 
     /**
+     * Names of attributes where to fetch missing or pad values. Order matter 
since it determines the bits to be set in the
+     * map returned by {@link #nodataValues(Variable)}. The main bit is bit 
#0, which identifies the background value.
+     */
+    private static final String[] NODATA_ATTRIBUTES = {
+        CDM.FILL_VALUE,
+        CDM.MISSING_VALUE
+    };
+
+    /**
      * For subclass constructors.
      */
     protected Convention() {
@@ -375,12 +387,46 @@ public class Convention {
     }
 
     /**
+     * Returns all no-data values declared for the given variable, or an empty 
map if none.
+     * The map keys are the no-data values (pad sample values or missing 
sample values).
+     * The map values can be either {@link String} or {@link 
org.opengis.util.InternationalString} values
+     * containing the description of the no-data value, or an {@link Integer} 
set to a bitmask identifying
+     * the role of the pad/missing sample value:
+     *
+     * <ul>
+     *   <li>If bit 0 is set, then the value is a pad value. Those values can 
be used for background.</li>
+     *   <li>If bit 1 is set, then the value is a missing value.</li>
+     * </ul>
+     *
+     * Pad values should be first in the map, followed by missing values.
+     * The same value may have more than one role.
+     *
+     * @param  data  the variable for which to get no-data values.
+     * @return no-data values with bitmask of their roles or textual 
descriptions.
+     */
+    public Map<Number,Object> nodataValues(final Variable data) {
+        final Map<Number,Object> pads = new LinkedHashMap<>();
+        for (int i=0; i < NODATA_ATTRIBUTES.length; i++) {
+            for (final Object value : 
data.getAttributeValues(NODATA_ATTRIBUTES[i], true)) {
+                if (value instanceof Number) {
+                    pads.merge((Number) value, 1 << i, (v1, v2) -> ((Integer) 
v1) | ((Integer) v2));
+                }
+            }
+        }
+        return pads;
+    }
+
+    /**
      * Builds the function converting values from their packed formats in the 
variable to "real" values.
      * The transfer function is typically built from the {@code 
"scale_factor"} and {@code "add_offset"}
      * attributes associated to the given variable, but other conventions 
could use different attributes.
      * The returned function will be a component of the {@link 
org.apache.sis.coverage.SampleDimension}
      * to be created for each variable.
      *
+     * <p>This method is invoked only if {@link #validRange(Variable)} 
returned a non-null value.
+     * Since a transfer function is assumed to exist in such case (even if 
that function is identity),
+     * this method shall never return {@code null}.</p>
+     *
      * @param  data  the variable from which to determine the transfer 
function.
      *               This is usually a variable containing raster data.
      *
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java
index 969ab4b..0b13627 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Dimension.java
@@ -28,7 +28,7 @@ import org.apache.sis.util.resources.Vocabulary;
  * and {@code Dimension.equals(object)} must return {@code true} if two {@code 
Dimension}
  * instances represent the same netCDF dimensions. This may require subclasses 
to override
  * {@link #hashCode()} and {@link #equals(Object)} if uniqueness is not 
guaranteed.
- * This is needed by {@link Variable#getGrid(Decoder)} default 
implementation.</p>
+ * This is needed by {@link Variable#getGrid()} default implementation.</p>
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
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 91c7943..07c5a1b 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
@@ -106,8 +106,8 @@ public abstract class Grid extends NamedElement {
 
     /**
      * Returns a localization grid having the same dimensions than this grid 
but in a different order.
-     * This method is invoked by {@link Variable#getGrid(Decoder)} when the 
localization grids created
-     * by {@link Decoder} subclasses are not sufficient and must be tailored 
for a particular variable.
+     * This method is invoked by {@link Variable#getGrid()} when the 
localization grids created by
+     * {@link Decoder} subclasses are not sufficient and must be tailored for 
a particular variable.
      * Subclasses should verify that the given {@code dimensions} array meets 
the following conditions:
      *
      * <ul>
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 4ca118c..a6dfaaf 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
@@ -20,7 +20,6 @@ import java.util.Set;
 import java.util.Map;
 import java.util.HashSet;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.Collection;
 import java.util.List;
 import java.util.ArrayList;
@@ -42,7 +41,6 @@ import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.util.CollectionsExt;
-import org.apache.sis.util.logging.WarningListeners;
 import org.apache.sis.util.resources.Errors;
 import ucar.nc2.constants.CDM;                      // We use only String 
constants.
 import ucar.nc2.constants.CF;
@@ -68,13 +66,9 @@ public abstract class Variable extends NamedElement {
     protected static final WeakHashSet<Vector> SHARED_VECTORS = new 
WeakHashSet<>(Vector.class);
 
     /**
-     * Names of attributes where to fetch missing or pad values. Order matter 
since it determines the bits to be set
-     * in the map returned by {@link #getNodataValues()}. The main bit is bit 
0, which identify the background value.
+     * The netCDF file where this variable is stored.
      */
-    private static final String[] NODATA_ATTRIBUTES = {
-        CDM.FILL_VALUE,
-        CDM.MISSING_VALUE
-    };
+    protected final Decoder decoder;
 
     /**
      * The pattern to use for parsing temporal units of the form "days since 
1970-01-01 00:00:00".
@@ -111,8 +105,11 @@ public abstract class Variable extends NamedElement {
     /**
      * All no-data values declared for this variable, or an empty map if none.
      * This is computed by {@link #getNodataValues()} and cached for 
efficiency and stability.
+     * The meaning of entries in this map is described in {@code 
getNodataValues()} method javadoc.
+     *
+     * @see #getNodataValues()
      */
-    private Map<Number,Integer> nodataValues;
+    private Map<Number,Object> nodataValues;
 
     /**
      * Factors by which to multiply a grid index in order to get the 
corresponding data index, or {@code null} if none.
@@ -126,17 +123,12 @@ public abstract class Variable extends NamedElement {
     private double[] gridToDataIndices;
 
     /**
-     * Where to report warnings, if any.
-     */
-    private final WarningListeners<?> listeners;
-
-    /**
      * Creates a new variable.
      *
-     * @param listeners where to report warnings.
+     * @param decoder  the netCDF file where this variable is stored.
      */
-    protected Variable(final WarningListeners<?> listeners) {
-        this.listeners = listeners;
+    protected Variable(final Decoder decoder) {
+        this.decoder = decoder;
     }
 
     /**
@@ -145,7 +137,9 @@ public abstract class Variable extends NamedElement {
      *
      * @return name of the netCDF file containing this variable, or {@code 
null} if unknown.
      */
-    public abstract String getFilename();
+    public String getFilename() {
+        return decoder.getFilename();
+    }
 
     /**
      * Returns the name of this variable.
@@ -337,12 +331,11 @@ public abstract class Variable extends NamedElement {
      * Subclasses should override this class with a more direct implementation 
and invoke this implementation only as a fallback.
      * Typically, subclasses will handle case #1 in above list and this 
implementation is invoked for case #2.
      *
-     * @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.
      */
-    protected Grid getGrid(final Decoder decoder) throws IOException, 
DataStoreException {
+    protected Grid getGrid() throws IOException, DataStoreException {
         final Convention convention = decoder.convention();
         /*
          * Collect all axis dimensions, in no particular order. We use this 
map for determining
@@ -465,13 +458,12 @@ public abstract class Variable extends NamedElement {
      * 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 final GridGeometry getGridGeometry(final Decoder decoder) throws 
IOException, DataStoreException {
-        final Grid info = getGrid(decoder);
+    public final GridGeometry getGridGeometry() throws IOException, 
DataStoreException {
+        final Grid info = getGrid();
         if (info == null) {
             return null;
         }
@@ -663,34 +655,30 @@ public abstract class Variable extends NamedElement {
 
     /**
      * Returns all no-data values declared for this variable, or an empty map 
if none.
-     * The map keys are pad sample values or missing sample values. The map 
values are
-     * bitmask identifying the role of the pad/missing sample value:
+     * The map keys are the no-data values (pad sample values or missing 
sample values).
+     * The map values can be either {@link String} or {@link 
org.opengis.util.InternationalString} values
+     * containing the description of the no-data value, or an {@link Integer} 
set to a bitmask identifying
+     * the role of the pad/missing sample value:
      *
      * <ul>
      *   <li>If bit 0 is set, then the value is a pad value. Those values can 
be used for background.</li>
      *   <li>If bit 1 is set, then the value is a missing value.</li>
      * </ul>
      *
-     * Pad values are first in the map, followed by missing values.
+     * Pad values should be first in the map, followed by missing values.
      * The same value may have more than one role.
      * The map returned by this method shall be stable, i.e. two invocations 
of this method shall return the
      * same entries in the same order. This is necessary for mapping "no data" 
values to the same NaN values,
      * since their {@linkplain MathFunctions#toNanFloat(int) ordinal values} 
are based on order.
      *
      * @return pad/missing values with bitmask of their role.
+     *
+     * @see Convention#nodataValues(Variable)
      */
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    public final Map<Number,Integer> getNodataValues() {
+    public final Map<Number,Object> getNodataValues() {
         if (nodataValues == null) {
-            final Map<Number,Integer> pads = new LinkedHashMap<>();
-            for (int i=0; i < NODATA_ATTRIBUTES.length; i++) {
-                for (final Object value : 
getAttributeValues(NODATA_ATTRIBUTES[i], true)) {
-                    if (value instanceof Number) {
-                        pads.merge((Number) value, 1 << i, (v1, v2) -> v1 | 
v2);
-                    }
-                }
-            }
-            nodataValues = CollectionsExt.unmodifiableOrCopy(pads);
+            nodataValues = 
CollectionsExt.unmodifiableOrCopy(decoder.convention().nodataValues(this));
         }
         return nodataValues;
     }
@@ -854,9 +842,11 @@ public abstract class Variable extends NamedElement {
 
     /**
      * Returns the locale to use for warnings and error messages.
+     *
+     * @return the locale for warnings and error messages.
      */
-    final Locale getLocale() {
-        return listeners.getLocale();
+    protected final Locale getLocale() {
+        return decoder.listeners.getLocale();
     }
 
     /**
@@ -877,7 +867,7 @@ public abstract class Variable extends NamedElement {
      * @param  arguments  values to be formatted in the {@link 
java.text.MessageFormat} pattern.
      */
     protected final void warning(final Class<?> caller, final String method, 
final short key, final Object... arguments) {
-        warning(listeners, caller, method, null, null, key, arguments);
+        warning(decoder.listeners, caller, method, null, null, key, arguments);
     }
 
     /**
@@ -890,7 +880,7 @@ public abstract class Variable extends NamedElement {
      * @param  arguments  values to be formatted in the {@link 
java.text.MessageFormat} pattern.
      */
     final void error(final Class<?> caller, final String method, final 
Exception exception, final short key, final Object... arguments) {
-        warning(listeners, caller, method, exception, 
Errors.getResources(listeners.getLocale()), key, arguments);
+        warning(decoder.listeners, caller, method, exception, 
Errors.getResources(getLocale()), key, arguments);
     }
 
     /**
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 42f0d92..7ce2a53 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
@@ -609,8 +609,8 @@ public final class ChannelDecoder extends Decoder {
                     default: throw malformedHeader();
                 }
             }
-            variables[j] = new VariableInfo(input, name, varDims, attributes,
-                    DataType.valueOf(input.readInt()), input.readInt(), 
readOffset(), listeners);
+            variables[j] = new VariableInfo(this, input, name, varDims, 
attributes,
+                    DataType.valueOf(input.readInt()), input.readInt(), 
readOffset());
         }
         /*
          * The VariableInfo constructor determined if the variables are 
"unlimited" or not.
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
index 90aeb08..f232f86 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
@@ -109,8 +109,8 @@ final class GridInfo extends Grid {
 
     /**
      * Returns a localization grid having the same dimensions than this grid 
but in a different order.
-     * This method is invoked by {@link VariableInfo#getGrid(Decoder)} when 
the localization grids created
-     * by {@link Decoder} subclasses are not sufficient and must be tailored 
for a particular variable.
+     * This method is invoked by {@link VariableInfo#getGrid()} when the 
localization grids created by
+     * {@link Decoder} subclasses are not sufficient and must be tailored for 
a particular variable.
      * Returns {@code null} the the given dimensions are not members of this 
grid.
      */
     @Override
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 15b3586..d2d9f09 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
@@ -45,7 +45,6 @@ import org.apache.sis.internal.util.UnmodifiableArrayList;
 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;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Numbers;
@@ -152,16 +151,16 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
      * computed by {@link ChannelDecoder#getGrids()} when first needed.
      * May stay {@code null} if the variable is not a data cube.
      *
-     * @see #getGrid(Decoder)
+     * @see #getGrid()
      */
     GridInfo grid;
 
     /**
      * For disambiguation of the case where {@link #grid} has been computed 
and the result still null.
-     * The that {@link #grid} may be determined and non-null even if this flag 
is {@code false}.
+     * Note that {@link #grid} may be determined and non-null even if this 
flag is {@code false}.
      *
      * @see #grid
-     * @see #getGrid(Decoder)
+     * @see #getGrid()
      */
     private transient boolean gridDetermined;
 
@@ -191,6 +190,7 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
     /**
      * Creates a new variable.
      *
+     * @param  decoder     the netCDF file where this variable is stored.
      * @param  input       the channel together with a buffer for reading the 
variable data.
      * @param  name        the variable name.
      * @param  dimensions  the dimensions of this variable.
@@ -198,20 +198,19 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
      * @param  dataType    the netCDF type of data, or {@code null} if unknown.
      * @param  size        the variable size. May be inaccurate and ignored.
      * @param  offset      the offset where the variable data begins in the 
netCDF file.
-     * @param  listeners   where to report warnings, if any.
      * @throws ArithmeticException if the variable size exceeds {@link 
Long#MAX_VALUE}.
      * @throws DataStoreContentException if a logical error is detected.
      */
-    VariableInfo(final ChannelDataInput      input,
-                 final String                name,
-                 final DimensionInfo[]       dimensions,
-                 final Map<String,Object>    attributes,
-                       DataType              dataType,
-                 final int                   size,
-                 final long                  offset,
-                 final WarningListeners<?>   listeners) throws 
DataStoreContentException
+    VariableInfo(final Decoder            decoder,
+                 final ChannelDataInput   input,
+                 final String             name,
+                 final DimensionInfo[]    dimensions,
+                 final Map<String,Object> attributes,
+                       DataType           dataType,
+                 final int                size,
+                 final long               offset) throws 
DataStoreContentException
     {
-        super(listeners);
+        super(decoder);
         this.name       = name;
         this.dimensions = dimensions;
         this.attributes = attributes;
@@ -232,7 +231,7 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
                     offsetToNextRecord = 
Math.multiplyExact(offsetToNextRecord, dim.length());
                 } else if (i != 0) {
                     // Unlimited dimension, if any, must be first in a netCDF 
3 classic format.
-                    throw new DataStoreContentException(listeners.getLocale(), 
Decoder.FORMAT_NAME, input.filename, null);
+                    throw new DataStoreContentException(getLocale(), 
Decoder.FORMAT_NAME, input.filename, null);
                 }
             }
             reader = new HyperRectangleReader(dataType.number, input, offset);
@@ -368,7 +367,11 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
      */
     @Override
     public String getFilename() {
-        return (reader != null) ? reader.filename() : null;
+        if (reader != null) {
+            final String filename = reader.filename();
+            if (filename != null) return filename;
+        }
+        return super.getFilename();
     }
 
     /**
@@ -483,12 +486,12 @@ final class VariableInfo extends Variable implements 
Comparable<VariableInfo> {
      * @see ChannelDecoder#getGrids()
      */
     @Override
-    protected Grid getGrid(final Decoder decoder) throws IOException, 
DataStoreException {
+    protected Grid getGrid() throws IOException, DataStoreException {
         if (grid == null && !gridDetermined) {
             gridDetermined = true;                            // Set first for 
avoiding other attempts in case of failure.
             decoder.getGrids();                               // Force 
calculation of grid geometries if not already done.
             if (grid == null) {                               // May have been 
computed as a side-effect of decoder.getGrids().
-                grid = (GridInfo) super.getGrid(decoder);     // Non-null if 
grid dimensions are different than this variable.
+                grid = (GridInfo) super.getGrid();            // Non-null if 
grid dimensions are different than this variable.
             }
         }
         return grid;
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 5dd644e..a6963ca 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
@@ -388,7 +388,7 @@ public final class DecoderWrapper extends Decoder 
implements CancelTask {
             final List<? extends VariableIF> all = file.getVariables();
             variables = new VariableWrapper[(all != null) ? all.size() : 0];
             for (int i=0; i<variables.length; i++) {
-                variables[i] = new VariableWrapper(listeners, all.get(i));
+                variables[i] = new VariableWrapper(this, all.get(i));
             }
         }
         return variables;
@@ -405,7 +405,7 @@ public final class DecoderWrapper extends Decoder 
implements CancelTask {
             }
         }
         // We should not reach this point, but let be safe.
-        return new VariableWrapper(listeners, variable);
+        return new VariableWrapper(this, variable);
     }
 
     /**
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 26d1220..e9eb3c0 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
@@ -97,7 +97,7 @@ final class GridWrapper extends Grid {
 
     /**
      * Returns a localization grid having the same dimensions than this grid 
but in a different order.
-     * This method is invoked by {@link VariableWrapper#getGrid(Decoder)} when 
the localization grids created
+     * This method is invoked by {@link VariableWrapper#getGrid()} when the 
localization grids created
      * by {@link Decoder} subclasses are not sufficient and must be tailored 
for a particular variable.
      * Returns {@code null} the the given dimensions are not members of this 
grid.
      */
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 6593a30..83b1e44 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
@@ -42,7 +42,6 @@ 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.MeasurementRange;
 import org.apache.sis.measure.NumberRange;
@@ -85,7 +84,7 @@ final class VariableWrapper extends Variable {
      * The grid needs to be computed if {@link #gridDetermined} is {@code 
false}.
      *
      * @see #gridDetermined
-     * @see #getGrid(Decoder)
+     * @see #getGrid()
      */
     private transient GridWrapper grid;
 
@@ -93,15 +92,15 @@ final class VariableWrapper extends Variable {
      * Whether {@link #grid} has been computed. Note that the result may still 
null.
      *
      * @see #grid
-     * @see #getGrid(Decoder)
+     * @see #getGrid()
      */
     private transient boolean gridDetermined;
 
     /**
      * Creates a new variable wrapping the given netCDF interface.
      */
-    VariableWrapper(final WarningListeners<?> listeners, VariableIF v) {
-        super(listeners);
+    VariableWrapper(final Decoder decoder, VariableIF v) {
+        super(decoder);
         variable = v;
         if (v instanceof VariableEnhanced) {
             v = ((VariableEnhanced) v).getOriginalVariable();
@@ -123,7 +122,7 @@ final class VariableWrapper extends Variable {
                 return name.substring(Math.max(name.lastIndexOf('/'), 
name.lastIndexOf(File.separatorChar)) + 1);
             }
         }
-        return null;
+        return super.getFilename();
     }
 
     /**
@@ -247,7 +246,7 @@ final class VariableWrapper extends Variable {
      * @see DecoderWrapper#getGrids()
      */
     @Override
-    protected Grid getGrid(final Decoder decoder) throws IOException, 
DataStoreException {
+    protected Grid getGrid() throws IOException, DataStoreException {
         if (!gridDetermined) {
             gridDetermined = true;                      // Set first so we 
don't try twice in case of failure.
             /*
@@ -273,7 +272,7 @@ final class VariableWrapper extends Variable {
              * can map to the variable dimension using attribute values. This 
mechanism is described
              * in Convention.nameOfDimension(…).
              */
-            grid = (GridWrapper) super.getGrid(decoder);
+            grid = (GridWrapper) super.getGrid();
         }
         return grid;
     }
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 d4b015f..611b534 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
@@ -24,7 +24,6 @@ import java.nio.file.Path;
 import java.nio.Buffer;
 import java.awt.image.DataBuffer;
 import org.opengis.util.GenericName;
-import org.opengis.util.InternationalString;
 import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.coverage.grid.GridGeometry;
@@ -166,7 +165,7 @@ final class GridResource extends AbstractGridResource 
implements ResourceOnFileS
             if (decoder.convention().roleOf(variable) != 
VariableRole.COVERAGE) {
                 continue;                                                   // 
Skip variables that are not grid coverages.
             }
-            final GridGeometry grid = variable.getGridGeometry(decoder);
+            final GridGeometry grid = variable.getGridGeometry();
             if (grid == null) {
                 continue;                                                   // 
Skip variables that are not grid coverages.
             }
@@ -198,7 +197,7 @@ final class GridResource extends AbstractGridResource 
implements ResourceOnFileS
                         final String cn = candidate.getStandardName();
                         if (cn.regionMatches(cn.length() - suffixLength, name, 
suffixStart, suffixLength) &&
                             cn.regionMatches(0, name, 0, prefixLength) && 
candidate.getDataType() == type &&
-                            grid.equals(candidate.getGridGeometry(decoder)))
+                            grid.equals(candidate.getGridGeometry()))
                         {
                             /*
                              * Found another variable with the same name 
except for the keyword. Verify that the
@@ -330,27 +329,33 @@ final class GridResource extends AbstractGridResource 
implements ResourceOnFileS
          */
         boolean setBackground = true;
         int ordinal = data.hasRealValues() ? 0 : -1;
-        final InternationalString[] names = new InternationalString[2];
-        for (final Map.Entry<Number,Integer> entry : 
data.getNodataValues().entrySet()) {
+        final CharSequence[] names = new CharSequence[2];
+        for (final Map.Entry<Number,Object> entry : 
data.getNodataValues().entrySet()) {
             final Number n;
             if (ordinal >= 0) {
                 n = MathFunctions.toNanFloat(ordinal++);        // Must be 
consistent with Variable.replaceNaN(Object).
             } else {
                 n = entry.getKey();                             // Should be 
real number, made unique by the HashMap.
             }
-            final int role = entry.getValue();          // Bit 0 set (value 1) 
= pad value, bit 1 set = missing value.
-            final int i = (role == 1) ? 1 : 0;          // i=1 if role is only 
pad value, i=0 otherwise.
-            InternationalString name = names[i];
-            if (name == null) {
-                name = Vocabulary.formatInternational(i == 0 ? 
Vocabulary.Keys.MissingValue : Vocabulary.Keys.FillValue);
-                names[i] = name;
-            }
-            if (setBackground & (role & 1) != 0) {
-                setBackground = false;                  // Declare only one 
fill value.
-                builder.setBackground(name, n);
+            CharSequence name;
+            final Object label = entry.getValue();
+            if (label instanceof Integer) {
+                final int role = (Integer) label;               // Bit 0 set 
(value 1) = pad value, bit 1 set = missing value.
+                final int i = (role == 1) ? 1 : 0;              // i=1 if role 
is only pad value, i=0 otherwise.
+                name = names[i];
+                if (name == null) {
+                    name = Vocabulary.formatInternational(i == 0 ? 
Vocabulary.Keys.MissingValue : Vocabulary.Keys.FillValue);
+                    names[i] = name;
+                }
+                if (setBackground & (role & 1) != 0) {
+                    setBackground = false;                      // Declare 
only one fill value.
+                    builder.setBackground(name, n);
+                    continue;
+                }
             } else {
-                builder.addQualitative(name, n, n);
+                name = (CharSequence) label;
             }
+            builder.addQualitative(name, n, n);
         }
         return builder.setName(data.getName()).build();
     }

Reply via email to