sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1817597 [15/19] - in /sis/branches/ISO-19115-3: ./ application/ application/sis-console/ application/sis-console/src/main/artifact/ application/sis-console/src/main/artifact/lib/ application/sis-console/src/main/artifact/lib/darwin/ applic...
Date Sat, 09 Dec 2017 10:57:47 GMT
Modified: sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -31,6 +31,7 @@ import org.opengis.metadata.Metadata;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.*;
 import org.opengis.metadata.content.*;
+import org.opengis.metadata.acquisition.*;
 import org.opengis.metadata.distribution.Distributor;
 import org.opengis.metadata.distribution.Distribution;
 import org.opengis.metadata.constraint.LegalConstraints;
@@ -44,18 +45,20 @@ import org.opengis.metadata.identificati
 import org.opengis.metadata.identification.Keywords;
 import org.opengis.metadata.quality.DataQuality;
 import org.opengis.metadata.lineage.Lineage;
+import org.opengis.metadata.lineage.Source;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.metadata.extent.VerticalExtent;
 import org.opengis.metadata.extent.TemporalExtent;
+import org.opengis.metadata.extent.BoundingPolygon;
 import org.opengis.metadata.extent.GeographicBoundingBox;
 import org.opengis.metadata.extent.GeographicDescription;
 
 
 /**
- * Name of attributes used in the mapping from/to NetCDF metadata to ISO 19115 metadata.
+ * Name of attributes used in the mapping from/to netCDF metadata to ISO 19115 metadata.
  * The attributes recognized by SIS are listed below:
  *
- * <blockquote><table class="compact" summary="List of all NetCDF attributes.">
+ * <blockquote><table class="compact" summary="List of all netCDF attributes.">
  * <tr valign="top"><td style="width: 25%">
  * {@value     #ACCESS_CONSTRAINT}<br>
  * {@value     #ACKNOWLEDGEMENT}<br>
@@ -66,18 +69,23 @@ import org.opengis.metadata.extent.Geogr
  * {@linkplain #CONTRIBUTOR "contributor_url"}<br>
  * {@linkplain #CREATOR     "creator_email"}<br>
  * {@linkplain #CREATOR     "creator_name"}<br>
+ * {@linkplain #CREATOR     "creator_type"}<br>
  * {@linkplain #CREATOR     "creator_url"}<br>
  * {@value     #DATA_TYPE}<br>
  * {@value     #DATE_CREATED}<br>
  * {@value     #DATE_ISSUED}<br>
+ * {@value     #METADATA_MODIFIED}<br>
  * {@value     #DATE_MODIFIED}<br>
  * {@value     #FLAG_MASKS}<br>
  * {@value     #FLAG_MEANINGS}<br>
  * {@value     #FLAG_NAMES}<br>
  * {@value     #FLAG_VALUES}<br>
- * </td><td style="width: 25%">
  * {@linkplain #TITLE "full_name"}<br>
+ * </td><td style="width: 25%">
  * {@linkplain #GEOGRAPHIC_IDENTIFIER "geographic_identifier"}<br>
+ * {@value     #GEOSPATIAL_BOUNDS}<br>
+ * {@linkplain #GEOSPATIAL_BOUNDS "geospatial_bounds_crs"}<br>
+ * {@linkplain #GEOSPATIAL_BOUNDS "geospatial_bounds_vertical_crs"}<br>
  * {@linkplain #LATITUDE  "geospatial_lat_max"}<br>
  * {@linkplain #LATITUDE  "geospatial_lat_min"}<br>
  * {@linkplain #LATITUDE  "geospatial_lat_resolution"}<br>
@@ -91,27 +99,31 @@ import org.opengis.metadata.extent.Geogr
  * {@linkplain #VERTICAL  "geospatial_vertical_positive"}<br>
  * {@linkplain #VERTICAL  "geospatial_vertical_resolution"}<br>
  * {@linkplain #VERTICAL  "geospatial_vertical_units"}<br>
- * </td><td style="width: 25%">
  * {@value     #HISTORY}<br>
- * {@value     #IDENTIFIER}<br>
- * {@linkplain #CREATOR "institution"}<br>
- * {@value     #KEYWORDS}<br>
- * {@value     #VOCABULARY}<br>
+ * {@linkplain #IDENTIFIER "id"}<br>
+ * {@linkplain #CREATOR    "institution"}<br>
+ * </td><td style="width: 25%">
+ * {@linkplain #KEYWORDS "keywords"}<br>
+ * {@linkplain #KEYWORDS "keywords_vocabulary"}<br>
  * {@value     #LICENSE}<br>
  * {@value     #METADATA_CREATION}<br>
+ * {@value     #METADATA_LINK}<br>
  * {@linkplain #TITLE "name"}<br>
- * {@value     #NAMING_AUTHORITY}<br>
  * {@value     #PROCESSING_LEVEL}<br>
+ * {@value     #PRODUCT_VERSION}<br>
+ * {@linkplain #PROGRAM   "program"}<br>
  * {@value     #PROJECT}<br>
  * {@linkplain #PUBLISHER "publisher_email"}<br>
  * {@linkplain #PUBLISHER "publisher_name"}<br>
+ * {@linkplain #PUBLISHER "publisher_type"}<br>
  * {@linkplain #PUBLISHER "publisher_url"}<br>
  * {@value     #PURPOSE}<br>
  * {@value     #REFERENCES}<br>
- * </td><td style="width: 25%">
- * {@value     #STANDARD_NAME}<br>
- * {@value     #STANDARD_NAME_VOCABULARY}<br>
+ * {@value     #SOURCE}<br>
+ * {@linkplain #STANDARD_NAME "standard_name"}<br>
+ * {@linkplain #STANDARD_NAME "standard_name_vocabulary"}<br>
  * {@value     #SUMMARY}<br>
+ * </td><td style="width: 25%">
  * {@linkplain #TIME "time_coverage_duration"}<br>
  * {@linkplain #TIME "time_coverage_end"}<br>
  * {@linkplain #TIME "time_coverage_resolution"}<br>
@@ -162,27 +174,86 @@ public class AttributeNames {
     public static final String SUMMARY = ACDD.summary;
 
     /**
-     * The {@value} attribute name for an identifier (<em>Recommended</em>).
-     * The combination of the {@value #NAMING_AUTHORITY} and the {@value}
-     * should be a globally unique identifier for the dataset.
+     * Holds the attribute names describing a term together with a vocabulary (or naming authority).
+     * A term is a word or expression having a precise meaning in a domain identified by the vocabulary.
+     * In the following table, the header lists the constants defined in the {@link AttributeNames}
+     * class and the other cells give the values assigned in this class fields for those constants.
      *
-     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
-     * {@link Metadata#getFileIdentifier() fileIdentifier}</li>
-     * <li>{@link Metadata} /
-     * {@link Metadata#getIdentificationInfo() identificationInfo} /
-     * {@link DataIdentification#getCitation() citation} /
-     * {@link Citation#getIdentifiers() identifier} /
-     * {@link Identifier#getCode() code}</li></ul>
+     * <table class="sis">
+     * <caption>Names of netCDF attributes describing a keyword</caption>
+     * <tr><th>{@link AttributeNames}</th>                             <th>{@link #TEXT}</th>           <th>{@link #VOCABULARY}</th></tr>
+     * <tr><td>{@link AttributeNames#IDENTIFIER    IDENTIFIER}</td>    <td>{@code "id"}</td>            <td>{@code "naming_authority"}</td></tr>
+     * <tr><td>{@link AttributeNames#STANDARD_NAME STANDARD_NAME}</td> <td>{@code "standard_name"}</td> <td>{@code "standard_name_vocabulary"}</td></tr>
+     * <tr><td>{@link AttributeNames#KEYWORDS      KEYWORDS}</td>      <td>{@code "keywords"}</td>      <td>{@code "keywords_vocabulary"}</td></tr>
+     * <tr><td>{@link AttributeNames#PROGRAM       PROGRAM}</td>       <td>{@code "program"}</td>       <td></td></tr>
+     * <tr><td>{@link AttributeNames#PLATFORM      PLATFORM}</td>      <td>{@code "platform"}</td>      <td>{@code "platform_vocabulary"}</td></tr>
+     * <tr><td>{@link AttributeNames#INSTRUMENT    INSTRUMENT}</td>    <td>{@code "instrument"}</td>    <td>{@code "instrument_vocabulary"}</td></tr>
+     * </table>
      *
-     * @see NetcdfFile#getId()
-     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#id">ESIP reference</a>
+     * <div class="note"><b>Note:</b>
+     * The member names in this class are upper-cases because they should be considered as constants.
+     * For example {@code AttributeNames.KEYWORD.TEXT} maps exactly to the {@code "keywords"} string
+     * and nothing else. A lower-case {@code text} member name could be misleading since it would
+     * suggest that the field contains the actual text value rather than the key by which the value
+     * is identified in a netCDF file.</div>
+     *
+     * @author  Martin Desruisseaux (Geomatys)
+     * @version 0.8
+     * @since   0.8
+     * @module
      */
