sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1813531 [3/3] - in /sis/trunk: ./ core/sis-feature/src/main/java/org/apache/sis/feature/builder/ core/sis-feature/src/main/java/org/apache/sis/internal/feature/ core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/ core/sis-r...
Date Fri, 27 Oct 2017 12:58:40 GMT
Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java [UTF-8] Fri Oct 27 12:58:39 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,9 +45,11 @@ 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;
 
@@ -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,32 @@ 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,8 +175,85 @@ 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}
+     * 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.
+     *
+     * <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>
+     *
+     * <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 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 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} /
@@ -172,16 +262,22 @@ public class AttributeNames {
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
      * {@link DataIdentification#getCitation() citation} /
      * {@link Citation#getIdentifiers() identifier} /
-     * {@link Identifier#getCode() code}</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 NetcdfFile#getId()
      * @see <a href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#id">ESIP reference</a>
      */
-    public static final String IDENTIFIER = ACDD.id;
+    public static final Term IDENTIFIER = new Term(ACDD.id, ACDD.naming_authority);
 
     /**
      * The {@value} attribute name for the identifier authority (<em>Recommended</em>).
-     * The combination of the {@value} and the {@value #IDENTIFIER} should be a globally
+     * The combination of the {@value} 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} /
@@ -190,32 +286,40 @@ public class AttributeNames {
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
      * {@link DataIdentification#getCitation() citation} /
      * {@link Citation#getIdentifiers() identifier} /
-     * {@link Identifier#getAuthority() authority}</li></ul>
+     * {@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>
+     *
+     * @deprecated Moved to {@code IDENTIFIER.VOCABULARY}.
      */
+    @Deprecated
     public static final String NAMING_AUTHORITY = 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>
+     * {@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_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;
+    public static final Term STANDARD_NAME = new Term(CF.STANDARD_NAME, ACDD.standard_name_vocabulary);
 
     /**
      * The {@value} attribute name for indicating which controlled list of variable names has been
-     * used in the {@value #STANDARD_NAME} attribute.
+     * used in the {@code "standard_name"} attribute.
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
@@ -226,27 +330,34 @@ public class AttributeNames {
      * @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>
+     *
+     * @deprecated Moved to {@code STANDARD_NAME.VOCABULARY}.
      */
+    @Deprecated
     public static final String STANDARD_NAME_VOCABULARY = 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>
+     * {@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 #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;
+    public static final Term KEYWORDS = new Term(ACDD.keywords, ACDD.keywords_vocabulary);
 
     /**
      * The {@value} attribute name for the guideline for the words/phrases in the
-     * {@value #KEYWORDS} attribute (<em>Recommended</em>).
+     * {@code "keyword"} attribute (<em>Recommended</em>).
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
      * {@link Metadata#getIdentificationInfo() identificationInfo} /
@@ -257,7 +368,10 @@ public class AttributeNames {
      * @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>
+     *
+     * @deprecated Moved to {@code KEYWORDS.VOCABULARY}.
      */
+    @Deprecated
     public static final String VOCABULARY = ACDD.keywords_vocabulary;
 
     /**
@@ -296,6 +410,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 +422,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 +454,24 @@ public class AttributeNames {
      * subgroup.
      *
      * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
-     * {@link Metadata#getDateStamp() dateStamp}</li></ul>
+     * {@code 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} /
+     * {@code 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,6 +514,80 @@ 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.
@@ -388,10 +605,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>
@@ -422,7 +644,7 @@ public class AttributeNames {
      * 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 +658,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 +667,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"}.
          *
@@ -492,19 +721,33 @@ public class AttributeNames {
         public final Role DEFAULT_ROLE;
 
         /**
+         * @deprecated replaced by the constructor with one more argument (the type).
+         */
+        @Deprecated
+        public Responsible(final String name, final String institution, final String url, final String email,
+                final String role, final Role defaultRole)
+        {
+            this(name, null, institution, url, email, role, defaultRole);
+        }
+
+        /**
          * 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 +767,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 +781,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 +800,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 +812,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";
@@ -664,6 +908,23 @@ 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.
@@ -724,7 +985,7 @@ 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
+     * 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)
@@ -806,7 +1067,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 +1223,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} /
+     * {@code 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/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -54,6 +54,7 @@ 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;
@@ -62,6 +63,7 @@ import org.apache.sis.internal.netcdf.Va
 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;
@@ -70,6 +72,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;
 
@@ -109,6 +112,12 @@ import static org.apache.sis.storage.net
  */
 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.
      *
@@ -123,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 = ',';
 
@@ -369,24 +378,39 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
+     * 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 +446,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 +457,29 @@ split:  while ((start = CharSequences.sk
      * @see AttributeNames#PUBLISHER
      */
     private ResponsibleParty 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;
@@ -491,7 +533,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, (DefaultIndividual) 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 DefaultResponsibleParty(role);
                 ((DefaultResponsibleParty) responsibility).setParties(singleton(party));
@@ -501,6 +543,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.
      *
@@ -521,8 +573,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);
@@ -585,8 +639,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));
@@ -612,10 +666,19 @@ 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.valueOf("PROJECT"), null);
         addKeywords(publisher, KeywordType.valueOf("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")));
+        }
     }
 
     /**
@@ -651,7 +714,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.
@@ -750,6 +813,33 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
+     * 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.
      */
@@ -805,11 +895,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)) {
@@ -826,6 +916,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)));
     }
 
     /**
@@ -854,18 +945,18 @@ split:  while ((start = CharSequences.sk
      * 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>{@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);
+        String identifier = stringValue(IDENTIFIER.TEXT);
         String authority;
         if (identifier != null) {
-            authority = stringValue(NAMING_AUTHORITY);
+            authority = stringValue(IDENTIFIER.VOCABULARY);
         } else {
             identifier = decoder.getId();
             if (identifier == null) {
@@ -900,6 +991,7 @@ split:  while ((start = CharSequences.sk
                 addResourceScope(ScopeCode.SERVICE, name);
             }
         }
+        addAcquisitionInfo();
         addContentInfo();
         /*
          * Add the dimension information, if any. This metadata node
@@ -921,17 +1013,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/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java [UTF-8] Fri Oct 27 12:58:39 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);
         }
     }

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -24,16 +24,19 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.net.URI;
 import java.nio.charset.Charset;
 import javax.measure.Unit;
 import org.opengis.util.MemberName;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
+import org.opengis.geometry.Geometry;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
+import org.opengis.metadata.citation.OnLineFunction;
 import org.opengis.metadata.spatial.GCP;
 import org.opengis.metadata.spatial.Dimension;
 import org.opengis.metadata.spatial.DimensionNameType;
@@ -42,6 +45,7 @@ import org.opengis.metadata.spatial.Pixe
 import org.opengis.metadata.spatial.GeolocationInformation;
 import org.opengis.metadata.spatial.SpatialRepresentationType;
 import org.opengis.metadata.constraint.Restriction;
+import org.opengis.metadata.content.CoverageContentType;
 import org.opengis.metadata.content.TransferFunctionType;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.acquisition.Context;
@@ -62,6 +66,7 @@ import org.apache.sis.metadata.iso.Defau
 import org.apache.sis.metadata.iso.extent.DefaultExtent;
 import org.apache.sis.metadata.iso.extent.DefaultVerticalExtent;
 import org.apache.sis.metadata.iso.extent.DefaultTemporalExtent;
+import org.apache.sis.metadata.iso.extent.DefaultBoundingPolygon;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicDescription;
 import org.apache.sis.metadata.iso.spatial.DefaultGridSpatialRepresentation;
@@ -83,6 +88,7 @@ import org.apache.sis.metadata.iso.citat
 import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.metadata.iso.citation.DefaultIndividual;
 import org.apache.sis.metadata.iso.citation.DefaultOrganisation;
+import org.apache.sis.metadata.iso.citation.DefaultOnlineResource;
 import org.apache.sis.metadata.iso.constraint.DefaultLegalConstraints;
 import org.apache.sis.metadata.iso.identification.DefaultKeywords;
 import org.apache.sis.metadata.iso.identification.DefaultResolution;
@@ -1134,12 +1140,31 @@ public class MetadataBuilder {
     }
 
     /**
+     * Adds a version of the resource.
+     * If a version already exists, the new one will be appended after a new line.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/identificationInfo/citation/edition}</li>
+     * </ul>
+     *
+     * @param version  the version of resource(s), or {@code null} for no-operation.
+     */
+    public final void addEdition(final CharSequence version) {
+        final InternationalString i18n = trim(version);
+        if (i18n != null) {
+            final DefaultCitation citation = citation();
+            citation.setEdition(append(citation.getEdition(), i18n));
+        }
+    }
+
+    /**
      * Adds a brief narrative summary of the resource(s).
-     * If a summary already existed, the new one will be appended after a new line.
+     * If a summary already exists, the new one will be appended after a new line.
      * Storage location is:
      *
      * <ul>
-     *   <li>{@code metadata/identificationInfo/abstract}
+     *   <li>{@code metadata/identificationInfo/abstract}</li>
      * </ul>
      *
      * @param description  the summary of resource(s), or {@code null} for no-operation.
@@ -1157,7 +1182,7 @@ public class MetadataBuilder {
 
     /**
      * Adds a summary of the intentions with which the resource(s) was developed.
-     * If a purpose already existed, the new one will be appended after a new line.
+     * If a purpose already exists, the new one will be appended after a new line.
      * Storage location is:
      *
      * <ul>
@@ -1196,7 +1221,7 @@ public class MetadataBuilder {
 
     /**
      * Adds any other descriptive information about the resource.
-     * If information already existed, the new one will be appended after a new line.
+     * If information already exists, the new one will be appended after a new line.
      * Storage location is:
      *
      * <ul>
@@ -1656,6 +1681,22 @@ parse:      for (int i = 0; i < length;)
     }
 
     /**
+     * Adds the given geometry as a bounding polygon.
+     * Storage locations is:
+     *
+     * <ul>
+     *   <li>{@code metadata/identificationInfo/extent/geographicElement/polygon}</li>
+     * </ul>
+     *
+     * @param  bounds  the bounding polygon, or {@code null} if none.
+     */
+    public final void addBoundingPolygon(final Geometry bounds) {
+        if (bounds != null) {
+            addIfNotPresent(extent().getGeographicElements(), new DefaultBoundingPolygon(bounds));
+        }
+    }
+
+    /**
      * Adds a geographic extent described by an identifier. The given identifier is stored as-is as
      * the natural language description, and possibly in a modified form as the geographic identifier.
      * See {@link DefaultGeographicDescription#DefaultGeographicDescription(CharSequence)} for details.
@@ -2044,6 +2085,22 @@ parse:      for (int i = 0; i < length;)
     }
 
     /**
+     * Adds type of information represented in the cell.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/attributeGroup/contentType}</li>
+     * </ul>
+     *
+     * @param  type  type of information represented in the cell, or {@code null} for no-operation.
+     */
+    public final void addContentType(final CoverageContentType type) {
+        if (type != null) {
+            attributeGroup().getContentTypes().add(type);
+        }
+    }
+
+    /**
      * Sets the name or number that uniquely identifies instances of bands of wavelengths on which a sensor operates.
      * If a coverage contains more than one band, additional bands can be created by calling
      * {@link #newSampleDimension()} before to call this method.
@@ -2103,7 +2160,7 @@ parse:      for (int i = 0; i < length;)
      * @param  authority  identifies which controlled list of name is used, or {@code null} if none.
      * @param  name       the band name, or {@code null} for no-operation.
      */
