Author: desruisseaux
Date: Mon Oct 16 19:10:29 2017
New Revision: 1812312

URL: http://svn.apache.org/viewvc?rev=1812312&view=rev
Log:
Add support for NetCDF "creator_type", "publisher_type" and "program" 
attributes.

Modified:
    
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java
    
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
    
sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java
    
sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
    
sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/StoreFormat.java

Modified: 
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java?rev=1812312&r1=1812311&r2=1812312&view=diff
==============================================================================
--- 
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/AttributeNames.java
 [UTF-8] Mon Oct 16 19:10:29 2017
@@ -31,6 +31,8 @@ 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.AcquisitionInformation;
+import org.opengis.metadata.acquisition.Operation;
 import org.opengis.metadata.distribution.Distributor;
 import org.opengis.metadata.distribution.Distribution;
 import org.opengis.metadata.constraint.LegalConstraints;
@@ -68,6 +70,7 @@ 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>
@@ -77,9 +80,12 @@ import org.opengis.metadata.extent.Geogr
  * {@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>
@@ -104,9 +110,11 @@ import org.opengis.metadata.extent.Geogr
  * {@linkplain #TITLE "name"}<br>
  * {@value     #NAMING_AUTHORITY}<br>
  * {@value     #PROCESSING_LEVEL}<br>
+ * {@value     #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>
@@ -391,6 +399,22 @@ public class AttributeNames {
     public static final String DATE_ISSUED = "date_issued";
 
     /**
+     * The overarching program(s) of which the dataset is a part
+     * (<em>Suggested</em>).
+     *
+     * <p><b>Path in ISO 19115:</b></p> <ul><li>{@link Metadata} /
+     * {@link Metadata#getAcquisitionInformation() acquisitionInformation} /
+     * {@link AcquisitionInformation#getOperations() operation} /
+     * {@link Operation#getCitation() citation} /
+     * {@link Citation#getTitle() title}</li></ul>
+     *
+     * @see <a 
href="http://wiki.esipfed.org/index.php/Attribute_Convention_for_Data_Discovery#program";>ESIP
 reference</a>
+     *
+     * @since 0.8
+     */
+    public static final String PROGRAM = "program";
+
+    /**
      * 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.
@@ -408,10 +432,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>
@@ -442,7 +471,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
      *
@@ -456,7 +485,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} /
@@ -465,6 +494,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"}.
          *
@@ -512,19 +548,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;
@@ -544,8 +594,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>).
@@ -558,7 +608,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);
 
     /**
@@ -577,8 +627,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
@@ -685,6 +735,8 @@ public class AttributeNames {
 
     /**
      * 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} /
@@ -692,6 +744,8 @@ public class AttributeNames {
      * {@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";

Modified: 
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java?rev=1812312&r1=1812311&r2=1812312&view=diff
==============================================================================
--- 
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
 [UTF-8] Mon Oct 16 19:10:29 2017
@@ -425,8 +425,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
@@ -434,13 +436,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;
@@ -500,7 +518,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);
             }
@@ -509,6 +527,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.
      *
@@ -768,6 +796,13 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
+     * Adds information about acquisition (program, platform).
+     */
+    private void addAcquisitionInfo() {
+        addAcquisitionOperation(null, stringValue(PROGRAM));
+    }
+
+    /**
      * 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.
      */
@@ -918,6 +953,7 @@ split:  while ((start = CharSequences.sk
                 addResourceScope(ScopeCode.SERVICE, name);
             }
         }
+        addAcquisitionInfo();
         addContentInfo();
         /*
          * Add the dimension information, if any. This metadata node

Modified: 
sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java?rev=1812312&r1=1812311&r2=1812312&view=diff
==============================================================================
--- 
sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/DecoderTest.java
 [UTF-8] Mon Oct 16 19:10:29 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/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java?rev=1812312&r1=1812311&r2=1812312&view=diff
==============================================================================
--- 
sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
 [UTF-8] Mon Oct 16 19:10:29 2017
@@ -2416,6 +2416,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:
      *

Modified: 
sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/StoreFormat.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/StoreFormat.java?rev=1812312&r1=1812311&r2=1812312&view=diff
==============================================================================
--- 
sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/StoreFormat.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/StoreFormat.java
 [UTF-8] Mon Oct 16 19:10:29 2017
@@ -77,16 +77,18 @@ public final class StoreFormat extends W
      * @param  geometry       the geometry to parse, or {@code null} if none.
      * @param  crs            the horizontal part of the WKT (2D or 3D), or 
{@code null} if none.
      * @param  additionalCRS  the vertical or temporal part of the WKT, or 
{@code null} if none.
-     * @return the geometry, or {@code null} if none.
+     * @return the geometry, or {@code null} if none or unparseable.
      */
     public Geometry parseGeometry(final String geometry, final String crs, 
final String additionalCRS) {
-        if (geometry != null) {
+        if (geometry != null) try {
             final Object obj = 
Geometries.implementation(library).parseWKT(geometry);
             final GeneralEnvelope envelope = Geometries.getEnvelope(geometry);
             if (envelope != null) {
                 envelope.setCoordinateReferenceSystem(parseCRS(crs, 
additionalCRS));
                 return new GeometryWrapper(obj, envelope);
             }
+        } catch (IllegalArgumentException | UnsupportedOperationException e) {
+            log(e);
         }
         return null;
     }
@@ -110,14 +112,13 @@ public final class StoreFormat extends W
                     components[n++] = (CoordinateReferenceSystem) crs;
                 }
             }
-            if (n == 0) {
-                return null;
+            if (n != 0) {
+                return CRS.compound(ArraysExt.resize(components, n));
             }
-            return CRS.compound(ArraysExt.resize(components, n));
         } catch (ParseException | ClassCastException | 
IllegalArgumentException | FactoryException e) {
             log(e);
-            return null;
         }
+        return null;
     }
 
     /**


Reply via email to