sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1798041 - in /sis/branches/JDK8: core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/ storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/ storage/sis-geotiff/src/main/java/org/apache/sis/sto...
Date Thu, 08 Jun 2017 10:45:14 GMT
Author: desruisseaux
Date: Thu Jun  8 10:45:14 2017
New Revision: 1798041

URL: http://svn.apache.org/viewvc?rev=1798041&view=rev
Log:
Use MetadataBuilder helper class in NetCDF ImageReader for building the CoverageDescription node.
This simplify a bit the MetadataReader class.

Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
    sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.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/storage/netcdf/MetadataReaderTest.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/FeatureCatalogBuilder.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/csv/Store.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java?rev=1798041&r1=1798040&r2=1798041&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java [UTF-8] Thu Jun  8 10:45:14 2017
@@ -149,7 +149,7 @@ public class DefaultRangeDimension exten
     }
 
     /**
-     * Sets the number that uniquely identifies instances of bands of wavelengths on which a sensor operates.
+     * Sets the name or number that uniquely identifies instances of bands of wavelengths on which a sensor operates.
      *
      * @param  newValue  the new sequence identifier.
      */

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java?rev=1798041&r1=1798040&r2=1798041&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java [UTF-8] Thu Jun  8 10:45:14 2017
@@ -78,6 +78,11 @@ public class DefaultSampleDimension exte
     private static final long serialVersionUID = 4517148689016920767L;
 
     /**
+     * Number of values used in a thematic classification resource.
+     */
+    private Integer numberOfValues;
+
+    /**
      * Minimum value of data values in each dimension included in the resource.
      */
     private Double minValue;
@@ -93,11 +98,6 @@ public class DefaultSampleDimension exte
     private Double meanValue;
 
     /**
-     * Number of values used in a thematicClassification resource.
-     */
-    private Integer numberOfValues;
-
-    /**
      * Standard deviation of data values in each dimension included in the resource.
      */
     private Double standardDeviation;