-    public final void addBandIdentifier(final CharSequence authority, String name) {
+    public final void addBandName(final CharSequence authority, String name) {
         if (name != null && !(name = name.trim()).isEmpty()) {
             addIfNotPresent(sampleDimension().getNames(), sharedIdentifier(authority, name));
         }
@@ -2416,6 +2473,26 @@ parse:      for (int i = 0; i < length;)
     }
 
     /**
+     * Adds the identifier of the operation used to acquire the dataset.
+     * Examples: "GHRSST", "NOAA CDR", "NASA EOS", "JPSS", "GOES-R".
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/acquisitionInformation/operation/identifier}</li>
+     * </ul>
+     *
+     * @param  program     identification of the mission, or {@code null} if none.
+     * @param  identifier  unique identification of the operation, or {@code null} for no-operation.
+     */
+    public final void addAcquisitionOperation(final CharSequence program, String identifier) {
+        if (identifier != null && !(identifier = identifier.trim()).isEmpty()) {
+            final DefaultOperation r = new DefaultOperation();
+            r.setIdentifier(sharedIdentifier(program, identifier));
+            addIfNotPresent(acquisition().getOperations(), r);
+        }
+    }
+
+    /**
      * Adds the identifier of the requirement to be satisfied by data acquisition.
      * Storage location is:
      *
@@ -2544,6 +2621,25 @@ parse:      for (int i = 0; i < length;)
         }
     }
 
+    /**
+     * Adds a URL to a more complete description of the metadata.
+     *
+     * <ul>
+     *   <li>{@code metadata/metadataLinkage/linkage}
+     *     with {@code function} set to {@code OnLineFunction.COMPLETE_METADATA}</li>
+     * </ul>
+     *
+     * @param  link
+     */
+    public final void addCompleteMetadata(final URI link) {
+        if (link != null) {
+            final DefaultOnlineResource ln = new DefaultOnlineResource(link);
+            ln.setFunction(OnLineFunction.valueOf("COMPLETE_METADATA"));
+            ln.setProtocol(link.getScheme());
+            addIfNotPresent(metadata().getMetadataLinkages(), ln);
+        }
+    }
+
     /**
      * Returns the metadata (optionally as an unmodifiable object), or {@code null} if none.
      * If {@code freeze} is {@code true}, then the returned metadata instance can not be modified.

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -67,6 +67,11 @@ public final class Resources extends Ind
         public static final short AmbiguousName_4 = 15;
 
         /**
+         * Can not read the Coordinate Reference System (CRS) Well Known Text (WKT) in “{0}”.
+         */
+        public static final short CanNotReadCRS_WKT_1 = 37;
+
+        /**
          * Can not read “{0}” directory.
          */
         public static final short CanNotReadDirectory_1 = 34;

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] Fri Oct 27 12:58:39 2017
@@ -20,6 +20,7 @@
 # For resources shared by all modules in the Apache SIS project, see "org.apache.sis.util.resources" package.
 #
 AmbiguousName_4                   = Name \u201c{3}\u201d is ambiguous because it can be understood as either \u201c{1}\u201d or \u201c{2}\u201d in the context of \u201c{0}\u201d data.