-    public static final String IDENTIFIER = ACDD.id;
+    public static class Term implements Serializable {
+        /**
+         * For cross-version compatibility.
+         */
+        private static final long serialVersionUID = 2625777878209548741L;
+
+        /**
+         * The keyword or the identifier code. Possible values for this field are
+         * {@code "id"}, {@code "standard_name"}, {@code "keywords"}, {@code "program"},
+         * {@code "platform"} or {@code "instrument"}.
+         *
+         * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+         * {@link Metadata#getIdentificationInfo() identificationInfo} /
+         * {@link DataIdentification#getDescriptiveKeywords() descriptiveKeywords} /
+         * {@link Keywords#getKeywords() keyword}</li>
+         * <li>or {@link Identifier} / {@link Identifier#getCode() code}</li></ul>
+         */
+        public final String TEXT;
+
+        /**
+         * The vocabulary or identifier namespace, or {@code null} if none. Possible values for this field are
+         * {@code "naming_authority"}, {@code "standard_name_vocabulary"}, {@code "keywords_vocabulary"},
+         * {@code "platform_vocabulary"} or {@code "instrument_vocabulary"}.
+         *
+         * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+         * {@link Metadata#getIdentificationInfo() identificationInfo} /
+         * {@link DataIdentification#getDescriptiveKeywords() descriptiveKeywords} /
+         * {@link Keywords#getThesaurusName() thesaurusName} /
+         * {@link Citation#getTitle() title}</li>
+         * <li>or {@link Identifier} / {@link Identifier#getAuthority() authority} /
+         * {@link Citation#getTitle() title}</li></ul>
+         */
+        public final String VOCABULARY;
+
+        /**
+         * Creates a new set of attribute names. Any argument can be {@code null} if not applicable.
+         *
+         * @param text        the keyword or the identifier code.
+         * @param vocabulary  the vocabulary or identifier namespace.
+         *
+         * @since 0.8
+         */
+        public Term(final String text, final String vocabulary) {
+            TEXT       = text;
+            VOCABULARY = vocabulary;
+        }
+    }
 
     /**
-     * The {@value} attribute name for the identifier authority (<em>Recommended</em>).
-     * The combination of the {@value} and the {@value #IDENTIFIER} should be a globally
-     * unique identifier for the dataset.
+     * The set of attribute names for an identifier (<em>Recommended</em>).
+     * The combination of the {@code "naming_authority"} and the {@code "id"}
+     * should be a globally unique identifier for the dataset.
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
      * {@link Metadata#getFileIdentifier() fileIdentifier}</li>
@@ -190,75 +261,57 @@ public class AttributeNames {
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
      * {@link DataIdentification#getCitation() citation} /
      * {@link Citation#getIdentifiers() identifier} /
-     * {@link Identifier#getAuthority() authority}</li></ul>
+     * {@link Identifier#getCode() code}</li>
+     * <li>{@link Metadata} /
+     * {@link Metadata#getIdentificationInfo() identificationInfo} /
+     * {@link DataIdentification#getCitation() citation} /
+     * {@link Citation#getIdentifiers() identifier} /
+     * {@link Identifier#getAuthority() authority} /
+     * {@link Citation#getTitle() title}</li></ul>
      *
-     * @see #IDENTIFIER
-     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#naming_authority">ESIP reference</a>
+     * @see NetcdfFile#getId()
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#id">ESIP reference</a>
      */
-    public static final String NAMING_AUTHORITY = ACDD.naming_authority;
+    public static final Term IDENTIFIER = new Term(ACDD.id, ACDD.naming_authority);
 
     /**
-     * The {@value} attribute name for a long descriptive name for the variable taken from a controlled
+     * The set of attribute names for a long descriptive name for the variable taken from a controlled
      * vocabulary of variable names. This is actually a {@linkplain VariableSimpleIF variable} attribute,
      * but sometime appears also in {@linkplain NetcdfFile#findGlobalAttribute(String) global attributes}.
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
      * {@link DataIdentification#getDescriptiveKeywords() descriptiveKeywords} /
-     * {@link Keywords#getKeywords() keyword} with {@link KeywordType#THEME}</li></ul>
-     *
-     * @see #STANDARD_NAME_VOCABULARY
-     * @see #KEYWORDS
-     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#standard_name">ESIP reference</a>
-     */
-    public static final String STANDARD_NAME = CF.STANDARD_NAME;
-
-    /**
-     * The {@value} attribute name for indicating which controlled list of variable names has been
-     * used in the {@value #STANDARD_NAME} attribute.
-     *
-     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Keywords#getKeywords() keyword} with {@link KeywordType#THEME}</li>
+     * <li>{@link Metadata} /
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
      * {@link DataIdentification#getDescriptiveKeywords() descriptiveKeywords} /
      * {@link Keywords#getThesaurusName() thesaurusName} /
      * {@link Citation#getTitle() title}</li></ul>
      *
-     * @see #STANDARD_NAME
-     * @see #VOCABULARY
-     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#standard_name_vocabulary">ESIP reference</a>
+     * @see #KEYWORDS
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#standard_name">ESIP reference</a>
      */
-    public static final String STANDARD_NAME_VOCABULARY = ACDD.standard_name_vocabulary;
+    public static final Term STANDARD_NAME = new Term(CF.STANDARD_NAME, ACDD.standard_name_vocabulary);
 
     /**
-     * The {@value} attribute name for a comma separated list of key words and phrases
+     * The set of attribute names for a comma separated list of key words and phrases
      * (<em>Highly Recommended</em>).
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
      * {@link DataIdentification#getDescriptiveKeywords() descriptiveKeywords} /
-     * {@link Keywords#getKeywords() keyword} with {@link KeywordType#THEME}</li></ul>
-     *
-     * @see #VOCABULARY
-     * @see #STANDARD_NAME
-     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#keywords">ESIP reference</a>
-     */
-    public static final String KEYWORDS = ACDD.keywords;
-
-    /**
-     * The {@value} attribute name for the guideline for the words/phrases in the
-     * {@value #KEYWORDS} attribute (<em>Recommended</em>).
-     *
-     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Keywords#getKeywords() keyword} with {@link KeywordType#THEME}</li>
+     * <li>{@link Metadata} /
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
      * {@link DataIdentification#getDescriptiveKeywords() descriptiveKeywords} /
      * {@link Keywords#getThesaurusName() thesaurusName} /
      * {@link Citation#getTitle() title}</li></ul>
      *
-     * @see #KEYWORDS
-     * @see #STANDARD_NAME_VOCABULARY
-     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#keywords_vocabulary">ESIP reference</a>
+     * @see #STANDARD_NAME
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#keywords">ESIP reference</a>
      */