@@ -218,6 +218,31 @@ public class DefaultSampleDimension exte
     }
 
     /**
+     * Returns the number of values used in a thematic classification resource.
+     *
+     * @return the number of values used in a thematic classification resource, or {@code null} if none.
+     */
+    @Override
+    @ValueRange(minimum = 0)
+/// @XmlElement(name = "numberOfValues")
+    public Integer getNumberOfValues() {
+        return numberOfValues;
+    }
+
+    /**
+     * Sets the number of values used in a thematic classification resource.
+     *
+     * @param  newValue  the new number of values used in a thematic classification resource.
+     * @throws IllegalArgumentException if the given value is negative.
+     */
+    public void setNumberOfValues(final Integer newValue) {
+        checkWritePermission();
+        if (ensurePositive(DefaultSampleDimension.class, "numberOfValues", false, newValue)) {
+            numberOfValues = newValue;
+        }
+    }
+
+    /**
      * Returns the minimum value of data values in each dimension included in the resource.
      *
      * @return minimum value of data values in each dimension included in the resource, or {@code null} if unspecified.
@@ -281,31 +306,6 @@ public class DefaultSampleDimension exte
     }
 
     /**
-     * Returns the number of values used in a thematic classification resource.
-     *
-     * @return the number of values used in a thematic classification resource, or {@code null} if none.
-     */
-    @Override
-    @ValueRange(minimum = 0)
-/// @XmlElement(name = "numberOfValues")
-    public Integer getNumberOfValues() {
-        return numberOfValues;
-    }
-
-    /**
-     * Sets the number of values used in a thematic classification resource.
-     *
-     * @param  newValue  the new number of values used in a thematic classification resource.
-     * @throws IllegalArgumentException if the given value is negative.
-     */
-    public void setNumberOfValues(final Integer newValue) {
-        checkWritePermission();
-        if (ensurePositive(DefaultSampleDimension.class, "numberOfValues", false, newValue)) {
-            numberOfValues = newValue;
-        }
-    }
-
-    /**
      * Returns the standard deviation of data values in each dimension included in the resource.
      *
      * @return standard deviation of data values in each dimension included in the resource, or {@code null} if none.
@@ -382,7 +382,7 @@ public class DefaultSampleDimension exte
     /**
      * Sets the physical value corresponding to a cell value of zero.
      *
-     * @param  newValue  the new physical value corresponding to a cell value of zero, or {@code null} if none..
+     * @param  newValue  the new physical value corresponding to a cell value of zero.
      */
     public void setOffset(final Double newValue) {
         checkWritePermission();

Modified: sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java?rev=1798041&r1=1798040&r2=1798041&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java [UTF-8] Thu Jun  8 10:45:14 2017
@@ -456,7 +456,7 @@ final class LandsatReader {
              * Example: "0501403126384_00011"
              */
             case "REQUEST_ID": {
-                metadata.addAcquisitionRequirement(value);
+                metadata.addAcquisitionRequirement(null, value);
                 break;
             }
             /*
@@ -525,7 +525,7 @@ final class LandsatReader {
              * Example: "LANDSAT_8".
              */
             case "SPACECRAFT_ID": {
-                metadata.addPlatform(value);
+                metadata.addPlatform(null, value);
                 break;
             }
             /*
@@ -533,7 +533,7 @@ final class LandsatReader {
              * Example: "OLI", "TIRS" or "OLI_TIRS".
              */
             case "SENSOR_ID": {
-                metadata.addInstrument(value);
+                metadata.addInstrument(null, value);
                 break;
             }
             /*

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java?rev=1798041&r1=1798040&r2=1798041&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java [UTF-8] Thu Jun  8 10:45:14 2017
@@ -730,7 +730,7 @@ final class ImageFileDirectory {
              */
             case Tags.Model: {
                 for (final String value : type.readString(input(), count, encoding())) {
-                    reader.metadata.addInstrument(value);
+                    reader.metadata.addInstrument(null, value);
                 }
                 break;
             }
@@ -877,6 +877,9 @@ final class ImageFileDirectory {
      *   <li>Otherwise throws an exception.</li>
      * </ul>
      *
+     * This method opportunistically computes default value of optional fields
+     * when those values can be computed from other (usually mandatory) fields.
+     *
      * @throws DataStoreContentException if a mandatory tag is missing and can not be inferred.
      */
     final void validateMandatoryTags() throws DataStoreContentException {
@@ -915,6 +918,8 @@ final class ImageFileDirectory {
         if (colorMap != null) {
             ensureSameLength(Tags.ColorMap, Tags.BitsPerSample, colorMap.size(),  3 * (1 << bitsPerSample));
         }
+        if (Double.isNaN(minValue)) minValue = 0;
+        if (Double.isNaN(maxValue)) maxValue = (1 << bitsPerSample) - 1;
         /*
          * All of tile width, height and length information should be provided. But if only one of them is missing,
          * we can compute it provided that the file does not use any compression method. If there is a compression,
@@ -994,6 +999,8 @@ final class ImageFileDirectory {
         if (compression != null) {
             metadata.addCompression(compression.name().toLowerCase(locale));
         }
+        // TODO: set band name and repeat for each band.
+        metadata.setBitPerSample(bitsPerSample);
         metadata.addMinimumSampleValue(minValue);
         metadata.addMaximumSampleValue(maxValue);
         /*

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=1798041&r1=1798040&r2=1798041&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] Thu Jun  8 10:45:14 2017
@@ -34,6 +34,7 @@ import javax.measure.UnitConverter;
 import javax.measure.IncommensurableException;
 import javax.measure.format.ParserException;
 
+import org.opengis.util.CodeList;
 import org.opengis.util.NameFactory;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Metadata;
@@ -46,13 +47,10 @@ import org.opengis.metadata.maintenance.
 import org.opengis.metadata.constraint.Restriction;
 import org.opengis.referencing.crs.VerticalCRS;
 
-import org.opengis.util.CodeList;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.iso.DefaultIdentifier;
 import org.apache.sis.metadata.iso.spatial.*;
-import org.apache.sis.metadata.iso.content.*;
 import org.apache.sis.metadata.iso.citation.*;
 import org.apache.sis.metadata.iso.identification.*;
 import org.apache.sis.metadata.iso.lineage.DefaultLineage;
@@ -63,6 +61,7 @@ import org.apache.sis.internal.netcdf.Va
 import org.apache.sis.internal.netcdf.GridGeometry;
 import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.measure.Units;
@@ -184,9 +183,8 @@ final class MetadataReader extends Metad
      * Creates a new <cite>NetCDF to ISO</cite> mapper for the given source.
      *
      * @param  decoder  the source of NetCDF attributes.
-     * @throws IOException if an I/O operation was necessary but failed.
      */
-    MetadataReader(final Decoder decoder) throws IOException {
+    MetadataReader(final Decoder decoder) {
         this.decoder = decoder;
         decoder.setSearchPath(SEARCH_PATH);
         searchPath = decoder.getSearchPath();
@@ -251,11 +249,10 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
-     * Reads the attribute value for the given name, then trims the leading and trailing spaces.
-     * If the value is null, empty or contains only spaces, then this method returns {@code null}.
+     * Trims the leading and trailing spaces of the given string.
+     * If the string is null, empty or contains only spaces, then this method returns {@code null}.
      */
-    private String stringValue(final String name) throws IOException {
-        String value = decoder.stringValue(name);
+    private static String trim(String value) {
         if (value != null) {
             value = value.trim();
             if (value.isEmpty()) {
@@ -266,6 +263,14 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
+     * Reads the attribute value for the given name, then trims the leading and trailing spaces.
+     * If the value is null, empty or contains only spaces, then this method returns {@code null}.
+     */
+    private String stringValue(final String name) {
+        return trim(decoder.stringValue(name));
+    }
+
+    /**
      * Returns the enumeration constant for the given name, or {@code null} if the given name is not recognized.
      * In the later case, this method emits a warning.
      */
@@ -420,15 +425,12 @@ split:  while ((start = CharSequences.sk
      * @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}.
      * @return the responsible party, or {@code null} if none.
-     * @throws IOException if an I/O operation was necessary but failed.
      *
      * @see AttributeNames#CREATOR
      * @see AttributeNames#CONTRIBUTOR
      * @see AttributeNames#PUBLISHER
      */
-    private Responsibility createResponsibleParty(final Responsible keys, final boolean isPointOfContact)
-            throws IOException
-    {
+    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);
@@ -510,10 +512,9 @@ split:  while ((start = CharSequences.sk
      * <p>This method opportunistically collects the name of all publishers.
      * Those names are useful to {@link #addIdentificationInfo(Set)}.</p>
      *
-     * @throws IOException if an I/O operation was necessary but failed.
      * @return the name of all publishers, or {@code null} if none.
      */
-    private Set<InternationalString> addCitation() throws IOException {
+    private Set<InternationalString> addCitation() {
         String title = stringValue(TITLE);
         if (title == null) {
             title = stringValue("full_name");   // THREDDS attribute documented in TITLE javadoc.
@@ -582,9 +583,8 @@ split:  while ((start = CharSequences.sk
      * Adds a {@code DataIdentification} element if at least one of the required attributes is non-null.
      *
      * @param  publisher   the publisher names, built by the caller in an opportunist way.
-     * @throws IOException if an I/O operation was necessary but failed.
      */
-    private void addIdentificationInfo(final Set<InternationalString> publisher) throws IOException {
+    private void addIdentificationInfo(final Set<InternationalString> publisher) {
         boolean     hasExtent = false;
         Set<String> project   = null;
         Set<String> standard  = null;
@@ -629,9 +629,8 @@ split:  while ((start = CharSequences.sk
      *
      * @param  cs  the grid geometry (related to the NetCDF coordinate system).
      * @return the grid spatial representation info.
-     * @throws IOException if an I/O operation was necessary but failed.
      */
-    private GridSpatialRepresentation createSpatialRepresentationInfo(final GridGeometry cs) throws IOException {
+    private GridSpatialRepresentation createSpatialRepresentationInfo(final GridGeometry cs) {
         final DefaultGridSpatialRepresentation grid = new DefaultGridSpatialRepresentation();
         grid.setNumberOfDimensions(cs.getTargetDimensions());
         final Axis[] axes = cs.getAxes();
@@ -661,7 +660,7 @@ split:  while ((start = CharSequences.sk
      *
      * @return {@code true} if at least one numerical value has been added.
      */
-    private boolean addExtent() throws IOException {
+    private boolean addExtent() {
         addExtent(stringValue(GEOGRAPHIC_IDENTIFIER));
         /*
          * If at least one geographic ordinates is available, add a GeographicBoundingBox.
@@ -755,108 +754,87 @@ split:  while ((start = CharSequences.sk
     }
 
     /**
-     * Creates a {@code <gmd:contentInfo>} elements from all applicable NetCDF attributes.
-     *
-     * @return the content information.
-     * @throws IOException if an I/O operation was necessary but failed.
+     * Adds information about all NetCDF variables. This is the {@code <gmd:contentInfo>} elements in GML.
+     * This method groups variables by their domains, i.e. variables having the same set of axes are grouped together.
      */
-    private Collection<DefaultCoverageDescription> createContentInfo() throws IOException {
-        final Map<List<String>, DefaultCoverageDescription> contents = new HashMap<>(4);
-        final String processingLevel = stringValue(PROCESSING_LEVEL);
+    private void addContentInfo() {
+        final Map<List<String>, List<Variable>> contents = new HashMap<>(4);
         for (final Variable variable : decoder.getVariables()) {
-            if (!variable.isCoverage(2)) {
-                continue;
+            if (variable.isCoverage(2)) {
+                final List<String> dimensions = Arrays.asList(variable.getGridDimensionNames());
+                CollectionsExt.addToMultiValuesMap(contents, dimensions, variable);
             }
-            DefaultAttributeGroup group = null;
+        }
+        final String processingLevel = stringValue(PROCESSING_LEVEL);
+        for (final List<Variable> group : contents.values()) {
             /*
              * Instantiate a CoverageDescription for each distinct set of NetCDF dimensions
              * (e.g. longitude,latitude,time). This separation is based on the fact that a
              * coverage has only one domain for every range of values.
              */
-            final List<String> dimensions = Arrays.asList(variable.getGridDimensionNames());
-            DefaultCoverageDescription content = contents.get(dimensions);
-            if (content == null) {
-                /*
-                 * If there is some NetCDF attributes that can be stored only in the ImageDescription
-                 * subclass, instantiate that subclass. Otherwise instantiate the more generic class.
-                 */
-                if (processingLevel != null) {
-                    content = new DefaultImageDescription();
-                    content.setProcessingLevelCode(new DefaultIdentifier(processingLevel));
-                } else {
-                    content = new DefaultCoverageDescription();
-                }
-                contents.put(dimensions, content);
-            } else {
-                group = (DefaultAttributeGroup) first(content.getAttributeGroups());
-            }
-            if (group == null) {
-                group = new DefaultAttributeGroup();
-                content.setAttributeGroups(singleton(group));
-            }
-            group.getAttributes().add(createSampleDimension(variable));
-            final Object[] names    = variable.getAttributeValues(FLAG_NAMES,    false);
-            final Object[] meanings = variable.getAttributeValues(FLAG_MEANINGS, false);
-            final Object[] masks    = variable.getAttributeValues(FLAG_MASKS,    true);
-            final Object[] values   = variable.getAttributeValues(FLAG_VALUES,   true);
-            final int length = Math.max(masks.length, Math.max(values.length, Math.max(names.length, meanings.length)));
-            for (int i=0; i<length; i++) {
-                final RangeElementDescription element = createRangeElementDescription(variable,
-                        (i < names   .length) ? (String) names   [i] : null,
-                        (i < meanings.length) ? (String) meanings[i] : null,
-                        (i < masks   .length) ? (Number) masks   [i] : null,
-                        (i < values  .length) ? (Number) values  [i] : null);
-                if (element != null) {
-                    content.getRangeElementDescriptions().add(element);
+            newCoverage(false);
+            setProcessingLevelCode(null, processingLevel);
+            for (final Variable variable : group) {
+                addSampleDimension(variable);
+                final Object[] names    = variable.getAttributeValues(FLAG_NAMES,    false);
+                final Object[] meanings = variable.getAttributeValues(FLAG_MEANINGS, false);
+                final Object[] masks    = variable.getAttributeValues(FLAG_MASKS,    true);
+                final Object[] values   = variable.getAttributeValues(FLAG_VALUES,   true);
+                final int length = Math.max(masks.length, Math.max(values.length, Math.max(names.length, meanings.length)));
+                for (int i=0; i<length; i++) {
+                    addSampleValueDescription(variable,
+                            (i < names   .length) ? (String) names   [i] : null,
+                            (i < meanings.length) ? (String) meanings[i] : null,
+                            (i < masks   .length) ? (Number) masks   [i] : null,
+                            (i < values  .length) ? (Number) values  [i] : null);
                 }
             }
         }
-        return contents.values();
     }
 
     /**
-     * Creates a {@code <gmd:dimension>} element from the given variable.
+     * Adds metadata about a sample dimension (or band) from the given variable.
+     * This is the {@code <gmd:dimension>} element in GML.
      *
      * @param  variable  the NetCDF variable.
-     * @return the sample dimension information.
-     * @throws IOException if an I/O operation was necessary but failed.
      */
-    private Band createSampleDimension(final Variable variable) throws IOException {
-        final DefaultBand band = new DefaultBand();     // TODO: not necessarily a band.
-        String name = variable.getName();
-        if (name != null && !(name = name.trim()).isEmpty()) {
+    private void addSampleDimension(final Variable variable) {
+        newSampleDimension();
+        final String name = trim(variable.getName());
+        if (name != null) {
             if (nameFactory == null) {
                 nameFactory = DefaultFactories.forBuildin(NameFactory.class);
                 // Real dependency injection to be used in a future version.
             }
-            band.setSequenceIdentifier(nameFactory.createMemberName(null, name,
+            setBandIdentifier(nameFactory.createMemberName(null, name,
                     nameFactory.createTypeName(null, variable.getDataTypeName())));
         }
-        String description = variable.getDescription();
-        if (description != null && !(description = description.trim()).isEmpty() && !description.equals(name)) {
-            band.setDescription(new SimpleInternationalString(description));
+        Object[] v = variable.getAttributeValues(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);
+        }
+        final String description = trim(variable.getDescription());
+        if (description != null && !description.equals(name) && !description.equals(id)) {
+            addBandDescription(description);
         }
         final String units = variable.getUnitsString();
         if (units != null) try {
-            band.setUnits(Units.valueOf(units));
+            setSampleUnits(Units.valueOf(units));
         } catch (ParserException e) {
             decoder.listeners.warning(errors().getString(Errors.Keys.CanNotAssignUnitToDimension_2, name, units), e);
         }
-        Object[] v = variable.getAttributeValues(CDM.SCALE_FACTOR, true);
-        if (v.length == 1) {
-            band.setScaleFactor(((Number) v[0]).doubleValue());
-            band.setTransferFunctionType(TransferFunctionType.LINEAR);
-        }
-        v = variable.getAttributeValues(CDM.ADD_OFFSET, true);
-        if (v.length == 1) {
-            band.setOffset(((Number) v[0]).doubleValue());
-            band.setTransferFunctionType(TransferFunctionType.LINEAR);
-        }
-        return band;
+        double scale  = Double.NaN;
+        double offset = Double.NaN;
+        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);
     }
 
     /**
-     * Creates a {@code <gmd:rangeElementDescription>} elements from the given information.
+     * Adds metadata about the meaning of a sample value.
+     * This is the {@code <gmd:rangeElementDescription>} element in GML.
      *
      * <p><b>Note:</b> ISO 19115 range elements are approximatively equivalent to
      * {@code org.apache.sis.coverage.Category} in the {@code sis-coverage} module.</p>
@@ -866,21 +844,13 @@ split:  while ((start = CharSequences.sk
      * @param  meaning   one of the elements in the {@link AttributeNames#FLAG_MEANINGS} attribute or {@code null}.
      * @param  mask      one of the elements in the {@link AttributeNames#FLAG_MASKS} attribute or {@code null}.
      * @param  value     one of the elements in the {@link AttributeNames#FLAG_VALUES} attribute or {@code null}.
-     * @return the sample dimension information or {@code null} if none.
-     * @throws IOException if an I/O operation was necessary but failed.
      */
-    private RangeElementDescription createRangeElementDescription(final Variable variable,
-            final String name, final String meaning, final Number mask, final Number value) throws IOException
+    private void addSampleValueDescription(final Variable variable,
+            final String name, final String meaning, final Number mask, final Number value)
     {
-        if (name != null && meaning != null) {
-            final DefaultRangeElementDescription element = new DefaultRangeElementDescription();
-            element.setName(new SimpleInternationalString(name));
-            element.setDefinition(new SimpleInternationalString(meaning));
-            // TODO: create a record from values (and possibly from the masks).
-            //       if (pixel & mask == value) then we have that range element.
-            return element;
-        }
-        return null;
+        addSampleValueDescription(name, meaning);
+        // TODO: create a record from values (and possibly from the masks).
+        //       if (pixel & mask == value) then we have that range element.
     }
 
     /**
@@ -891,10 +861,8 @@ split:  while ((start = CharSequences.sk
      *   <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>
      * </ul>
-     *
-     * @throws IOException if an I/O operation was necessary but failed.
      */
-    private void addFileIdentifier() throws IOException {
+    private void addFileIdentifier() {
         String identifier = stringValue(IDENTIFIER);
         if (identifier == null) {
             identifier = decoder.getId();
@@ -902,8 +870,7 @@ split:  while ((start = CharSequences.sk
                 return;
             }
         }
-        final String namespace = stringValue(NAMING_AUTHORITY);
-        addIdentifier((namespace != null) ? new DefaultCitation(namespace) : null, identifier, Scope.ALL);
+        addIdentifier(stringValue(NAMING_AUTHORITY), identifier, Scope.ALL);
     }
 
     /**
@@ -923,6 +890,7 @@ split:  while ((start = CharSequences.sk
                 addResourceScope(ScopeCode.SERVICE, name);
             }
         }
+        addContentInfo();
         /*
          * Add history in Metadata.dataQualityInfo.lineage.statement as specified by UnidataDD2MI.xsl.
          * However Metadata.resourceLineage.statement could be a more appropriate place.
@@ -941,7 +909,6 @@ split:  while ((start = CharSequences.sk
             }
         }
         decoder.setSearchPath(searchPath);
-        metadata.setContentInfo(createContentInfo());
         /*
          * Add the dimension information, if any. This metadata node
          * is built from the NetCDF CoordinateSystem objects.

Modified: sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java?rev=1798041&r1=1798040&r2=1798041&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] Thu Jun  8 10:45:14 2017
@@ -142,7 +142,8 @@ public final strictfp class MetadataRead
             "  │   └─Attribute group\n" +
             "  │       └─Attribute…………………………………………………………………… SST\n" +
             "  │           ├─Units…………………………………………………………………… K\n" +
-            "  │           └─Description…………………………………………………… Sea temperature\n" +
+            "  │           ├─Description…………………………………………………… Sea temperature\n" +
+            "  │           └─Name……………………………………………………………………… sea_water_temperature\n" +
             "  ├─Data quality info\n" +
             "  │   ├─Scope\n" +
             "  │   │   └─Level……………………………………………………………………………… Dataset\n" +

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/FeatureCatalogBuilder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/FeatureCatalogBuilder.java?rev=1798041&r1=1798040&r2=1798041&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/FeatureCatalogBuilder.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/FeatureCatalogBuilder.java [UTF-8] Thu Jun  8 10:45:14 2017
@@ -28,8 +28,8 @@ import org.opengis.feature.FeatureType;
 
 /**
  * Helper methods for the feature metadata created by {@code DataStore} implementations.
- * This is a convenience class for chaining {@link #add(FeatureType, Integer)} method calls
- * with {@link FeatureNaming#add(DataStore, GenericName, Object)}.
+ * This is a convenience class for chaining {@link #addFeatureType(FeatureType, Integer)}
+ * method calls with {@link FeatureNaming#add(DataStore, GenericName, Object)}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
@@ -74,10 +74,10 @@ public class FeatureCatalogBuilder exten
      * @param  type  the feature type to add, or {@code null}.
      * @throws IllegalNameException if a feature of the same name has already been added.
      *
-     * @see #add(FeatureType, Integer)
+     * @see #addFeatureType(FeatureType, Integer)
      */
     public final void define(final FeatureType type) throws IllegalNameException {
-        final GenericName name = add(type, null);
+        final GenericName name = addFeatureType(type, null);
         if (name != null) {
             features.add(store, name, type);
         }

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=1798041&r1=1798040&r2=1798041&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] Thu Jun  8 10:45:14 2017
@@ -25,6 +25,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 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.metadata.Identifier;
@@ -39,6 +41,7 @@ import org.opengis.metadata.spatial.Cell
 import org.opengis.metadata.spatial.PixelOrientation;
 import org.opengis.metadata.spatial.SpatialRepresentationType;
 import org.opengis.metadata.constraint.Restriction;
+import org.opengis.metadata.content.TransferFunctionType;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.acquisition.Context;
 import org.opengis.metadata.acquisition.OperationType;
@@ -64,6 +67,7 @@ import org.apache.sis.metadata.iso.conte
 import org.apache.sis.metadata.iso.content.DefaultSampleDimension;
 import org.apache.sis.metadata.iso.content.DefaultCoverageDescription;
 import org.apache.sis.metadata.iso.content.DefaultFeatureCatalogueDescription;
+import org.apache.sis.metadata.iso.content.DefaultRangeElementDescription;
 import org.apache.sis.metadata.iso.content.DefaultImageDescription;
 import org.apache.sis.metadata.iso.content.DefaultFeatureTypeInfo;
 import org.apache.sis.metadata.iso.citation.AbstractParty;
@@ -134,13 +138,19 @@ public class MetadataBuilder {
     private boolean electromagnetic;
 
     /**
-     * For using the same instance of {@code Double} when the value is the same.
-     * We use this map because the same values appear many time in a Landsat file.
-     *
-     * @see #shared(Integer)
-     * @see #shared(Double)
+     * For using the same instance of {@code Integer} or {@code Double} when the value is the same.
+     * Also used for reusing {@link Citation} instances already created for a given title.
+     * Keys and values can be:
+     *
+     * <table class="sis">
+     *   <tr><th>Key</th>                          <th>Value</th>               <th>Method</th></tr>
+     *   <tr><td>{@link Integer}</td>              <td>{@link Integer}</td>     <td>{@link #shared(Integer)}</td></tr>
+     *   <tr><td>{@link Double}</td>               <td>{@link Double}</td>      <td>{@link #shared(Double)}</td></tr>
+     *   <tr><td>{@link Identifier}</td>           <td>{@link Identifier}</td>  <td>{@link #sharedIdentifier(CharSequence, String)}</td></tr>
+     *   <tr><td>{@link InternationalString}</td>  <td>{@link Citation}</td>    <td>{@link #sharedCitation(InternationalString)}</td></tr>
+     * </table>
      */
-    private final Map<Number,Number> sharedNumbers = new HashMap<>();
+    private final Map<Object,Object> sharedValues = new HashMap<>();
 
     // Other fields declared below together with closely related methods.
 
@@ -383,6 +393,7 @@ public class MetadataBuilder {
      * Creates the sample dimension object if it does not already exists, then returns it.
      *
      * @return the sample dimension (never {@code null}).
+     * @see #newSampleDimension()
      */
     private DefaultSampleDimension sampleDimension() {
         if (sampleDimension == null) {
@@ -660,10 +671,7 @@ public class MetadataBuilder {
      *         will be a description of measurements in the electromagnetic spectrum.
      */
     public final void newCoverage(final boolean electromagnetic) {
-        if (sampleDimension != null) {
-            addIfNotPresent(attributeGroup().getAttributes(), sampleDimension);
-            sampleDimension = null;
-        }
+        newSampleDimension();
         if (attributeGroup != null) {
             addIfNotPresent(coverageDescription().getAttributeGroups(), attributeGroup);
             attributeGroup = null;
@@ -676,6 +684,20 @@ public class MetadataBuilder {
     }
 
     /**
+     * Commits all pending information under the coverage "attribute group" node.
+     * If there is no pending sample dimension description, then invoking this method has no effect.
+     * If new sample dimensions are added after this method call, they will be stored in a new element.
+     *
+     * <p>This method does not need to be invoked unless a new "sample dimension" node is desired.</p>
+     */
+    public final void newSampleDimension() {
+        if (sampleDimension != null) {
+            addIfNotPresent(attributeGroup().getAttributes(), sampleDimension);
+            sampleDimension = null;
+        }
+    }
+
+    /**
      * Commits all pending information under the metadata "spatial representation" node (dimensions, <i>etc</i>).
      * If there is no pending spatial representation information, then invoking this method has no effect.
      * If new spatial representation info are added after this method call, they will be stored in a new element.
@@ -718,6 +740,33 @@ public class MetadataBuilder {
     }
 
     /**
+     * Creates or fetches a citation for the given title. The same citation may be shared by many metadata objects,
+     * for example identifiers or groups of keywords. Current implementation creates a {@link DefaultCitation} for
+     * the given title and caches the result. Future implementations may return predefined citation constants from
+     * the SQL database when applicable.
+     *
+     * @param  title  the citation title, or {@code null} if none.
+     * @return a (potentially shared) citation for the given title, or {@code null} if the given title was null.
+     */
+    private Citation sharedCitation(final InternationalString title) {
+        if (title == null) return null;
+        return (Citation) sharedValues.computeIfAbsent(title, k -> new DefaultCitation((CharSequence) k));
+    }
+
+    /**
+     * Creates or fetches an identifier for the given authority and code. This method may query the metadata
+     * database for fetching a more complete {@link Citation} for the given {@code authority}.
+     * This method may return a shared {@code Identifier} instance.
+     *
+     * @param  authority  the authority tile, or {@code null} if none.
+     * @param  code       the identifier code (mandatory).
+     */
+    private Identifier sharedIdentifier(final CharSequence authority, final String code) {
+        final DefaultIdentifier id = new DefaultIdentifier(sharedCitation(trim(authority)), code);
+        return (Identifier) sharedValues.getOrDefault(id, id);
+    }
+
+    /**
      * Specify if an information apply to data, to metadata or to both.
      * This is used for setting the locale or character encoding.
      */
@@ -755,10 +804,10 @@ public class MetadataBuilder {
      *
      * @see #addTitle(CharSequence)
      */
-    public final void addIdentifier(final Citation authority, String code, final Scope scope) {
+    public final void addIdentifier(final CharSequence authority, String code, final Scope scope) {
         ArgumentChecks.ensureNonNull("scope", scope);
         if (code != null && !(code = code.trim()).isEmpty()) {
-            final DefaultIdentifier id = new DefaultIdentifier(authority, code);
+            final Identifier id = sharedIdentifier(authority, code);
             if (scope != Scope.RESOURCE) metadata().setMetadataIdentifier(id);
             if (scope != Scope.METADATA) addIfNotPresent(citation().getIdentifiers(), id);
         }
@@ -1097,9 +1146,7 @@ public class MetadataBuilder {
                         group = new DefaultKeywords();
                         group.setType(type);
                         final InternationalString c = trim(thesaurusName);
-                        if (c != null) {
-                            group.setThesaurusName(new DefaultCitation(c));
-                        }
+                        group.setThesaurusName(sharedCitation(c));
                         list = group.getKeywords();
                     }
                     list.add(i18n);
@@ -1627,7 +1674,7 @@ parse:      for (int i = 0; i < length;)
      *
      * @see FeatureCatalogBuilder#define(FeatureType)
      */
-    public final GenericName add(final FeatureType type, final Integer occurrences) {
+    public final GenericName addFeatureType(final FeatureType type, final Integer occurrences) {
         if (type != null) {
             final GenericName name = type.getName();
             if (name != null) {
@@ -1771,8 +1818,94 @@ parse:      for (int i = 0; i < length;)
     }
 
     /**
+     * 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.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/sequenceIdentifier}</li>
+     * </ul>
+     *
+     * @param  sequenceIdentifier  the band name or number, or {@code null} for no-operation.
+     */
+    public final void setBandIdentifier(final MemberName sequenceIdentifier) {
+        if (sequenceIdentifier != null) {
+            sampleDimension().setSequenceIdentifier(sequenceIdentifier);
+        }
+    }
+
+    /**
+     * Adds an identifier for the current band.
+     * These identifiers can be use to provide names for the attribute from a standard set of names.
+     * If a coverage contains more than one band, additional bands can be created by calling
+     * {@link #newSampleDimension()} before to call this method.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/name}</li>
+     * </ul>
+     *
+     * @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) {
+        if (name != null && !(name = name.trim()).isEmpty()) {
+            addIfNotPresent(sampleDimension().getNames(), sharedIdentifier(authority, name));
+        }
+    }
+
+    /**
+     * Adds a description of the current band.
+     * If a coverage contains more than one band, additional bands can be created by calling
+     * {@link #newSampleDimension()} before to call this method.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/description}</li>
+     * </ul>
+     *
+     * @param  description  the band description, or {@code null} for no-operation.
+     */
+    public final void addBandDescription(final CharSequence description) {
+        final InternationalString i18n = trim(description);
+        if (i18n != null) {
+            final DefaultSampleDimension sampleDimension = sampleDimension();
+            sampleDimension.setDescription(append(sampleDimension.getDescription(), i18n));
+        }
+    }
+
+    /**
+     * Adds a description of a particular sample value.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/rangeElementDescription}</li>
+     * </ul>
+     *
+     * <div class="note"><b>Note:</b>
+     * ISO 19115 range elements are approximatively equivalent to
+     * {@code org.apache.sis.coverage.Category} in the {@code sis-coverage} module.</div>
+     *
+     * @param  name        designation associated with a set of range elements, or {@code null} if none.
+     * @param  definition  description of a set of specific range elements, or {@code null} if none.
+     */
+    public void addSampleValueDescription(final CharSequence name, final CharSequence definition) {
+        final InternationalString i18n = trim(name);
+        final InternationalString def  = trim(definition);
+        if (i18n != null && def != null) {
+            final DefaultRangeElementDescription element = new DefaultRangeElementDescription();
+            element.setName(i18n);
+            element.setDefinition(def);
+            addIfNotPresent(coverageDescription().getRangeElementDescriptions(), element);
+        }
+    }
+
+    /**
      * Adds a minimal value for the current sample dimension. If a minimal value was already defined, then
      * the new value will be set only if it is smaller than the existing one. {@code NaN} values are ignored.
+     * If a coverage contains more than one band, additional bands can be created by calling
+     * {@link #newSampleDimension()} before to call this method.
      * Storage location is:
      *
      * <ul>
@@ -1794,6 +1927,8 @@ parse:      for (int i = 0; i < length;)
     /**
      * Adds a maximal value for the current sample dimension. If a maximal value was already defined, then
      * the new value will be set only if it is greater than the existing one. {@code NaN} values are ignored.
+     * If a coverage contains more than one band, additional bands can be created by calling
+     * {@link #newSampleDimension()} before to call this method.
      * Storage location is:
      *
      * <ul>
@@ -1813,6 +1948,85 @@ parse:      for (int i = 0; i < length;)
     }
 
     /**
+     * Sets the units of data in the current band.
+     * If a coverage contains more than one band, additional bands can be created by calling
+     * {@link #newSampleDimension()} before to call this method.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/unit}</li>
+     * </ul>
+     *
+     * @param  unit  units of measurement of sample values.
+     */
+    public final void setSampleUnits(final Unit<?> unit) {
+        if (unit != null) {
+            sampleDimension().setUnits(unit);
+        }
+    }
+
+    /**
+     * Sets the scale factor and offset which have been applied to the cell value.
+     * The transfer function type is declared {@linkplain TransferFunctionType#LINEAR linear}
+     * If a coverage contains more than one band, additional bands can be created by calling
+     * {@link #newSampleDimension()} before to call this method.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/scale}</li>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/offset}</li>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/transferFunctionType}</li>
+     * </ul>
+     *
+     * @param scale   the scale factor which has been applied to the cell value.
+     * @param offset  the physical value corresponding to a cell value of zero.
+     */
+    public final void setTransferFunction(final double scale, final double offset) {
+        if (!Double.isNaN(scale) || !Double.isNaN(offset)) {
+            final DefaultSampleDimension sd = sampleDimension();
+            if (!Double.isNaN(scale))  sd.setScaleFactor(scale);
+            if (!Double.isNaN(offset)) sd.setOffset(offset);
+            sd.setTransferFunctionType(TransferFunctionType.LINEAR);
+        }
+    }
+
+    /**
+     * Sets the maximum number of significant bits in the uncompressed representation for the value in current band.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/attributeGroup/attribute/bitsPerValue}</li>
+     * </ul>
+     *
+     * @param  bits  the new maximum number of significant bits.
+     * @throws IllegalArgumentException if the given value is zero or negative.
+     */
+    public final void setBitPerSample(final int bits) {
+        sampleDimension().setBitsPerValue(bits);
+    }
+
+    /**
+     * Sets an identifier for the level of processing that has been applied to the coverage.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/contentInfo/processingLevelCode}</li>
+     * </ul>
+     *
+     * @param  authority        identifies which controlled list of code is used, or {@code null} if none.
+     * @param  processingLevel  identifier for the level of processing that has been applied to the resource,
+     *                          or {@code null} for no-operation.
+     */
+    public final void setProcessingLevelCode(final CharSequence authority, String processingLevel) {
+        if (processingLevel != null) {
+            processingLevel = processingLevel.trim();
+            if (!processingLevel.isEmpty()) {
+                coverageDescription().setProcessingLevelCode(sharedIdentifier(authority, processingLevel));
+            }
+        }
+    }
+
+    /**
      * Sets the area of the dataset obscured by clouds, expressed as a percentage of the spatial extent.
      * This method does nothing if the given value is {@link Double#NaN}.
      *
@@ -1884,9 +2098,10 @@ parse:      for (int i = 0; i < length;)
      *   <li>{@code metadata/acquisitionInformation/platform/identifier}</li>
      * </ul>
      *
+     * @param  authority   identifiers the authority that define platform codes, or {@code null} if none.
      * @param  identifier  identifier of the platform to add, or {@code null} for no-operation.
      */
-    public final void addPlatform(String identifier) {
+    public final void addPlatform(final CharSequence authority, String identifier) {
         if (identifier != null && !(identifier = identifier.trim()).isEmpty()) {
             if (platform != null) {
                 final Identifier current = platform.getIdentifier();
@@ -1898,7 +2113,7 @@ parse:      for (int i = 0; i < length;)
                     platform = null;
                 }
             }
-            platform().setIdentifier(new DefaultIdentifier(identifier));
+            platform().setIdentifier(sharedIdentifier(authority, identifier));
         }
     }
 
@@ -1910,12 +2125,13 @@ parse:      for (int i = 0; i < length;)
      *   <li>{@code metadata/acquisitionInformation/platform/instrument/identifier}</li>
      * </ul>
      *
+     * @param  authority   identifiers the authority that define instrument codes, or {@code null} if none.
      * @param  identifier  identifier of the sensor to add, or {@code null} for no-operation.
      */
-    public final void addInstrument(String identifier) {
+    public final void addInstrument(final CharSequence authority, String identifier) {
         if (identifier != null && !(identifier = identifier.trim()).isEmpty()) {
             final DefaultInstrument instrument = new DefaultInstrument();
-            instrument.setIdentifier(new DefaultIdentifier(identifier));
+            instrument.setIdentifier(sharedIdentifier(authority, identifier));
             addIfNotPresent(platform().getInstruments(), instrument);
         }
     }
@@ -1953,12 +2169,13 @@ parse:      for (int i = 0; i < length;)
      *   <li>{@code metadata/acquisitionInformation/acquisitionRequirement/identifier}</li>
      * </ul>
      *
+     * @param  authority   specifies the authority that define requirement codes, or {@code null} if none.
      * @param  identifier  unique name or code for the requirement, or {@code null} for no-operation.
      */
-    public final void addAcquisitionRequirement(String identifier) {
+    public final void addAcquisitionRequirement(final CharSequence authority, String identifier) {
         if (identifier != null && !(identifier = identifier.trim()).isEmpty()) {
             final DefaultRequirement r = new DefaultRequirement();
-            r.setIdentifier(new DefaultIdentifier(identifier));
+            r.setIdentifier(sharedIdentifier(authority, identifier));
             addIfNotPresent(acquisition().getAcquisitionRequirements(), r);
         }
     }
@@ -1972,12 +2189,13 @@ parse:      for (int i = 0; i < length;)
      *   <li>{@code metadata/resourceLineage/processStep/processingInformation/identifier}</li>
      * </ul>
      *
+     * @param  authority   identifies the authority that defines processing code, or {@code null} if none.
      * @param  identifier  processing package that produced the data, or {@code null} for no-operation.
      *
      * @see #addSoftwareReference(CharSequence)
      * @see #addHostComputer(CharSequence)
      */
-    public final void addProcessing(String identifier) {
+    public final void addProcessing(final CharSequence authority, String identifier) {
         if (identifier != null && !(identifier = identifier.trim()).isEmpty()) {
             if (processing != null) {
                 final Identifier current = processing.getIdentifier();
@@ -1991,13 +2209,13 @@ parse:      for (int i = 0; i < length;)
                     processStep = null;
                 }
             }
-            processing().setIdentifier(new DefaultIdentifier(identifier));
+            processing().setIdentifier(sharedIdentifier(authority, identifier));
         }
     }
 
     /**
      * Adds a reference to document describing processing software.
-     * This is added to the processing identified by last call to {@link #addProcessing(String)}.
+     * This is added to the processing identified by last call to {@link #addProcessing(CharSequence, String)}.
      * Storage location is:
      *
      * <ul>
@@ -2009,13 +2227,13 @@ parse:      for (int i = 0; i < length;)
     public final void addSoftwareReference(final CharSequence title) {
         final InternationalString i18n = trim(title);
         if (i18n != null) {
-            addIfNotPresent(processing().getSoftwareReferences(), new DefaultCitation(i18n));
+            addIfNotPresent(processing().getSoftwareReferences(), sharedCitation(i18n));
         }
     }
 
     /**
      * Adds information about the computer and/or operating system in use at the processing time.
-     * This is added to the processing identified by last call to {@link #addProcessing(String)}.
+     * This is added to the processing identified by last call to {@link #addProcessing(CharSequence, String)}.
      * Storage location is:
      *
      * <ul>
@@ -2104,7 +2322,7 @@ parse:      for (int i = 0; i < length;)
      * @return  the same value, but as an existing instance if possible.
      */
     public final Double shared(final Double value) {
-        final Number existing = sharedNumbers.putIfAbsent(value, value);
+        final Object existing = sharedValues.putIfAbsent(value, value);
         return (existing != null) ? (Double) existing : value;
     }
 
@@ -2117,7 +2335,7 @@ parse:      for (int i = 0; i < length;)
      * @return  the same value, but as an existing instance if possible.
      */
     public final Integer shared(final Integer value) {
-        final Number existing = sharedNumbers.putIfAbsent(value, value);
+        final Object existing = sharedValues.putIfAbsent(value, value);
         return (existing != null) ? (Integer) existing : value;
     }
 }

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java?rev=1798041&r1=1798040&r2=1798041&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] Thu Jun  8 10:45:14 2017
@@ -506,7 +506,7 @@ public final class Store extends Feature
                  */
                 listeners.warning(null, e);
             }
-            builder.add(featureType, null);
+            builder.addFeatureType(featureType, null);
             metadata = builder.build(true);
         }
         return metadata;



Mime
View raw message