+CanNotReadCRS_WKT_1               = Can not read the Coordinate Reference System (CRS) Well Known Text (WKT) in \u201c{0}\u201d.
 CanNotReadDirectory_1             = Can not read \u201c{0}\u201d directory.
 CanNotReadFile_2                  = Can not read \u201c{1}\u201d as a file in the {0} format.
 CanNotReadFile_3                  = Can not read line {2} of \u201c{1}\u201d as part of a file in the {0} format.

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] Fri Oct 27 12:58:39 2017
@@ -25,6 +25,7 @@
 #   U+00A0 NO-BREAK SPACE         before  :
 #
 AmbiguousName_4                   = Le nom \u00ab\u202f{3}\u202f\u00bb est ambigu\u00eb car il peut \u00eatre interpr\u00e9t\u00e9 aussi bien comme \u00ab\u202f{1}\u202f\u00bb ou \u00ab\u202f{2}\u202f\u00bb dans le contexte des donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb.
+CanNotReadCRS_WKT_1               = Ne peut pas lire le syst\u00e8me de r\u00e9f\u00e9rence spatial dans le \u00ab\u202fWell Known Text\u202f\u00bb (WKT) de \u00ab\u202f{0}\u202f\u00bb.
 CanNotReadDirectory_1             = Ne peut pas lire le r\u00e9pertoire \u00ab\u202f{0}\u202f\u00bb.
 CanNotReadFile_2                  = Ne peut pas lire \u00ab\u202f{1}\u202f\u00bb comme un fichier au format {0}.
 CanNotReadFile_3                  = Ne peut pas lire la ligne {2} de \u00ab\u202f{1}\u202f\u00bb comme une partie d\u2019un fichier au format {0}.

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -686,7 +686,6 @@ final class Store extends URIDataStore i
      * @todo Need to reset the position when doing another pass on the features. See {@link #rewind()}.
      * @todo If sequential order, publish Feature as soon as identifier changed.
      */
-    @Override
     public final synchronized Stream<AbstractFeature> features(final boolean parallel) throws DataStoreException {
         /*
          * If the user asks for one feature instance per line, then we can return a FeatureIter instance directly.

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -19,27 +19,22 @@ package org.apache.sis.internal.storage.
 import java.util.List;
 import java.util.Arrays;
 import java.util.ArrayList;
-import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.io.Reader;
 import java.io.IOException;
 import java.text.ParsePosition;
 import java.text.ParseException;
 import org.opengis.metadata.Metadata;
-import org.opengis.util.FactoryException;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.internal.storage.Resources;
 import org.apache.sis.internal.system.Loggers;
-import org.apache.sis.io.wkt.WKTFormat;
-import org.apache.sis.io.wkt.Warnings;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.storage.UnsupportedStorageException;
-import org.apache.sis.internal.referencing.DefinitionVerifier;
 import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.internal.storage.URIDataStore;
+import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.setup.OptionKey;
 import org.apache.sis.util.CharSequences;
 
@@ -66,6 +61,11 @@ final class Store extends URIDataStore {
     private Reader source;
 
     /**
+     * The geometry library, or {@code null} for the default.
+     */
+    private final GeometryLibrary library;
+
+    /**
      * The parsed objects, filled only when first needed.
      * May still be empty if the parsing failed.
      */
@@ -92,6 +92,7 @@ final class Store extends URIDataStore {
             throw new UnsupportedStorageException(super.getLocale(), StoreProvider.NAME,
                     connector.getStorage(), connector.getOption(OptionKey.OPEN_OPTIONS));
         }
+        library = connector.getOption(OptionKey.GEOMETRY_LIBRARY);
     }
 
     /**
@@ -128,30 +129,12 @@ final class Store extends URIDataStore {
              * definitions.
              */
             final ParsePosition pos = new ParsePosition(0);
-            final WKTFormat parser = new WKTFormat(null, null);
+            final StoreFormat parser = new StoreFormat(library, listeners);
             do {
                 final Object obj = parser.parse(wkt, pos);
                 objects.add(obj);
                 pos.setIndex(CharSequences.skipLeadingWhitespaces(wkt, pos.getIndex(), wkt.length()));
-                final Warnings warnings = parser.getWarnings();
-                if (warnings != null) {
-                    log(new LogRecord(Level.WARNING, warnings.toString()));
-                }
-                /*
-                 * The WKT has been parsed. Below is a verification of whether the parsed WKT is conform with
-                 * the authority definition (if an authority code has been specified). This verification is not
-                 * really necessary since we will use the WKT definition anyway even if we find discrepancies.
-                 * But non-conform WKT definitions happen so often in practice that we are better to check.
-                 */
-                if (obj instanceof CoordinateReferenceSystem) try {
-                    final DefinitionVerifier v = DefinitionVerifier.withAuthority((CoordinateReferenceSystem) obj, null, false);
-                    if (v != null) {
-                        final LogRecord warning = v.warning(false);
-                        if (warning != null) log(warning);
-                    }
-                } catch (FactoryException e) {
-                    listeners.warning(null, e);
-                }
+                parser.validate(obj);
             } while (pos.getIndex() < wkt.length());
         } catch (ParseException e) {
             throw new DataStoreContentException(getLocale(), "WKT", getDisplayName(), in).initCause(e);

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureSet.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureSet.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureSet.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureSet.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -17,8 +17,6 @@
 package org.apache.sis.storage;
 
 // Branch-dependent imports
-import org.apache.sis.internal.jdk8.Stream;
-import org.apache.sis.feature.AbstractFeature;
 import org.apache.sis.feature.DefaultFeatureType;
 
 
@@ -46,7 +44,7 @@ public interface FeatureSet extends Data
      *   <li>{@linkplain org.opengis.referencing.crs.CoordinateReferenceSystem Coordinate Reference System}.</li>
      * </ul>
      *
-     * All features returned by {@link #features(boolean)} will be either of that type, or a sub-type of it.
+     * All features returned by {@code features(boolean)} will be either of that type, or a sub-type of it.
      *
      * <div class="note"><b>Relationship with metadata:</b>
      * if subtypes exist, their list may be obtained from the {@linkplain #getMetadata() metadata} like below
@@ -100,5 +98,5 @@ public interface FeatureSet extends Data
      * @return all features contained in this dataset.
      * @throws DataStoreException if an error occurred while creating the stream.
      */
-    Stream<AbstractFeature> features(boolean parallel) throws DataStoreException;
+//  Stream<Feature> features(boolean parallel) throws DataStoreException;
 }

Copied: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java (from r1813524, sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java)
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java?p2=sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java&p1=sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java&r1=1813524&r2=1813531&rev=1813531&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -16,23 +16,21 @@
  */
 package org.apache.sis.storage;
 
-import org.opengis.feature.Feature;
-
 
 /**
  * Definition of filtering to apply for fetching a resource subset.
  * Filtering can happen in two domains:
  *
  * <ol>
- *   <li>By filtering the {@link Feature} instances.</li>
+ *   <li>By filtering the {@code Feature} instances.</li>
  *   <li>By filtering the {@linkplain org.apache.sis.feature.DefaultFeatureType#getProperty properties}
  *       in each feature instance.</li>
  * </ol>
  *
  * Compared to Java functional interfaces, the first domain is equivalent to using
- * <code>{@linkplain java.util.function.Predicate}&lt;{@linkplain Feature}&gt;</code>
+ * <code>{@linkplain java.util.function.Predicate}&lt;Feature&gt;</code>
  * while the second domain is equivalent to using
- * <code>{@linkplain java.util.function.UnaryOperator}&lt;{@linkplain Feature}&gt;</code>.
+ * <code>{@linkplain java.util.function.UnaryOperator}&lt;Feature&gt;</code>.
  * It is technically possible to use {@code Query} for performing more generic feature transformations,
  * for example inserting new properties computed from other properties, but such {@code Query} usages
  * should be rare since transformations (or more generic processing) are the topic of another package.

Modified: sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java?rev=1813531&r1=1813530&r2=1813531&view=diff
==============================================================================
--- sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java [UTF-8] (original)
+++ sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java [UTF-8] Fri Oct 27 12:58:39 2017
@@ -213,7 +213,6 @@ public final class Store extends StaxDat
      * @return a stream over all features in the XML file.
      * @throws DataStoreException if an error occurred while creating the feature stream.
      */
-    @Override
     public final synchronized Stream<AbstractFeature> features(boolean parallel) throws DataStoreException {
         Reader r = reader;
         reader = null;



Mime
View raw message