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 2019/02/21 12:04:33 UTC
[sis] 03/04: Merge branch 'feat/netcdf-attribute-names' of
https://github.com/alexismanin/sis into geoapi-4.0. Changes have been
applied regarding methods order, documentation,
and where the search path is set.
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 a972b833d92ed1675032770e5204575ae23a9ecc
Merge: f8a6001 bc1c422
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Feb 21 12:58:37 2019 +0100
Merge branch 'feat/netcdf-attribute-names' of https://github.com/alexismanin/sis into geoapi-4.0.
Changes have been applied regarding methods order, documentation, and where the search path is set.
.../org/apache/sis/internal/netcdf/Convention.java | 57 +++++++++++++++++++++-
.../org/apache/sis/internal/netcdf/Decoder.java | 4 +-
.../sis/internal/netcdf/impl/ChannelDecoder.java | 30 ++++++++++--
.../sis/internal/netcdf/ucar/DecoderWrapper.java | 17 ++++++-
.../apache/sis/storage/netcdf/MetadataReader.java | 15 ++----
5 files changed, 102 insertions(+), 21 deletions(-)
diff --cc storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java
index fc79692,ae501ef..01baef3
--- 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
@@@ -66,6 -69,6 +66,14 @@@ public class Convention
private static final Convention DEFAULT = new Convention();
/**
++ * Names of groups where to search for metadata, in precedence order.
++ * The {@code null} value stands for global attributes.
++ *
++ * <p>REMINDER: if modified, update {@link org.apache.sis.storage.netcdf.MetadataReader} class javadoc too.</p>
++ */
++ private static final String[] SEARCH_PATH = {"NCISOMetadata", "CFMetadata", null, "THREDDSMetadata"};
++
++ /**
* Names of attributes where to fetch minimum and maximum sample values, in preference order.
*
* @see #getValidValues(Variable)
@@@ -85,35 -96,66 +93,80 @@@
/**
* Finds the convention to apply to the file opened by the given decoder, or {@code null} if none.
++ * This method does not change the state of the given {@link Decoder}.
++ *
++ * @todo this method is temporarily synchronized because of a {@link java.util.ServiceLoader} bug in JDK 8,
++ * which does not support the use of a new {@link Iterator} while another iteration is in progress,
++ * even if they are in the same thread. We will remove this synchronization in JDK9 if that bug is fixed.
++ * Only the {@code synchronized (AVAILABLES)} statements should stay.
*/
- static Convention find(final Decoder decoder) {
+ static synchronized Convention find(final Decoder decoder) {
final Iterator<Convention> it;
Convention c;
synchronized (AVAILABLES) {
it = AVAILABLES.iterator();
- if (!it.hasNext()) return DEFAULT;
++ if (!it.hasNext()) {
++ return DEFAULT;
++ }
+ c = it.next();
}
-
- do {
++ /*
++ * We want the call to isApplicableTo(…) to be outside the synchronized block in order to avoid contentions.
++ * This is also a safety against dead locks if that method acquire other locks. Only Iterator methods should
++ * be invoked inside the synchronized block.
++ */
+ while (!c.isApplicableTo(decoder)) {
synchronized (AVAILABLES) {
- if (!it.hasNext()) return DEFAULT;
+ if (it.hasNext()) {
- c = it.next();
- } else {
- decoder.setSearchPath(DEFAULT.getSearchPath());
- return DEFAULT;
++ c = DEFAULT;
++ break;
+ }
+ c = it.next();
}
-
- decoder.setSearchPath(c.getSearchPath());
-
- } while (!c.isApplicableTo(decoder));
-
+ }
return c;
}
/**
- * Specify a list of groups to focus on when searching for attribute values.
+ * Detects if this set of conventions applies to the given netCDF file.
++ * This method shall not change the state of the given {@link Decoder}.
*
- * @return Groups we should search in for global data attributes. Never null, never empty, but can contain null
- * values to specify root as search path.
+ * @param decoder the netCDF file to test.
+ * @return {@code true} if this set of conventions can apply.
*/
- public final String[] getSearchPath() {
- String[] paths = getSearchPathImpl();
- if (paths == null || paths.length < 1) {
- return new String[1];
- }
-
- return Arrays.copyOf(paths, paths.length);
+ protected boolean isApplicableTo(final Decoder decoder) {
+ return false;
}
/**
- * An abstraction over {@link #getSearchPath() }, allowing subclasses to specify their own groups. The abstraction
- * is needed as a control mechanism to avoid invalid paths (null or empty).
- * @return Groups to look at for attribute values.
++ * Specifies a list of groups where to search for named attributes, in preference order.
++ * The {@code null} name stands for the root group.
++ *
++ * @return name of groups where to search in for global attributes, in preference order.
++ * Never null, never empty, but can contain null values to specify root as search path.
++ *
++ * @see Decoder#setSearchPath(String...)
+ */
- protected String[] getSearchPathImpl() {
- return SEARCH_PATH;
++ public String[] getSearchPath() {
++ return SEARCH_PATH.clone();
+ }
+
+ /**
- * Detects if this set of conventions applies to the given netCDF file.
++ * Returns the name of an attribute in this convention which is equivalent to the attribute of given name in CF-convention.
++ * The given parameter is a name from <cite>CF conventions</cite> or from <cite>Attribute Convention for Dataset Discovery
++ * (ACDD)</cite>. Some of those attribute names are listed in the {@link org.apache.sis.storage.netcdf.AttributeNames} class.
+ *
- * @param decoder the netCDF file to test.
- * @return {@code true} if this set of conventions can apply.
++ * <p>The default implementation returns {@code name} unchanged.</p>
++ *
++ * @param name an attribute name from CF or ACDD convention.
++ * @return the attribute name expected to be found in a netCDF file structured according this {@code Convention}.
++ * If this convention does not know about attribute of the given name, then {@code name} is returned unchanged.
+ */
- protected boolean isApplicableTo(final Decoder decoder) {
- return false;
++ public String mapAttributeName(final String name) {
++ return name;
+ }
+
+ /**
* Returns whether the given variable is used as a coordinate system axis, a coverage or something else.
* In particular this method shall return {@link VariableRole#AXIS} if the given variable seems to be a
* coordinate system axis instead than the actual data. By netCDF convention, coordinate system axes
diff --cc storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
index f2bb45e,f2bb45e..d4d0cc4
--- 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
@@@ -159,9 -159,9 +159,11 @@@ public abstract class Decoder extends R
/**
* Defines the groups where to search for named attributes, in preference order.
-- * The {@code null} group name stands for the global attributes.
++ * The {@code null} group name stands for attributes in the root group.
*
* @param groupNames the name of the group where to search, in preference order.
++ *
++ * @see Convention#getSearchPath()
*/
public abstract void setSearchPath(String... groupNames);
diff --cc storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
index f135d66,ac065f0..42f0d92
--- 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
@@@ -724,7 -725,7 +724,9 @@@ public final class ChannelDecoder exten
}
/**
-- * Returns the netCDF attribute of the given name, or {@code null} if none.
++ * Returns the netCDF attribute of the given name, or {@code null} if none. This method is invoked
++ * for every global attributes to be read by this class (but not {@linkplain VariableInfo variable}
++ * attributes), thus providing a single point where we can filter the attributes to be read.
* The {@code name} argument is typically (but is not restricted to) one of the constants
* defined in the {@link org.apache.sis.storage.netcdf.AttributeNames} class.
*
@@@ -736,12 -737,21 +738,30 @@@
private Object findAttribute(final String name) {
Object value = attributeMap.get(name);
if (value == null && name != null) {
-- final String lower = name.toLowerCase(NAME_LOCALE);
-- // Identity comparison is ok since following check is only an optimization for a common case.
-- if (lower != name) {
-- value = attributeMap.get(lower);
- }
- }
-
- // Check if a custom convention could be applied.
- if (value == null && convention() != null) {
- final String mappedName = convention().mapAttributeName(name);
- if (!Objects.equals(name, mappedName)) {
- value = findAttribute(mappedName);
++ /*
++ * If no value were found for the given name, tries the following alternatives:
++ *
++ * - Same name but in lower cases.
++ * - Alternative name specific to the non-standard convention used by current file.
++ * - Same alternative name but in lower cases.
++ *
++ * Identity comparisons performed between String instances below are okay since they
++ * are only optimizations for skipping calls to Map.get(Object) in common cases.
++ */
++ String lower = name.toLowerCase(NAME_LOCALE);
++ if (lower == name || (value = attributeMap.get(lower)) == null) {
++ final String mappedName = convention().mapAttributeName(name);
++ if (mappedName != name) {
++ value = attributeMap.get(mappedName);
++ if (value == null) {
++ lower = name.toLowerCase(NAME_LOCALE);
++ if (lower != mappedName) {
++ value = attributeMap.get(lower);
++ }
++ }
++ }
}
}
-
return value;
}
diff --cc storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
index f2b264d,6df5a66..5dd644e
--- 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
@@@ -224,7 -226,7 +224,7 @@@ public final class DecoderWrapper exten
* Returns the netCDF attribute of the given name in the given group, or {@code null} if none.
* This method is invoked for every global and group attributes to be read by this class (but
* not {@linkplain ucar.nc2.VariableSimpleIF variable} attributes), thus providing a single point
-- * where we can filter the attributes to be read - if we want to do that in a future version.
++ * where we can filter the attributes to be read.
*
* <p>The {@code name} argument is typically (but is not restricted too) one of the constants
* defined in the {@link org.apache.sis.storage.netcdf.AttributeNames} class.</p>
@@@ -234,7 -236,17 +234,20 @@@
* @return the attribute, or {@code null} if none.
*/
private Attribute findAttribute(final Group group, final String name) {
- return (group != null) ? group.findAttributeIgnoreCase(name) : file.findGlobalAttributeIgnoreCase(name);
- Attribute value = (group != null) ?
- group.findAttributeIgnoreCase(name) : file.findGlobalAttributeIgnoreCase(name);
-
- if (value == null && convention() != null) {
- String mappedName = convention().mapAttributeName(name);
- if (!Objects.equals(name, mappedName)) {
- value = findAttribute(group, mappedName);
++ Attribute value = (group != null) ? group.findAttributeIgnoreCase(name)
++ : file.findGlobalAttributeIgnoreCase(name);
++ if (value == null) {
++ final String mappedName = convention().mapAttributeName(name);
++ /*
++ * Identity check between String instances below is okay
++ * since this is only an optimization for a common case.
++ */
++ if (mappedName != name) {
++ value = (group != null) ? group.findAttributeIgnoreCase(mappedName)
++ : file.findGlobalAttributeIgnoreCase(mappedName);
+ }
+ }
-
+ return value;
}
/**
diff --cc storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
index bf3e41b,d835802..ca8f55a
--- 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
@@@ -110,6 -110,6 +110,7 @@@ import static org.apache.sis.internal.u
*
* @author Martin Desruisseaux (Geomatys)
* @author Thi Phuong Hao Nguyen (VNSC)
++ * @author Alexis Manin (Geomatys)
* @version 1.0
* @since 0.3
* @module
@@@ -159,8 -151,8 +152,8 @@@ final class MetadataReader extends Meta
private final Decoder decoder;
/**
-- * The actual search path, as a subset of {@link #SEARCH_PATH} with only the name of the groups
-- * which have been found in the NeCDF file.
++ * The actual search path, as a subset of {@link org.apache.sis.internal.netcdf.Convention#SEARCH_PATH}
++ * with only the name of the groups which have been found in the NeCDF file.
*/
private final String[] searchPath;
@@@ -194,7 -186,6 +187,7 @@@
*/
MetadataReader(final Decoder decoder) {
this.decoder = decoder;
- decoder.setSearchPath(SEARCH_PATH);
++ decoder.setSearchPath(decoder.convention().getSearchPath());
searchPath = decoder.getSearchPath();
}