-    public static final String VOCABULARY = ACDD.keywords_vocabulary;
+    public static final Term KEYWORDS = new Term(ACDD.keywords, ACDD.keywords_vocabulary);
 
     /**
      * The {@value} attribute name for a high-level geographic data thematic classification.
@@ -296,6 +349,7 @@ public class AttributeNames {
     /**
      * The {@value} attribute name for providing an audit trail for modifications to the
      * original data (<em>Recommended</em>).
+     * This is a character array with a line for each invocation of a program that has modified the dataset.
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
      * {@link Metadata#getDataQualityInfo() dataQualityInfo} /
@@ -307,6 +361,21 @@ public class AttributeNames {
     public static final String HISTORY = ACDD.history;
 
     /**
+     * The {@value} attribute name for the method of production of the original data (<em>Recommended</em>).
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getDataQualityInfo() dataQualityInfo} /
+     * {@link DataQuality#getLineage() lineage} /
+     * {@link Lineage#getSources() source} /
+     * {@link Source#getDescription() description}</li></ul>
+     *
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#source">ESIP reference</a>
+     *
+     * @since 0.8
+     */
+    public static final String SOURCE = "source";
+
+    /**
      * The {@value} attribute name for miscellaneous information about the data
      * (<em>Recommended</em>).
      *
@@ -324,11 +393,24 @@ public class AttributeNames {
      * subgroup.
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
-     * {@link Metadata#getDateStamp() dateStamp}</li></ul>
+     * {@link Metadata#getDateInfo() dateInfo}
+     * {@link CitationDate#getDate() date} with {@link DateType#CREATION}</li></ul>
      */
     public static final String METADATA_CREATION = "metadata_creation";
 
     /**
+     * The {@value} attribute name for the date on which the metadata has been modified
+     * (<em>Suggested</em>).
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getDateInfo() dateInfo}
+     * {@link CitationDate#getDate() date} with {@link DateType#REVISION}</li></ul>
+     *
+     * @since 0.8
+     */
+    public static final String METADATA_MODIFIED = "date_metadata_modified";
+
+    /**
      * The {@value} attribute name for the date on which the data was created
      * (<em>Recommended</em>).
      *
@@ -371,12 +453,86 @@ public class AttributeNames {
     public static final String DATE_ISSUED = "date_issued";
 
     /**
+     * The {@value} attribute for version identifier of the data file or product as assigned by the data creator
+     * (<em>Suggested</em>).
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getIdentificationInfo() identificationInfo} /
+     * {@link DataIdentification#getCitation() citation} /
+     * {@link Citation#getEdition() edition}</li></ul>
+     *
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#product_version">ESIP reference</a>
+     */
+    public static final String PRODUCT_VERSION = "product_version";
+
+    /**
+     * The set of attribute names for the overarching program(s) of which the dataset is a part (<em>Suggested</em>).
+     * Examples: "GHRSST", "NOAA CDR", "NASA EOS", "JPSS", "GOES-R".
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getAcquisitionInformation() acquisitionInformation} /
+     * {@link AcquisitionInformation#getOperations() operation} /
+     * {@link Operation#getIdentifier() identifier} /
+     * {@link Identifier#getCode() code}</li></ul>
+     *
+     * <p><b>This attribute is not yet read by {@link NetcdfStore}</b>,
+     * because we are not sure what would be the most appropriate ISO 19115 location.
+     * The above-cited location is experimental and may change in any future Apache SIS version.</p>
+     *
+     * @see #PROJECT
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#program">ESIP reference</a>
+     *
+     * @since 0.8
+     */
+    public static final Term PROGRAM = new Term("program", null);
+
+    /**
+     * The set of attribute names for the platform(s) that supported the sensors used to create the resource(s).
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getAcquisitionInformation() acquisitionInformation} /
+     * {@link AcquisitionInformation#getPlatforms() platform} /
+     * {@link Platform#getIdentifier() identifier} /
+     * {@link Identifier#getCode() code}</li>
+     * <li>{@link Metadata} /
+     * {@link Metadata#getAcquisitionInformation() acquisitionInformation} /
+     * {@link AcquisitionInformation#getPlatforms() platform} /
+     * {@link Platform#getIdentifier() identifier} /
+     * {@link Identifier#getAuthority() authority} /
+     * {@link Citation#getTitle() title}</li></ul>
+     *
+     * @since 0.8
+     */
+    public static final Term PLATFORM = new Term("platform", "platform_vocabulary");
+
+    /**
+     * The set of attribute names for the contributing instrument(s) or sensor(s) used to create the resource(s).
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getAcquisitionInformation() acquisitionInformation} /
+     * {@link AcquisitionInformation#getPlatforms() platform} /
+     * {@link Platform#getInstruments() instrument} /
+     * {@link Instrument#getIdentifier() identifier} /
+     * {@link Identifier#getCode() code}</li>
+     * <li>{@link Metadata} /
+     * {@link Metadata#getAcquisitionInformation() acquisitionInformation} /
+     * {@link AcquisitionInformation#getPlatforms() platform} /
+     * {@link Platform#getInstruments() instrument} /
+     * {@link Instrument#getIdentifier() identifier} /
+     * {@link Identifier#getAuthority() authority} /
+     * {@link Citation#getTitle() title}</li></ul>
+     *
+     * @since 0.8
+     */
+    public static final Term INSTRUMENT = new Term("instrument", "instrument_vocabulary");
+
+    /**
      * Holds the attribute names describing a responsible party.
      * In the following table, the header lists the constants defined in the {@link AttributeNames}
      * class and the other cells give the values assigned in this class fields for those constants.
      *
      * <table class="sis">
-     * <caption>Names of NetCDF attributes describing a responsible party</caption>
+     * <caption>Names of netCDF attributes describing a responsible party</caption>
      * <tr>
      *   <th            >Field in this class</th>
      *   <th class="sep">{@link AttributeNames#CREATOR     CREATOR}</th>
@@ -388,10 +544,15 @@ public class AttributeNames {
      *   <td            >{@code "contributor_name"}</td>
      *   <td            >{@code "publisher_name"}</td>
      * </tr><tr>
-     *   <td            >{@link #INSTITUTION}</td>
-     *   <td class="sep">{@code "institution"}</td>
+     *   <td            >{@link #TYPE}</td>
+     *   <td class="sep">{@code "creator_type"}</td>
      *   <td            ></td>
+     *   <td            >{@code "publisher_type"}</td>
+     * </tr><tr>
+     *   <td            >{@link #INSTITUTION}</td>
+     *   <td class="sep">{@code "creator_institution"}</td>
      *   <td            ></td>
+     *   <td            >{@code "publisher_institution"}</td>
      * </tr><tr>
      *   <td            >{@link #URL}</td>
      *   <td class="sep">{@code "creator_url"}</td>
@@ -419,10 +580,10 @@ public class AttributeNames {
      * For example {@code AttributeNames.CREATOR.EMAIL} maps exactly to the {@code "creator_email"} string
      * and nothing else. A lower-case {@code email} member name could be misleading since it would suggest
      * that the field contains the actual name value rather than the key by which the value is identified
-     * in a NetCDF file.</div>
+     * in a netCDF file.</div>
      *
      * @author  Martin Desruisseaux (Geomatys)
-     * @version 0.3
+     * @version 0.8
      *
      * @see org.apache.sis.storage.netcdf.AttributeNames.Dimension
      *
@@ -436,7 +597,7 @@ public class AttributeNames {
         private static final long serialVersionUID = 2680152633273321012L;
 
         /**
-         * The attribute name for the responsible's name. Possible values are
+         * The attribute name for the responsible's name. Possible values for this field are
          * {@code "creator_name"}, {@code "contributor_name"} or {@code "publisher_name"}.
          *
          * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link ResponsibleParty} /
@@ -445,6 +606,13 @@ public class AttributeNames {
         public final String NAME;
 
         /**
+         * The attribute name for the responsible's type. Possible values for this field are
+         * {@code "creator_type"} or {@code "publisher_type"}. Possible values in a netCDF file
+         * are {@code "person"}, {@code "group"}, {@code "institution"} or {@code "position"}.
+         */
+        public final String TYPE;
+
+        /**
          * The attribute name for the responsible's institution, or {@code null} if none.
          * Possible value is {@code "institution"}.
          *
@@ -495,16 +663,20 @@ public class AttributeNames {
          * Creates a new set of attribute names. Any argument can be {@code null} if not applicable.
          *
          * @param name         the attribute name for the responsible's name.
+         * @param type         the attribute name for the responsible party type.
          * @param institution  the attribute name for the responsible's institution.
          * @param url          the attribute name for the responsible's URL.
          * @param email        the attribute name for the responsible's email address.
-         * @param role         the attribute name for the responsible's role.
+         * @param role         the attribute name for the responsible party role.
          * @param defaultRole  the role to use as a fallback if no attribute value is associated to the {@code role} key.
+         *
+         * @since 0.8
          */
-        public Responsible(final String name, final String institution, final String url, final String email,
-                final String role, final Role defaultRole)
+        public Responsible(final String name, final String type, final String institution, final String url,
+                final String email, final String role, final Role defaultRole)
         {
             NAME         = name;
+            TYPE         = type;
             INSTITUTION  = institution;
             URL          = url;
             EMAIL        = email;
@@ -524,8 +696,8 @@ public class AttributeNames {
      * @see #PUBLISHER
      * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#creator_name">ESIP reference</a>
      */
-    public static final Responsible CREATOR = new Responsible(ACDD.creator_name,
-            "institution", ACDD.creator_url, ACDD.creator_email, null, Role.ORIGINATOR);
+    public static final Responsible CREATOR = new Responsible(ACDD.creator_name, "creator_type",
+            "creator_institution", ACDD.creator_url, ACDD.creator_email, null, Role.ORIGINATOR);
 
     /**
      * The set of attribute names for the contributor (<em>Suggested</em>).
@@ -538,7 +710,7 @@ public class AttributeNames {
      * @see #PUBLISHER
      * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#contributor_name">ESIP reference</a>
      */
-    public static final Responsible CONTRIBUTOR = new Responsible("contributor_name",
+    public static final Responsible CONTRIBUTOR = new Responsible("contributor_name", null,
             null, "contributor_url", "contributor_email", "contributor_role", null);
 
     /**
@@ -557,8 +729,8 @@ public class AttributeNames {
      * @see #CONTRIBUTOR
      * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#publisher_name">ESIP reference</a>
      */
-    public static final Responsible PUBLISHER = new Responsible(ACDD.publisher_name,
-            null, ACDD.publisher_url, ACDD.publisher_email, null, Role.PUBLISHER);
+    public static final Responsible PUBLISHER = new Responsible(ACDD.publisher_name, "publisher_type",
+            ACDD.publisher_institution, ACDD.publisher_url, ACDD.publisher_email, null, Role.PUBLISHER);
 
     /**
      * The {@value} attribute name for the scientific project that produced the data
@@ -569,6 +741,7 @@ public class AttributeNames {
      * {@link DataIdentification#getDescriptiveKeywords() descriptiveKeywords} /
      * {@link Keywords#getKeywords() keyword} with the {@code "project"} {@link KeywordType}</li></ul>
      *
+     * @see #PROGRAM
      * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#project">ESIP reference</a>
      */
     public static final String PROJECT = "project";
@@ -620,11 +793,6 @@ public class AttributeNames {
     public static final String ACKNOWLEDGEMENT = ACDD.acknowledgement;
 
     /**
-     * @deprecated Renamed {@link #ACKNOWLEDGEMENT}.
-     */
-    public static final String ACKNOWLEDGMENT = "acknowledgment";
-
-    /**
      * The {@value} attribute name for a description of the restrictions to data access
      * and distribution (<em>Recommended</em>).
      *
@@ -664,12 +832,29 @@ public class AttributeNames {
     public static final String GEOGRAPHIC_IDENTIFIER = "geographic_identifier";
 
     /**
+     * Data's 2D or 3D geospatial extent in OGC's Well-Known Text (WKT) geometry format.
+     * The Coordinate Reference System is given by {@code "geospatial_bounds_crs"},
+     * possibly completed by {@code "geospatial_bounds_vertical_crs"}.
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getIdentificationInfo() identificationInfo} /
+     * {@link DataIdentification#getExtents() extent} /
+     * {@link Extent#getGeographicElements() geographicElement} /
+     * {@link BoundingPolygon#getPolygons() polygon}</li></ul>
+     *
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#geospatial_bounds">ESIP reference</a>
+     *
+     * @since 0.8
+     */
+    public static final String GEOSPATIAL_BOUNDS = "geospatial_bounds";
+
+    /**
      * Holds the attribute names describing a simple latitude, longitude, and vertical bounding box.
      * In the following table, the header lists the constants defined in the {@link AttributeNames}
      * class and the other cells give the values assigned in this class fields for those constants.
      *
      * <table class="sis">
-     * <caption>Names of NetCDF attributes describing an extent</caption>
+     * <caption>Names of netCDF attributes describing an extent</caption>
      * <tr>
      *   <th            >Field in this class</th>
      *   <th class="sep">{@link AttributeNames#LATITUDE  LATITUDE}</th>
@@ -724,8 +909,8 @@ public class AttributeNames {
      * The member names in this class are upper-cases because they should be considered as constants.
      * For example {@code AttributeNames.LATITUDE.MINIMUM} maps exactly to the {@code "geospatial_lat_min"}
      * string and nothing else. A lower-case {@code minimum} member name could be misleading since it would
-     * suggest that the field contains the actual name value rather than the key by which the value is
-     * identified in a NetCDF file.</div>
+     * suggest that the field contains the actual latitude value rather than the key by which the value is
+     * identified in a netCDF file.</div>
      *
      * @author  Martin Desruisseaux (Geomatys)
      * @version 0.3
@@ -785,12 +970,12 @@ public class AttributeNames {
         /**
          * The default ISO-19115 dimension name type, or {@code null} if none.
          * By default, {@link DimensionNameType#COLUMN} is associated to longitudes and {@link DimensionNameType#ROW}
-         * to latitudes since geographic maps in NetCDF files are typically shown horizontally.
+         * to latitudes since geographic maps in netCDF files are typically shown horizontally.
          *
          * <p>The default associations may not be always correct since the columns and rows can be anything.
          * Strictly speaking, the dimension name types shall be associated to the <em>grid axes</em> rather
          * than the <em>coordinate system axes</em>. However the default association is correct in the common case
-         * (for NetCDF files) where there is no axis swapping in the <cite>grid to CRS</cite> conversion.</p>
+         * (for netCDF files) where there is no axis swapping in the <cite>grid to CRS</cite> conversion.</p>
          */
         public final DimensionNameType DEFAULT_NAME_TYPE;
 
@@ -806,7 +991,7 @@ public class AttributeNames {
          * @param positive    the attribute name for indicating which direction is positive.
          */
         public Dimension(final DimensionNameType type, final String min, final String max, final String span,
-                final String resolution,final String units, final String positive)
+                final String resolution, final String units, final String positive)
         {
             DEFAULT_NAME_TYPE = type;
             MINIMUM           = min;
@@ -962,6 +1147,20 @@ public class AttributeNames {
     public static final String FLAG_MEANINGS = "flag_meanings";
 
     /**
+     * The {@value} attribute name for a URL that gives the location of more complete metadata.
+     * For example it may be the URL to an ISO 19115 metadata in XML format.
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getMetadataLinkages() metadataLinkage} /
+     * {@link OnlineResource#getLinkage() linkage}</li></ul>
+     *
+     * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#metadata_link">ESIP reference</a>
+     *
+     * @since 0.8
+     */
+    public static final String METADATA_LINK = "metadata_link";
+
+    /**
      * For subclass constructors only. {@code AttributeNames} may be sub-classed by communities
      * defining domain-specific attributes in addition to the ones defined by the CF convention.
      */

Modified: sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -53,13 +53,16 @@ import org.apache.sis.storage.DataStoreE
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.metadata.iso.citation.*;
 import org.apache.sis.metadata.iso.identification.*;
+import org.apache.sis.metadata.iso.lineage.DefaultSource;
 import org.apache.sis.metadata.iso.lineage.DefaultLineage;
 import org.apache.sis.metadata.iso.quality.DefaultDataQuality;
 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.GridGeometry;
+import org.apache.sis.internal.storage.io.IOUtilities;
 import org.apache.sis.internal.storage.MetadataBuilder;
+import org.apache.sis.internal.storage.wkt.StoreFormat;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.util.resources.Errors;
@@ -68,6 +71,7 @@ import org.apache.sis.measure.Units;
 
 // The following dependency is used only for static final String constants.
 // Consequently the compiled class files should not have this dependency.
+import ucar.nc2.constants.ACDD;
 import ucar.nc2.constants.CDM;
 import ucar.nc2.constants.CF;
 
@@ -77,7 +81,7 @@ import static org.apache.sis.internal.ut
 
 
 /**
- * Mapping from NetCDF metadata to ISO 19115-2 metadata. The {@link String} constants declared in
+ * Mapping from netCDF metadata to ISO 19115-2 metadata. The {@link String} constants declared in
  * the {@linkplain AttributeNames parent class} are the name of attributes examined by this class.
  * The current implementation searches the attribute values in the following places, in that order:
  *
@@ -108,6 +112,12 @@ import static org.apache.sis.internal.ut
  */
 final class MetadataReader extends MetadataBuilder {
     /**
+     * Whether the reader should include experimental fields.
+     * They are fields for which we are unsure of the proper ISO 19115 location.
+     */
+    private static final boolean EXPERIMENTAL = true;
+
+    /**
      * Names of groups where to search for metadata, in precedence order.
      * The {@code null} value stands for global attributes.
      *
@@ -122,7 +132,7 @@ final class MetadataReader extends Metad
 
     /**
      * The character to use as a separator in comma-separated list. This separator is used for parsing the
-     * {@value org.apache.sis.storage.netcdf.AttributeNames#KEYWORDS} attribute value for instance.
+     * {@link AttributeNames#KEYWORDS} attribute value for instance.
      */
     private static final char SEPARATOR = ',';
 
@@ -143,7 +153,7 @@ final class MetadataReader extends Metad
     private static final VerticalCRS VERTICAL_CRS = null;
 
     /**
-     * The source of NetCDF attributes from which to infer ISO metadata.
+     * The source of netCDF attributes from which to infer ISO metadata.
      * This source is set at construction time.
      *
      * <p>This {@code MetadataReader} class does <strong>not</strong> close this source.
@@ -167,7 +177,7 @@ final class MetadataReader extends Metad
      * more than once.
      *
      * <p>The point of contact is stored in the two following places. The semantic of those two
-     * contacts is not strictly identical, but the distinction is not used in NetCDF file:</p>
+     * contacts is not strictly identical, but the distinction is not used in netCDF file:</p>
      *
      * <ul>
      *   <li>{@link DefaultMetadata#getContacts()}</li>
@@ -180,9 +190,9 @@ final class MetadataReader extends Metad
     private transient Responsibility pointOfContact;
 
     /**
-     * Creates a new <cite>NetCDF to ISO</cite> mapper for the given source.
+     * Creates a new <cite>netCDF to ISO</cite> mapper for the given source.
      *
-     * @param  decoder  the source of NetCDF attributes.
+     * @param  decoder  the source of netCDF attributes.
      */
     MetadataReader(final Decoder decoder) {
         this.decoder = decoder;
@@ -327,22 +337,22 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
-     * Returns {@code true} if the given NetCDF attribute is either null or equals to the
+     * Returns {@code true} if the given netCDF attribute is either null or equals to the
      * string value of the given metadata value.
      *
      * @param metadata  The value stored in the metadata object.
-     * @param attribute The value parsed from the NetCDF file.
+     * @param attribute The value parsed from the netCDF file.
      */
     private static boolean canShare(final CharSequence metadata, final String attribute) {
         return (attribute == null) || (metadata != null && metadata.toString().equals(attribute));
     }
 
     /**
-     * Returns {@code true} if the given NetCDF attribute is either null or equals to one
+     * Returns {@code true} if the given netCDF attribute is either null or equals to one
      * of the values in the given collection.
      *
      * @param  metadata   the value stored in the metadata object.
-     * @param  attribute  the value parsed from the NetCDF file.
+     * @param  attribute  the value parsed from the netCDF file.
      */
     private static boolean canShare(final Collection<String> metadata, final String attribute) {
         return (attribute == null) || metadata.contains(attribute);
@@ -352,7 +362,7 @@ split:  while ((start = CharSequences.sk
      * Returns {@code true} if the given URL is null, or if the given resource contains that URL.
      *
      * @param  resource  the value stored in the metadata object.
-     * @param  url       the value parsed from the NetCDF file.
+     * @param  url       the value parsed from the netCDF file.
      */
     private static boolean canShare(final OnlineResource resource, final String url) {
         return (url == null) || (resource != null && canShare(resource.getLinkage().toString(), url));
@@ -362,31 +372,46 @@ split:  while ((start = CharSequences.sk
      * Returns {@code true} if the given email is null, or if the given address contains that email.
      *
      * @param  address  the value stored in the metadata object.
-     * @param  email    the value parsed from the NetCDF file.
+     * @param  email    the value parsed from the netCDF file.
      */
     private static boolean canShare(final Address address, final String email) {
         return (email == null) || (address != null && canShare(address.getElectronicMailAddresses(), email));
     }
 
     /**
+     * Creates a URI form the given path, or returns {@code null} if the given URL is null or can not be parsed.
+     * In the later case, a warning will be emitted.
+     */
+    private URI createURI(final String url) {
+        if (url != null) try {
+            return new URI(url);
+        } catch (URISyntaxException e) {
+            warning(e);
+        }
+        return null;
+    }
+
+    /**
      * Creates an {@code OnlineResource} element if the given URL is not null. Since ISO 19115
      * declares the URL as a mandatory attribute, this method will ignore all other attributes
      * if the given URL is null.
      *
-     * @param  url  the URL (mandatory - if {@code null}, no resource will be created).
+     * @param  url   the URL (mandatory - if {@code null}, no resource will be created).
      * @return the online resource, or {@code null} if the URL was null.
      */
     private OnlineResource createOnlineResource(final String url) {
-        if (url != null) try {
-            final DefaultOnlineResource resource = new DefaultOnlineResource(new URI(url));
-            resource.setProtocol("http");
+        final URI uri = createURI(url);
+        if (uri == null) {
+            return null;
+        }
+        final DefaultOnlineResource resource = new DefaultOnlineResource(uri);
+        final String protocol = uri.getScheme();
+        resource.setProtocol(protocol);
+        if ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) {
             resource.setApplicationProfile("web browser");
-            resource.setFunction(OnLineFunction.INFORMATION);
-            return resource;
-        } catch (URISyntaxException e) {
-            warning(e);
         }
-        return null;
+        resource.setFunction(OnLineFunction.INFORMATION);
+        return resource;
     }
 
     /**
@@ -422,8 +447,10 @@ split:  while ((start = CharSequences.sk
      * <p>Implementation note: this method tries to reuse the existing {@link #pointOfContact} instance,
      * or part of it, if it is suitable.</p>
      *
-     * @param  keys  the group of attribute names to use for fetching the values.
-     * @param  isPointOfContact {@code true} for forcing the role to {@link Role#POINT_OF_CONTACT}.
+     * @param  keys              the group of attribute names to use for fetching the values.
+     * @param  isPointOfContact  {@code true} if this responsible party is the "main" one. This will force the
+     *         role to {@link Role#POINT_OF_CONTACT} and enable the use of {@code "institution"} attribute as
+     *         a fallback if there is no value for {@link Responsible#INSTITUTION}.
      * @return the responsible party, or {@code null} if none.
      *
      * @see AttributeNames#CREATOR
@@ -431,13 +458,29 @@ split:  while ((start = CharSequences.sk
      * @see AttributeNames#PUBLISHER
      */
     private Responsibility createResponsibleParty(final Responsible keys, final boolean isPointOfContact) {
-        final String individualName   = stringValue(keys.NAME);
-        final String organisationName = stringValue(keys.INSTITUTION);
-        final String email            = stringValue(keys.EMAIL);
-        final String url              = stringValue(keys.URL);
+        String individualName   = stringValue(keys.NAME);
+        String organisationName = stringValue(keys.INSTITUTION);
+        final String email      = stringValue(keys.EMAIL);
+        final String url        = stringValue(keys.URL);
+        if (organisationName == null && isPointOfContact) {
+            organisationName = stringValue("institution");
+        }
         if (individualName == null && organisationName == null && email == null && url == null) {
             return null;
         }
+        /*
+         * The "individual" name may actually be an institution name, either because a "*_type" attribute
+         * said so or because the "individual" name is the same than the institution name. In such cases,
+         * reorganize the names in order to avoid duplication.
+         */
+        if (organisationName == null) {
+            if (isOrganisation(keys)) {
+                organisationName = individualName;
+                individualName = null;
+            }
+        } else if (organisationName.equalsIgnoreCase(individualName)) {
+            individualName = null;
+        }
         Role role = forCodeName(Role.class, stringValue(keys.ROLE));
         if (role == null) {
             role = isPointOfContact ? Role.POINT_OF_CONTACT : keys.DEFAULT_ROLE;
@@ -497,7 +540,7 @@ split:  while ((start = CharSequences.sk
                 AbstractParty party = null;
                 if (individualName   != null) party = new DefaultIndividual(individualName, null, null);
                 if (organisationName != null) party = new DefaultOrganisation(organisationName, null, (Individual) party, null);
-                if (party            == null) party = new AbstractParty(); // We don't know if this is an individual or an organisation.
+                if (party            == null) party = isOrganisation(keys) ? new DefaultOrganisation() : new DefaultIndividual();
                 if (contact          != null) party.setContactInfo(singleton(contact));
                 responsibility = new DefaultResponsibility(role, null, party);
             }
@@ -506,6 +549,16 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
+     * Returns {@code true} if the responsible party described by the given keys is an organization.
+     * In case of doubt, this method returns {@code false}. This is consistent with ACDD recommendation,
+     * which set the default value to {@code "person"}.
+     */
+    private boolean isOrganisation(final Responsible keys) {
+        final String type = stringValue(keys.TYPE);
+        return "institution".equalsIgnoreCase(type) || "group".equalsIgnoreCase(type);
+    }
+
+    /**
      * Adds a {@code DataIdentification/Citation} element if at least one of the required attributes is non-null.
      * This method will initialize the {@link #pointOfContact} field, than reuse it if non-null and suitable.
      *
@@ -526,8 +579,10 @@ split:  while ((start = CharSequences.sk
             }
         }
         addTitle(title);
+        addEdition(stringValue(PRODUCT_VERSION));
         addOtherCitationDetails(stringValue(REFERENCES));
         addCitationDate(decoder.dateValue(METADATA_CREATION), DateType.CREATION,    Scope.ALL);
+        addCitationDate(decoder.dateValue(METADATA_MODIFIED), DateType.REVISION,    Scope.ALL);
         addCitationDate(decoder.dateValue(DATE_CREATED),      DateType.CREATION,    Scope.RESOURCE);
         addCitationDate(decoder.dateValue(DATE_MODIFIED),     DateType.REVISION,    Scope.RESOURCE);
         addCitationDate(decoder.dateValue(DATE_ISSUED),       DateType.PUBLICATION, Scope.RESOURCE);
@@ -547,7 +602,7 @@ split:  while ((start = CharSequences.sk
             }
         }
         /*
-         * There is no distinction in NetCDF files between "point of contact" and "creator".
+         * There is no distinction in netCDF files between "point of contact" and "creator".
          * We take the first one as the data originator.
          */
         addCitedResponsibleParty(pointOfContact, Role.ORIGINATOR);
@@ -591,8 +646,8 @@ split:  while ((start = CharSequences.sk
         final Set<String> keywords = new LinkedHashSet<>();
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            keywords.addAll(split(stringValue(KEYWORDS)));
-            standard = addIfNonNull(standard, stringValue(STANDARD_NAME));
+            keywords.addAll(split(stringValue(KEYWORDS.TEXT)));
+            standard = addIfNonNull(standard, stringValue(STANDARD_NAME.TEXT));
             project  = addIfNonNull(project,  stringValue(PROJECT));
             for (final String keyword : split(stringValue(ACCESS_CONSTRAINT))) {
                 addAccessConstraint(forCodeName(Restriction.class, keyword));
@@ -601,7 +656,7 @@ split:  while ((start = CharSequences.sk
             addSpatialRepresentation(forCodeName(SpatialRepresentationType.class, stringValue(DATA_TYPE)));
             if (!hasExtent) {
                 /*
-                 * Takes only ONE extent, because a NetCDF file may declare many time the same
+                 * Takes only ONE extent, because a netCDF file may declare many time the same
                  * extent with different precision. The groups are ordered in such a way that
                  * the first extent should be the most accurate one.
                  */
@@ -618,17 +673,26 @@ split:  while ((start = CharSequences.sk
         addCredits                (stringValue(ACKNOWLEDGEMENT));
         addCredits                (stringValue("acknowledgment"));          // Legacy spelling.
         addUseLimitation          (stringValue(LICENSE));
-        addKeywords(standard,  KeywordType.THEME,       stringValue(STANDARD_NAME_VOCABULARY));
-        addKeywords(keywords,  KeywordType.THEME,       stringValue(VOCABULARY));
+        addKeywords(standard,  KeywordType.THEME,       stringValue(STANDARD_NAME.VOCABULARY));
+        addKeywords(keywords,  KeywordType.THEME,       stringValue(KEYWORDS.VOCABULARY));
         addKeywords(project,   KeywordType.PROJECT,     null);
         addKeywords(publisher, KeywordType.DATA_CENTRE, null);
+        /*
+         * Add geospatial bounds as a geometric object. This optional operation requires
+         * an external library (ESRI or JTS) to be present on the classpath.
+         */
+        final String wkt = stringValue(GEOSPATIAL_BOUNDS);
+        if (wkt != null) {
+            addBoundingPolygon(new StoreFormat(decoder.geomlib, decoder.listeners).parseGeometry(wkt,
+                    stringValue(GEOSPATIAL_BOUNDS + "_crs"), stringValue(GEOSPATIAL_BOUNDS + "_vertical_crs")));
+        }
     }
 
     /**
      * Adds information about axes and cell geometry.
      * This is the {@code <gmd:spatialRepresentationInfo>} element in XML.
      *
-     * @param  cs  the grid geometry (related to the NetCDF coordinate system).
+     * @param  cs  the grid geometry (related to the netCDF coordinate system).
      */
     private void addSpatialRepresentationInfo(final GridGeometry cs) throws IOException, DataStoreException {
         final Axis[] axes = cs.getAxes();
@@ -636,7 +700,7 @@ split:  while ((start = CharSequences.sk
             final int dim = axes.length - i;
             final Axis axis = axes[--i];
             /*
-             * Axes usually have exactly one dimension. However some NetCDF axes are backed by a two-dimensional
+             * Axes usually have exactly one dimension. However some netCDF axes are backed by a two-dimensional
              * conversion grid. In such case, our Axis constructor should have ensured that the first element in
              * the 'sourceDimensions' and 'sourceSizes' arrays are for the grid dimension which is most closely
              * oriented toward the axis direction.
@@ -657,7 +721,7 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
-     * Adds the extent declared in the given group. For more consistent results, the caller should restrict
+     * Adds the extent declared in the current group. For more consistent results, the caller should restrict
      * the {@linkplain Decoder#setSearchPath search path} to a single group before invoking this method.
      *
      * @return {@code true} if at least one numerical value has been added.
@@ -756,7 +820,34 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
-     * Adds information about all NetCDF variables. This is the {@code <gmd:contentInfo>} element in XML.
+     * Adds information about acquisition (program, platform).
+     */
+    private void addAcquisitionInfo() {
+        final Term[] attributes = {
+            AttributeNames.PROGRAM,
+            AttributeNames.PLATFORM,
+            AttributeNames.INSTRUMENT
+        };
+        for (int i=0; i<attributes.length; i++) {
+            final Term at = attributes[i];
+            final String authority = stringValue(at.VOCABULARY);
+            for (final String keyword : split(stringValue(at.TEXT))) {
+                switch (i) {
+                    case 0: {
+                        if (EXPERIMENTAL) {
+                            addAcquisitionOperation(authority, keyword);
+                        }
+                        break;
+                    }
+                    case 1: addPlatform  (authority, keyword); break;
+                    case 2: addInstrument(authority, keyword); break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds information about all netCDF variables. This is the {@code <gmd:contentInfo>} element in XML.
      * This method groups variables by their domains, i.e. variables having the same set of axes are grouped together.
      */
     private void addContentInfo() {
@@ -770,7 +861,7 @@ split:  while ((start = CharSequences.sk
         final String processingLevel = stringValue(PROCESSING_LEVEL);
         for (final List<Variable> group : contents.values()) {
             /*
-             * Instantiate a CoverageDescription for each distinct set of NetCDF dimensions
+             * Instantiate a CoverageDescription for each distinct set of netCDF dimensions
              * (e.g. longitude,latitude,time). This separation is based on the fact that a
              * coverage has only one domain for every range of values.
              */
@@ -798,7 +889,7 @@ split:  while ((start = CharSequences.sk
      * Adds metadata about a sample dimension (or band) from the given variable.
      * This is the {@code <gmd:dimension>} element in XML.
      *
-     * @param  variable  the NetCDF variable.
+     * @param  variable  the netCDF variable.
      */
     private void addSampleDimension(final Variable variable) {
         newSampleDimension();
@@ -811,11 +902,11 @@ split:  while ((start = CharSequences.sk
             setBandIdentifier(nameFactory.createMemberName(null, name,
                     nameFactory.createTypeName(null, variable.getDataTypeName())));
         }
-        Object[] v = variable.getAttributeValues(STANDARD_NAME, false);
+        Object[] v = variable.getAttributeValues(CF.STANDARD_NAME, false);
         final String id = (v.length == 1) ? trim((String) v[0]) : null;
         if (id != null && !id.equals(name)) {
-            v = variable.getAttributeValues(STANDARD_NAME_VOCABULARY, false);
-            addBandIdentifier(v.length == 1 ? (String) v[0] : null, id);
+            v = variable.getAttributeValues(ACDD.standard_name_vocabulary, false);
+            addBandName(v.length == 1 ? (String) v[0] : null, id);
         }
         final String description = trim(variable.getDescription());
         if (description != null && !description.equals(name) && !description.equals(id)) {
@@ -832,6 +923,7 @@ split:  while ((start = CharSequences.sk
         v = variable.getAttributeValues(CDM.SCALE_FACTOR, true); if (v.length == 1) scale  = ((Number) v[0]).doubleValue();
         v = variable.getAttributeValues(CDM.ADD_OFFSET,   true); if (v.length == 1) offset = ((Number) v[0]).doubleValue();
         setTransferFunction(scale, offset);
+        addContentType(forCodeName(CoverageContentType.class, stringValue(ACDD.coverage_content_type)));
     }
 
     /**
@@ -841,7 +933,7 @@ split:  while ((start = CharSequences.sk
      * <p><b>Note:</b> ISO 19115 range elements are approximatively equivalent to
      * {@code org.apache.sis.coverage.Category} in the {@code sis-coverage} module.</p>
      *
-     * @param  variable  the NetCDF variable.
+     * @param  variable  the netCDF variable.
      * @param  name      one of the elements in the {@link AttributeNames#FLAG_NAMES} attribute, or {@code null}.
      * @param  meaning   one of the elements in the {@link AttributeNames#FLAG_MEANINGS} attribute or {@code null}.
      * @param  mask      one of the elements in the {@link AttributeNames#FLAG_MASKS} attribute or {@code null}.
@@ -856,34 +948,47 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
-     * Adds a globally unique identifier for the current NetCDF {@linkplain #decoder}.
+     * Adds a globally unique identifier for the current netCDF {@linkplain #decoder}.
      * The current implementation builds the identifier from the following attributes:
      *
      * <ul>
-     *   <li>{@value AttributeNames#NAMING_AUTHORITY} used as the {@linkplain Identifier#getAuthority() authority}.</li>
-     *   <li>{@value AttributeNames#IDENTIFIER}, or {@link ucar.nc2.NetcdfFile#getId()} if no identifier attribute was found.</li>
+     *   <li>{@code AttributeNames.IDENTIFIER.VOCABULARY} used as the {@linkplain Identifier#getAuthority() authority}.</li>
+     *   <li>{@code AttributeNames.IDENTIFIER.TEXT}, or {@link ucar.nc2.NetcdfFile#getId()} if no identifier attribute was found,
+     *       or the filename without extension if {@code getId()} returned nothing.</li>
      * </ul>
+     *
+     * This method should be invoked last, after we made our best effort to set the title.
      */
     private void addFileIdentifier() {
-        String identifier = stringValue(IDENTIFIER);
-        if (identifier == null) {
+        String identifier = stringValue(IDENTIFIER.TEXT);
+        String authority;
+        if (identifier != null) {
+            authority = stringValue(IDENTIFIER.VOCABULARY);
+        } else {
             identifier = decoder.getId();
             if (identifier == null) {
-                return;
+                identifier = IOUtilities.filenameWithoutExtension(decoder.getFilename());
+                if (identifier == null) {
+                    return;
+                }
             }
+            authority = null;
+        }
+        if (authority == null) {
+            addTitleOrIdentifier(identifier, Scope.ALL);
+        } else {
+            addIdentifier(authority, identifier, Scope.ALL);
         }
-        addIdentifier(stringValue(NAMING_AUTHORITY), identifier, Scope.ALL);
     }
 
     /**
-     * Creates an ISO {@code Metadata} object from the information found in the NetCDF file.
+     * Creates an ISO {@code Metadata} object from the information found in the netCDF file.
      *
      * @return the ISO metadata object.
      * @throws IOException if an I/O operation was necessary but failed.
      * @throws DataStoreException if a logical error occurred.
      */
     public Metadata read() throws IOException, DataStoreException {
-        addFileIdentifier();
         addResourceScope(ScopeCode.DATASET, null);
         Set<InternationalString> publisher = addCitation();
         addIdentificationInfo(publisher);
@@ -893,10 +998,11 @@ split:  while ((start = CharSequences.sk
                 addResourceScope(ScopeCode.SERVICE, name);
             }
         }
+        addAcquisitionInfo();
         addContentInfo();
         /*
          * Add the dimension information, if any. This metadata node
-         * is built from the NetCDF CoordinateSystem objects.
+         * is built from the netCDF CoordinateSystem objects.
          */
         for (final GridGeometry cs : decoder.getGridGeometries()) {
             if (cs.getSourceDimensions() >= Variable.MIN_DIMENSION &&
@@ -905,6 +1011,7 @@ split:  while ((start = CharSequences.sk
                 addSpatialRepresentationInfo(cs);
             }
         }
+        addFileIdentifier();
         /*
          * Add history in Metadata.dataQualityInfo.lineage.statement as specified by UnidataDD2MI.xsl.
          * However Metadata.resourceLineage.statement could be a more appropriate place.
@@ -913,17 +1020,26 @@ split:  while ((start = CharSequences.sk
         final DefaultMetadata metadata = build(false);
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final String history = stringValue(HISTORY);
-            if (history != null) {
+            DefaultLineage lineage = null;
+            String value = stringValue(HISTORY);
+            if (value != null) {
+                lineage = new DefaultLineage();
+                lineage.setStatement(new SimpleInternationalString(value));
+            }
+            value = stringValue(SOURCE);
+            if (value != null) {
+                if (lineage == null) lineage = new DefaultLineage();
+                addIfAbsent(lineage.getSources(), new DefaultSource(value));
+            }
+            if (lineage != null) {
                 final DefaultDataQuality quality = new DefaultDataQuality(ScopeCode.DATASET);
-                final DefaultLineage lineage = new DefaultLineage();
-                lineage.setStatement(new SimpleInternationalString(history));
                 quality.setLineage(lineage);
                 addIfAbsent(metadata.getDataQualityInfo(), quality);
             }
         }
         decoder.setSearchPath(searchPath);
         metadata.setMetadataStandards(Citations.ISO_19115);
+        addCompleteMetadata(createURI(stringValue(METADATA_LINK)));
         return metadata;
     }
 }

Modified: sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -17,13 +17,20 @@
 package org.apache.sis.storage.netcdf;
 
 import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Collection;
 import org.opengis.metadata.Metadata;
+import org.opengis.parameter.ParameterValueGroup;
 import org.apache.sis.util.Debug;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.UnsupportedStorageException;
 import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.Aggregate;
 import org.apache.sis.internal.netcdf.Decoder;
+import org.apache.sis.internal.storage.URIDataStore;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.metadata.ModifiableMetadata;
 import org.apache.sis.setup.OptionKey;
 import org.apache.sis.storage.Resource;
@@ -33,7 +40,7 @@ import ucar.nc2.constants.CDM;
 
 
 /**
- * A data store backed by NetCDF files.
+ * A data store backed by netCDF files.
  * Instances of this data store are created by {@link NetcdfStoreProvider#open(StorageConnector)}.
  *
  * @author  Martin Desruisseaux (Geomatys)
@@ -44,53 +51,51 @@ import ucar.nc2.constants.CDM;
  * @since 0.3
  * @module
  */
-public class NetcdfStore extends DataStore {
+public class NetcdfStore extends DataStore implements Aggregate {
     /**
-     * The object to use for decoding the NetCDF file content. There is two different implementations,
+     * The object to use for decoding the netCDF file content. There is two different implementations,
      * depending on whether we are using the embedded SIS decoder or a wrapper around the UCAR library.
      */
     private final Decoder decoder;
 
     /**
+     * The {@link NetcdfStoreProvider#LOCATION} parameter value, or {@code null} if none.
+     */
+    private final URI location;
+
+    /**
      * The object returned by {@link #getMetadata()}, created when first needed and cached.
      */
     private Metadata metadata;
 
     /**
-     * Creates a new NetCDF store from the given file, URL, stream or {@link ucar.nc2.NetcdfFile} object.
-     * This constructor invokes {@link StorageConnector#closeAllExcept(Object)}, keeping open only the
-     * needed resource.
-     *
-     * @param  connector information about the storage (URL, stream, {@link ucar.nc2.NetcdfFile} instance, <i>etc</i>).
-     * @throws DataStoreException if an error occurred while opening the NetCDF file.
+     * The data (raster or features) found in the netCDF file. This list is created when first needed.
      *
-     * @deprecated Replaced by {@link #NetcdfStore(NetcdfStoreProvider, StorageConnector)}.
+     * @see #components()
      */
-    @Deprecated
-    public NetcdfStore(final StorageConnector connector) throws DataStoreException {
-        this(null, connector);
-    }
+    private List<Resource> components;
 
     /**
-     * Creates a new NetCDF store from the given file, URL, stream or {@link ucar.nc2.NetcdfFile} object.
+     * Creates a new netCDF store from the given file, URL, stream or {@link ucar.nc2.NetcdfFile} object.
      * This constructor invokes {@link StorageConnector#closeAllExcept(Object)}, keeping open only the
      * needed resource.
      *
      * @param  provider   the factory that created this {@code DataStore} instance, or {@code null} if unspecified.
      * @param  connector  information about the storage (URL, stream, {@link ucar.nc2.NetcdfFile} instance, <i>etc</i>).
-     * @throws DataStoreException if an error occurred while opening the NetCDF file.
+     * @throws DataStoreException if an error occurred while opening the netCDF file.
      *
      * @since 0.8
      */
     public NetcdfStore(final NetcdfStoreProvider provider, final StorageConnector connector) throws DataStoreException {
         super(provider, connector);
+        location = connector.getStorageAs(URI.class);
         try {
             decoder = NetcdfStoreProvider.decoder(listeners, connector);
         } catch (IOException e) {
             throw new DataStoreException(e);
         }
         if (decoder == null) {
-            throw new UnsupportedStorageException(super.getLocale(), "NetCDF",
+            throw new UnsupportedStorageException(super.getLocale(), NetcdfStoreProvider.NAME,
                     connector.getStorage(), connector.getOption(OptionKey.OPEN_OPTIONS));
         }
     }
@@ -118,18 +123,23 @@ public class NetcdfStore extends DataSto
     }
 
     /**
-     * This implementation does not provide any resource yet.
+     * Returns the parameters used to open this netCDF data store.
+     * If non-null, the parameters are described by {@link NetcdfStoreProvider#getOpenParameters()} and contains at
+     * least a parameter named {@value org.apache.sis.storage.DataStoreProvider#LOCATION} with a {@link URI} value.
+     * This method may return {@code null} if the storage input can not be described by a URI
+     * (for example a netCDF file reading directly from a {@link java.nio.channels.ReadableByteChannel}).
      *
-     * @return currently {@code null} (will be implemented in future Apache SIS version).
-     * @throws DataStoreException if an error occurred while reading the data.
+     * @return parameters used for opening this data store, or {@code null} if not available.
+     *
+     * @since 0.8
      */
     @Override
-    public Resource getRootResource() throws DataStoreException {
-        return null;
+    public ParameterValueGroup getOpenParameters() {
+        return URIDataStore.parameters(provider, location);
     }
 
     /**
-     * Returns the version number of the Climate and Forecast (CF) conventions used in the NetCDF file.
+     * Returns the version number of the Climate and Forecast (CF) conventions used in the netCDF file.
      * The use of CF convention is mandated by the OGC 11-165r2 standard
      * (<cite>CF-netCDF3 Data Model Extension standard</cite>).
      *
@@ -148,9 +158,28 @@ public class NetcdfStore extends DataSto
     }
 
     /**
-     * Closes this NetCDF store and releases any underlying resources.
+     * Returns the resources (features or coverages) in this netCDF file.
+     *
+     * @return children resources that are components of this netCDF.
+     * @throws DataStoreException if an error occurred while fetching the components.
+     *
+     * @since 0.8
+     */
+    @Override
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
+    public synchronized Collection<Resource> components() throws DataStoreException {
+        if (components == null) try {
+            components = UnmodifiableArrayList.wrap(decoder.getDiscreteSampling());
+        } catch (IOException e) {
+            throw new DataStoreException(e);
+        }
+        return components;
+    }
+
+    /**
+     * Closes this netCDF store and releases any underlying resources.
      *
-     * @throws DataStoreException if an error occurred while closing the NetCDF file.
+     * @throws DataStoreException if an error occurred while closing the netCDF file.
      */
     @Override
     public synchronized void close() throws DataStoreException {
@@ -163,10 +192,10 @@ public class NetcdfStore extends DataSto
     }
 
     /**
-     * Returns a string representation of this NetCDF store for debugging purpose.
+     * Returns a string representation of this netCDF store for debugging purpose.
      * The content of the string returned by this method may change in any future SIS version.
      *
-     * @return a string representation of this datastore for debugging purpose.
+     * @return a string representation of this data store for debugging purpose.
      */
     @Debug
     @Override

Modified: sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -26,6 +26,7 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.UndeclaredThrowableException;
+import org.opengis.parameter.ParameterDescriptorGroup;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.Resources;
 import org.apache.sis.internal.netcdf.impl.ChannelDecoder;
@@ -33,8 +34,11 @@ import org.apache.sis.internal.netcdf.uc
 import org.apache.sis.internal.storage.io.ChannelDataInput;
 import org.apache.sis.internal.storage.Capabilities;
 import org.apache.sis.internal.storage.Capability;
+import org.apache.sis.internal.storage.URIDataStore;
 import org.apache.sis.internal.system.SystemListener;
 import org.apache.sis.internal.system.Modules;
+import org.apache.sis.setup.GeometryLibrary;
+import org.apache.sis.setup.OptionKey;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreProvider;
 import org.apache.sis.storage.StorageConnector;
@@ -47,7 +51,7 @@ import org.apache.sis.util.Version;
 
 /**
  * The provider of {@link NetcdfStore} instances. Given a {@link StorageConnector} input,
- * this class tries to instantiate a {@code NetcdfStore} using the embedded NetCDF decoder.
+ * this class tries to instantiate a {@code NetcdfStore} using the embedded netCDF decoder.
  * If the embedded decoder can not decode the given input and the UCAR library is reachable
  * on the classpath, then this class tries to instantiate a {@code NetcdfStore} backed by
  * the UCAR library.
@@ -67,11 +71,21 @@ import org.apache.sis.util.Version;
 @Capabilities(Capability.READ)
 public class NetcdfStoreProvider extends DataStoreProvider {
     /**
-     * The MIME type for NetCDF files.
+     * The format name.
+     */
+    static final String NAME = "NetCDF";
+
+    /**
+     * The MIME type for netCDF files.
      */
     static final String MIME_TYPE = "application/x-netcdf";
 
     /**
+     * The parameter descriptor to be returned by {@link #getOpenParameters()}.
+     */
+    private static final ParameterDescriptorGroup OPEN_DESCRIPTOR = URIDataStore.Provider.descriptor(NAME);
+
+    /**
      * The name of the {@link ucar.nc2.NetcdfFile} class, which is {@value}.
      */
     private static final String UCAR_CLASSNAME = "ucar.nc2.NetcdfFile";
@@ -91,7 +105,7 @@ public class NetcdfStoreProvider extends
 
     /**
      * If the {@link #netcdfFileClass} has been found, then the {@link DecoderWrapper} constructor receiving
-     * in argument the name of the NetCDF file as a {@link String} object. Otherwise {@code null}.
+     * in argument the name of the netCDF file as a {@link String} object. Otherwise {@code null}.
      */
     private static volatile Constructor<? extends Decoder> createFromPath;
 
@@ -126,7 +140,19 @@ public class NetcdfStoreProvider extends
      */
     @Override
     public String getShortName() {
-        return "NetCDF";
+        return NAME;
+    }
+
+    /**
+     * Returns a description of all parameters accepted by this provider for opening a netCDF file.
+     *
+     * @return description of available parameters for opening a netCDF file.
+     *
+     * @since 0.8
+     */
+    @Override
+    public ParameterDescriptorGroup getOpenParameters() {
+        return OPEN_DESCRIPTOR;
     }
 
     /**
@@ -232,51 +258,54 @@ public class NetcdfStoreProvider extends
      * {@link StorageConnector#closeAllExcept(Object)} after the decoder has been created.
      *
      * @param  listeners  where to send the warnings.
-     * @param  storage    information about the input (file, input stream, <i>etc.</i>)
+     * @param  connector  information about the input (file, input stream, <i>etc.</i>)
      * @return the decoder for the given input, or {@code null} if the input type is not recognized.
-     * @throws IOException if an error occurred while opening the NetCDF file.
+     * @throws IOException if an error occurred while opening the netCDF file.
      * @throws DataStoreException if a logical error (other than I/O) occurred.
      */
-    static Decoder decoder(final WarningListeners<DataStore> listeners, final StorageConnector storage)
+    static Decoder decoder(final WarningListeners<DataStore> listeners, final StorageConnector connector)
             throws IOException, DataStoreException
     {
+        final GeometryLibrary geomlib = connector.getOption(OptionKey.GEOMETRY_LIBRARY);
         Decoder decoder;
         Object keepOpen;
-        final ChannelDataInput input = storage.getStorageAs(ChannelDataInput.class);
+        final ChannelDataInput input = connector.getStorageAs(ChannelDataInput.class);
         if (input != null) try {
-            decoder = new ChannelDecoder(listeners, input);
+            decoder = new ChannelDecoder(input, connector.getOption(OptionKey.ENCODING), geomlib, listeners);
             keepOpen = input;
         } catch (DataStoreException e) {
-            final String path = storage.getStorageAs(String.class);
+            final String path = connector.getStorageAs(String.class);
             if (path != null) try {
-                decoder = createByReflection(listeners, path, false);
+                decoder = createByReflection(path, false, geomlib, listeners);
                 keepOpen = path;
             } catch (IOException | DataStoreException s) {
                 e.addSuppressed(s);
             }
             throw e;
         } else {
-            keepOpen = storage.getStorage();
-            decoder = createByReflection(listeners, keepOpen, true);
+            keepOpen = connector.getStorage();
+            decoder = createByReflection(keepOpen, true, geomlib, listeners);
         }
-        storage.closeAllExcept(keepOpen);
+        connector.closeAllExcept(keepOpen);
         return decoder;
     }
 
     /**
-     * Creates a new NetCDF decoder as a wrapper around the UCAR library. This decoder is used only when we can
-     * not create our embedded NetCDF decoder. This method uses reflection for creating the wrapper, in order
+     * Creates a new netCDF decoder as a wrapper around the UCAR library. This decoder is used only when we can
+     * not create our embedded netCDF decoder. This method uses reflection for creating the wrapper, in order
      * to keep the UCAR dependency optional.
      *
-     * @param  listeners  where to send the warnings.
-     * @param  input      the NetCDF file object of filename string from which to read data.
+     * @param  input      the netCDF file object of filename string from which to read data.
      * @param  isUCAR     {@code true} if {@code input} is an instance of the UCAR {@link ucar.nc2.NetcdfFile} object,
      *                    or {@code false} if it is the filename as a {@code String}.
+     * @param  geomlib    the library for geometric objects, or {@code null} for the default.
+     * @param  listeners  where to send the warnings.
      * @return the {@link DecoderWrapper} instance for the given input, or {@code null} if the input type is not recognized.
-     * @throws IOException if an error occurred while opening the NetCDF file.
+     * @throws IOException if an error occurred while opening the netCDF file.
      * @throws DataStoreException if a logical error (other than I/O) occurred.
      */
-    private static Decoder createByReflection(final WarningListeners<DataStore> listeners, final Object input, final boolean isUCAR)
+    private static Decoder createByReflection(final Object input, final boolean isUCAR,
+            final GeometryLibrary geomlib, final WarningListeners<DataStore> listeners)
             throws IOException, DataStoreException
     {
         ensureInitialized(true);
@@ -297,7 +326,7 @@ public class NetcdfStoreProvider extends
             return null;
         }
         try {
-            return constructor.newInstance(listeners, input);
+            return constructor.newInstance(input, geomlib, listeners);
         } catch (InvocationTargetException e) {
             final Throwable cause = e.getCause();
             if (cause instanceof IOException)        throw (IOException)        cause;
@@ -336,9 +365,9 @@ public class NetcdfStoreProvider extends
                          */
                         final Class<? extends Decoder> wrapper =
                                 Class.forName("org.apache.sis.internal.netcdf.ucar.DecoderWrapper").asSubclass(Decoder.class);
-                        final Class<?>[] parameterTypes = new Class<?>[] {WarningListeners.class, netcdfFileClass};
+                        final Class<?>[] parameterTypes = new Class<?>[] {netcdfFileClass, GeometryLibrary.class, WarningListeners.class};
                         createFromUCAR = wrapper.getConstructor(parameterTypes);
-                        parameterTypes[1] = String.class;
+                        parameterTypes[0] = String.class;
                         createFromPath = wrapper.getConstructor(parameterTypes);
                         return;                                                                         // Success
                     }
@@ -356,7 +385,7 @@ public class NetcdfStoreProvider extends
                      *
                      * ReflectiveOperationException should never happen because API compatibility shall be verified
                      * by the JUnit tests. If it happen anyway  (for example because the user puts on his classpath
-                     * a different version of the NetCDF library than the one we tested), report a warning.
+                     * a different version of the netCDF library than the one we tested), report a warning.
                      */
                     severity = Level.WARNING;
                     cause = e;

Modified: sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -17,7 +17,7 @@
 
 /**
  * Maps ISO metadata elements from/to the <a href="http://www.cfconventions.org">Climate and Forecast (CF)</a>
- * attributes in a NetCDF file. The mapping is defined in the following web pages:
+ * attributes in a netCDF file. The mapping is defined in the following web pages:
  *
  * <ul>
  *   <li><a href="http://wiki.esipfed.org/index.php/Category:Attribute_Conventions_Dataset_Discovery">NetCDF
@@ -25,7 +25,7 @@
  *   <li><a href="https://github.com/Unidata/threddsIso/blob/master/src/main/resources/xsl/nciso/UnidataDD2MI.xsl">UnidataDD2MI.xsl</a> file.</li>
  * </ul>
  *
- * The NetCDF attributes recognized by this package are listed in the
+ * The netCDF attributes recognized by this package are listed in the
  * {@link org.apache.sis.storage.netcdf.AttributeNames} class.
  *
  * <div class="section">Note on the definition of terms</div>
@@ -42,7 +42,7 @@
  *       but is rather related to <cite>grid envelope</cite>.</li>
  *   <li>ISO 19123 coverage <cite>domain</cite> is related to UCAR coordinate system <cite>"range"</cite>.</li>
  *   <li>ISO 19123 coverage <cite>range</cite> is not equivalent to UCAR <cite>"range"</cite>,
- *       but is rather related to the NetCDF variable's minimum and maximum values.</li>
+ *       but is rather related to the netCDF variable's minimum and maximum values.</li>
  * </ul>
  *
  * Care must be taken for avoiding confusion when using SIS and UCAR libraries together.

Modified: sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DataTypeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DataTypeTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DataTypeTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DataTypeTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -32,7 +32,7 @@ import static org.junit.Assert.*;
  */
 public final strictfp class DataTypeTest extends TestCase {
     /**
-     * Verifies the relationship between the enumeration ordinal value and the NetCDF numerical code.
+     * Verifies the relationship between the enumeration ordinal value and the netCDF numerical code.
      */
     @Test
     public void testOrdinalValues() {

Modified: sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -57,7 +57,7 @@ public strictfp class DecoderTest extend
         if (isSupplementalFormatSupported("HDF5")) {
             selectDataset(CIP);
             assertAttributeEquals(/* Only control character */ (String) null,   TITLE);
-            assertAttributeEquals("UCAR",                                       CREATOR.INSTITUTION);
+            assertAttributeEquals("UCAR",                                      "INSTITUTION");
             assertAttributeEquals("U.S. National Weather Service - NCEP (WMC)", HISTORY);
         }
     }



Mime
View raw message