sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1803070 [19/20] - in /sis/branches/JDK9: ./ application/sis-console/src/main/java/org/apache/sis/console/ core/sis-build-helper/ core/sis-build-helper/src/main/java/org/apache/sis/internal/book/ core/sis-build-helper/src/main/java/org/apac...
Date Wed, 26 Jul 2017 16:14:14 GMT
Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -149,6 +149,11 @@ public final class Resources extends Ind
         public static final short ProcessingExecutedOn_1 = 12;
 
         /**
+         * The “{1}” element must be declared before “{0}”.
+         */
+        public static final short ShallBeDeclaredBefore_2 = 22;
+
+        /**
          * Can not move backward in the “{0}” stream.
          */
         public static final short StreamIsForwardOnly_1 = 13;

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] Wed Jul 26 16:14:09 2017
@@ -36,6 +36,7 @@ IllegalOutputTypeForWriter_2      = The
 InconsistentNameComponents_2      = Components of the \u201c{1}\u201d name are inconsistent with those of the name previously binded in \u201c{0}\u201d data store.
 MissingSchemeInURI_1              = Missing scheme in \u201c{0}\u201d URI.
 ProcessingExecutedOn_1            = Processing executed on {0}.
+ShallBeDeclaredBefore_2           = The \u201c{1}\u201d element must be declared before \u201c{0}\u201d.
 StreamIsForwardOnly_1             = Can not move backward in the \u201c{0}\u201d stream.
 StreamIsReadOnce_1                = The \u201c{0}\u201d data store can be read only once.
 StreamIsWriteOnce_1               = Can not modify previously written data in \u201c{0}\u201d.

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] Wed Jul 26 16:14:09 2017
@@ -41,6 +41,7 @@ IllegalOutputTypeForWriter_2      = Le l
 InconsistentNameComponents_2      = Les \u00e9l\u00e9ments qui composent le nom \u00ab\u202f{1}\u202f\u00bb ne sont pas coh\u00e9rents avec ceux du nom qui avait \u00e9t\u00e9 pr\u00e9c\u00e9demment li\u00e9 dans les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb.
 MissingSchemeInURI_1              = Il manque le sch\u00e9ma dans l\u2019URI \u00ab\u202f{0}\u202f\u00bb.
 ProcessingExecutedOn_1            = Traitement ex\u00e9cut\u00e9 sur {0}.
+ShallBeDeclaredBefore_2           = L\u2019\u00e9l\u00e9ment \u00ab\u202f{1}\u202f\u00bb doit \u00eatre d\u00e9clar\u00e9 avant \u00ab\u202f{0}\u202f\u00bb.
 StreamIsForwardOnly_1             = Ne peut pas reculer dans le flux de donn\u00e9es \u00ab\u202f{0}\u202f\u00bb.
 StreamIsReadOnce_1                = Les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb ne peuvent \u00eatre lues qu\u2019une seule fois.
 StreamIsWriteOnce_1               = Ne peut pas revenir sur les donn\u00e9es d\u00e9j\u00e0 \u00e9crites dans \u00ab\u202f{0}\u202f\u00bb.

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -21,8 +21,10 @@ import org.apache.sis.util.CharSequences
 
 
 /**
- * The converter to use for converting a text into a geometry. In current implementation,
- * geometries are line strings represented by an array of ordinate values.
+ * The converter to use for converting a text into a geometry.
+ * This converter performs only the first step, the conversion to a {@code double[]} array.
+ * The second step (the conversion to a geometry object) is performed after we collected all arrays.
+ * The resulting geometry class depends on the library available at runtime.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
@@ -58,7 +60,7 @@ final class GeometryParser extends Surje
     }
 
     /**
-     * Converts an element from the CSV file to our current pseudo-geometry type.
+     * Converts an element from the CSV file to the array type.
      */
     @Override
     public double[] apply(final String text) {

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -18,7 +18,6 @@ package org.apache.sis.internal.storage.
 
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Locale;
@@ -43,12 +42,16 @@ import org.apache.sis.feature.DefaultFea
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.internal.storage.io.IOUtilities;
+import org.apache.sis.internal.storage.FeatureStore;
+import org.apache.sis.internal.feature.Geometries;
+import org.apache.sis.internal.feature.MovingFeature;
+import org.apache.sis.internal.storage.Resources;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.metadata.sql.MetadataStoreException;
-import org.apache.sis.internal.storage.FeatureStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.storage.DataStoreReferencingException;
@@ -57,17 +60,12 @@ import org.apache.sis.storage.StorageCon
 import org.apache.sis.setup.OptionKey;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.ObjectConverter;
-import org.apache.sis.util.ObjectConverters;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.measure.Units;
 
 // Branch-dependent imports
 import java.time.Instant;
 import java.time.DateTimeException;
-import java.util.function.Consumer;
-import java.util.Spliterator;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 import org.opengis.feature.Feature;
@@ -120,6 +118,8 @@ public final class Store extends Feature
 
     /**
      * The reader, set by the constructor and cleared when no longer needed.
+     *
+     * @see #readLine()
      */
     private BufferedReader source;
 
@@ -153,10 +153,27 @@ public final class Store extends Feature
 
     /**
      * {@code true} if {@link #featureType} contains a trajectory column.
+     * This field should be considered immutable after {@code Store} construction.
+     *
+     * @see #hasTrajectories()
      */
     private boolean hasTrajectories;
 
     /**
+     * The number of dimensions other than time in the coordinate reference system.
+     * Shall be 2 or 3 according Moving Features CSV encoding specification, but Apache SIS
+     * may be tolerant to other values (depending on the backing geometry library).
+     *
+     * @see #spatialDimensionCount()
+     */
+    private short spatialDimensionCount;
+
+    /**
+     * The factory to use for creating geometries.
+     */
+    final Geometries<?> geometries;
+
+    /**
      * Appearing order of trajectories (time or sequential), or {@code null} if unspecified.
      *
      * @see #parseFoliation(List)
@@ -165,20 +182,39 @@ public final class Store extends Feature
 
     /**
      * Specifies how time is encoded in the CSV file, or {@code null} if there is no time.
+     * This field should be considered immutable after {@code Store} construction.
+     *
+     * @see #timeEncoding()
      */
     private TimeEncoding timeEncoding;
 
     /**
+     * {@code true} if this reader should create a separated {@code Feature} instance for each line in the CSV file.
+     * By default, this is {@code true} if the CSV files does not seem to contain moving features.
+     * But the user can also force this value to {@code true}, for example for testing purposes.
+     */
+    private boolean dissociate;
+
+    /**
+     * All parsed moving features, or {@code null} if none or if not yet parsed. If {@link #dissociate}
+     * is {@code false}, then this list will be created by {@link #features(boolean)} when first needed.
+     */
+    private transient List<Feature> movingFeatures;
+
+    /**
      * Creates a new CSV store from the given file, URL or stream.
      *
      * <p>If the CSV file is known to be a Moving Feature file, then the given connector should
-     * have an {@link org.apache.sis.setup.OptionKey#ENCODING} associated to the UTF-8 value.</p>
+     * have an {@link org.apache.sis.setup.OptionKey#ENCODING} value set to UTF-8.</p>
      *
      * @param  provider   the factory that created this {@code DataStore} instance, or {@code null} if unspecified.
      * @param  connector  information about the storage (URL, stream, <i>etc</i>).
+     * @param  immediate  {@code true} for forcing the creation of a distinct {@code Feature} instance for each line.
      * @throws DataStoreException if an error occurred while opening the stream.
      */
-    public Store(final StoreProvider provider, final StorageConnector connector) throws DataStoreException {
+    public Store(final StoreProvider provider, final StorageConnector connector, final boolean immediate)
+            throws DataStoreException
+    {
         super(provider, connector);
         final Reader r = connector.getStorageAs(Reader.class);
         connector.closeAllExcept(r);
@@ -186,6 +222,8 @@ public final class Store extends Feature
             throw new DataStoreException(Errors.format(Errors.Keys.CanNotOpen_1, super.getDisplayName()));
         }
         source = (r instanceof BufferedReader) ? (BufferedReader) r : new LineNumberReader(r);
+        geometries = Geometries.implementation(connector.getOption(OptionKey.GEOMETRY_LIBRARY));
+        dissociate = immediate;
         GeneralEnvelope envelope    = null;
         FeatureType     featureType = null;
         Foliation       foliation   = null;
@@ -206,7 +244,12 @@ public final class Store extends Feature
                         if (envelope != null) {
                             throw new DataStoreContentException(duplicated("@stboundedby"));
                         }
-                        envelope = parseEnvelope(elements);
+                        if (featureType != null) {
+                            throw new DataStoreContentException(Resources.forLocale(getLocale())
+                                    .getString(Resources.Keys.ShallBeDeclaredBefore_2, "@columns", "@stboundedby"));
+                        }
+                        envelope = parseEnvelope(elements);     // Also set 'timeEncoding' and 'spatialDimensionCount'.
+                        dissociate |= (timeEncoding == null);   // Need to be updated before parseFeatureType(…) execution.
                         break;
                     }
                     case "@columns": {
@@ -236,16 +279,17 @@ public final class Store extends Feature
             }
             source.reset();
         } catch (IOException e) {
-            throw new DataStoreException(getLocale(), "CSV", super.getDisplayName(), source).initCause(e);
+            throw new DataStoreException(getLocale(), StoreProvider.NAME, super.getDisplayName(), source).initCause(e);
         } catch (FactoryException e) {
-            throw new DataStoreReferencingException(getLocale(), "CSV", super.getDisplayName(), source).initCause(e);
+            throw new DataStoreReferencingException(getLocale(), StoreProvider.NAME, super.getDisplayName(), source).initCause(e);
         } catch (IllegalArgumentException | DateTimeException e) {
-            throw new DataStoreContentException(getLocale(), "CSV", super.getDisplayName(), source).initCause(e);
+            throw new DataStoreContentException(getLocale(), StoreProvider.NAME, super.getDisplayName(), source).initCause(e);
         }
         this.encoding    = connector.getOption(OptionKey.ENCODING);
         this.envelope    = envelope;
         this.featureType = featureType;
         this.foliation   = foliation;
+        this.dissociate |= (timeEncoding == null);
     }
 
     /**
@@ -257,6 +301,8 @@ public final class Store extends Feature
      *   &#64;stboundedby, urn:ogc:def:crs:CRS:1.3:84, 2D, 50.23 9.23, 50.31 9.27, 2012-01-17T12:33:41Z, 2012-01-17T12:37:00Z, sec
      * }
      *
+     * This method sets {@link #timeEncoding} and {@link #spatialDimensionCount} as a side-effect.
+     *
      * @param  elements  the line elements. The first elements should be {@code "@stboundedby"}.
      * @return the envelope, or {@code null} if the given list does not contain enough elements.
      */
@@ -264,6 +310,7 @@ public final class Store extends Feature
     private GeneralEnvelope parseEnvelope(final List<String> elements) throws DataStoreException, FactoryException {
         CoordinateReferenceSystem crs = null;
         int spatialDimensionCount = 2;
+        boolean    isDimExplicit  = false;
         double[]   lowerCorner    = ArraysExt.EMPTY_DOUBLE;
         double[]   upperCorner    = ArraysExt.EMPTY_DOUBLE;
         Instant    startTime      = null;
@@ -278,8 +325,9 @@ public final class Store extends Feature
                     case 0: continue;                                       // The "@stboundedby" header.
                     case 1: crs = CRS.forCode(element); continue;
                     case 2: if (element.length() == 2 && Character.toUpperCase(element.charAt(1)) == 'D') {
+                                isDimExplicit = true;
                                 spatialDimensionCount = element.charAt(0) - '0';
-                                if (spatialDimensionCount < 2 || spatialDimensionCount > 3) {
+                                if (spatialDimensionCount < 1 || spatialDimensionCount > 3) {
                                     throw new DataStoreReferencingException(errors().getString(
                                         Errors.Keys.IllegalCoordinateSystem_1, element));
                                 }
@@ -326,12 +374,33 @@ public final class Store extends Feature
             int count = 0;
             final CoordinateReferenceSystem[] components = new CoordinateReferenceSystem[3];
             components[count++] = crs;
-
-            // If the coordinates are three-dimensional but the CRS is 2D, add a vertical axis.
-            if (spatialDimensionCount >= 3 && crs.getCoordinateSystem().getDimension() == 2) {
-                components[count++] = CommonCRS.Vertical.MEAN_SEA_LEVEL.crs();
+            /*
+             * If the coordinates are three-dimensional but the CRS is 2D, add a vertical axis.
+             * The vertical axis shall be the third one, however we do not enforce that rule
+             * since Apache SIS should work correctly even if the vertical axis is elsewhere.
+             */
+            int dimension = crs.getCoordinateSystem().getDimension();
+            if (isDimExplicit) {
+                if (spatialDimensionCount > dimension) {
+                    components[count++] = CommonCRS.Vertical.MEAN_SEA_LEVEL.crs();
+                    dimension++;
+                }
+                if (dimension != spatialDimensionCount) {
+                    throw new DataStoreReferencingException(errors().getString(
+                            Errors.Keys.MismatchedDimension_3, "@stboundedby(CRS)", spatialDimensionCount, dimension));
+                }
+            }
+            if (dimension > Short.MAX_VALUE) {
+                throw new DataStoreReferencingException(errors().getString(
+                        Errors.Keys.ExcessiveNumberOfDimensions_1, dimension));
             }
-            // Add a temporal axis if we have a start time (no need for end time).
+            spatialDimensionCount = dimension;
+            /*
+             * Add a temporal axis if we have a start time (no need for end time).
+             * This block presumes that the CRS does not already have a time axis.
+             * If a time axis was already present, an exception will be thrown at
+             * builder.createCompoundCRS(…) invocation time.
+             */
             final GeodeticObjectBuilder builder = new GeodeticObjectBuilder();
             String name = crs.getName().getCode();
             if (startTime != null) {
@@ -366,7 +435,7 @@ public final class Store extends Feature
             (dim = upperCorner.length) != spatialDimensionCount)
         {
             throw new DataStoreReferencingException(errors().getString(
-                    Errors.Keys.MismatchedDimension_2, dim, spatialDimensionCount));
+                    Errors.Keys.MismatchedDimension_3, "@stboundedby(BBOX)", spatialDimensionCount, dim));
         }
         for (int i=0; i<spatialDimensionCount; i++) {
             envelope.setRange(i, lowerCorner[i], upperCorner[i]);
@@ -375,6 +444,7 @@ public final class Store extends Feature
             envelope.setRange(spatialDimensionCount, timeEncoding.toCRS(startTime.toEpochMilli()),
                     (endTime == null) ? Double.NaN : timeEncoding.toCRS(endTime.toEpochMilli()));
         }
+        this.spatialDimensionCount = (short) spatialDimensionCount;
         return envelope;
     }
 
@@ -387,10 +457,15 @@ public final class Store extends Feature
      *   &#64;columns, mfidref, trajectory, state,xsd:token, "type code",xsd:integer
      * }
      *
-     * @param  elements  the line elements. The first elements should be {@code "@columns"}.
+     * This method needs {@link #timeEncoding} and {@link #dissociate} to be computed.
+     * This methods sets {@link #hasTrajectories} as a side-effect.
+     *
+     * @param  elements  the line elements. The first element should be {@code "@columns"}.
      * @return the column metadata, or {@code null} if the given list does not contain enough elements.
      */
+    @SuppressWarnings("rawtypes")               // "rawtypes" because of generic array creation.
     private FeatureType parseFeatureType(final List<String> elements) throws DataStoreException {
+        AttributeType[] characteristics = null;
         final int size = elements.size();
         final List<PropertyType> properties = new ArrayList<>();
         for (int i=1; i<size; i++) {
@@ -412,6 +487,7 @@ public final class Store extends Feature
                 }
             }
             int minOccurrence = 0;
+            int maxOccurrence = dissociate ? 1 : Integer.MAX_VALUE;
             if (type == null) {
                 /*
                  * If the column name was not followed by a type, default to a String type except in the special
@@ -426,22 +502,33 @@ public final class Store extends Feature
                  */
                 type = String.class;
                 switch (--i) {
-                    case 1: minOccurrence = 1; break;
-                    case 2: {
+                    case 0:                                             // "@column" (should not happen actually)
+                    case 1: {
+                        minOccurrence = 1;                              // "mfidref"
+                        maxOccurrence = 1;
+                        break;
+                    }
+                    case 2: {                                           // "trajectory" or property.
                         if (name.equalsIgnoreCase("trajectory")) {
                             hasTrajectories = true;
                             if (timeEncoding != null) {
-                                properties.add(createProperty("startTime", Instant.class, 1));
-                                properties.add(createProperty(  "endTime", Instant.class, 1));
+                                properties.add(createProperty("startTime", Instant.class, 1, 1, null));
+                                properties.add(createProperty(  "endTime", Instant.class, 1, 1, null));
+                            }
+                            if (dissociate) {
+                                type = double[].class;
+                            } else {
+                                type = geometries.polylineClass;
+                                characteristics = new AttributeType[] {MovingFeature.TIME};
                             }
-                            type = double[].class;
                             minOccurrence = 1;
+                            maxOccurrence = 1;
                         }
                         break;
                     }
                 }
             }
-            properties.add(createProperty(name, type, minOccurrence));
+            properties.add(createProperty(name, type, minOccurrence, maxOccurrence, characteristics));
         }
         String name = super.getDisplayName();
         final int s = name.lastIndexOf('.');
@@ -454,9 +541,13 @@ public final class Store extends Feature
 
     /**
      * Creates a property type for the given name and type.
+     * This is a helper method for {@link #parseFeatureType(List)}.
      */
-    private static PropertyType createProperty(final String name, final Class<?> type, final int minOccurrence) {
-        return new DefaultAttributeType<>(Collections.singletonMap(DefaultAttributeType.NAME_KEY, name), type, minOccurrence, 1, null);
+    private static PropertyType createProperty(final String name, final Class<?> type,
+            final int minOccurrence, final int maxOccurrence, final AttributeType<?>[] characteristics)
+    {
+        return new DefaultAttributeType<>(Collections.singletonMap(DefaultAttributeType.NAME_KEY, name),
+                type, minOccurrence, maxOccurrence, null, characteristics);
     }
 
     /**
@@ -489,16 +580,16 @@ public final class Store extends Feature
         if (metadata == null) {
             final MetadataBuilder builder = new MetadataBuilder();
             try {
-                builder.setFormat(timeEncoding != null && hasTrajectories ? "CSV-MF" : "CSV");
+                builder.setFormat(timeEncoding != null && hasTrajectories ? StoreProvider.MOVING : StoreProvider.NAME);
             } catch (MetadataStoreException e) {
                 listeners.warning(null, e);
             }
-            builder.add(encoding, MetadataBuilder.Scope.ALL);
-            builder.add(ScopeCode.DATASET);
+            builder.addEncoding(encoding, MetadataBuilder.Scope.ALL);
+            builder.addResourceScope(ScopeCode.DATASET, null);
             try {
                 builder.addExtent(envelope);
             } catch (TransformException e) {
-                throw new DataStoreReferencingException(getLocale(), "CSV", getDisplayName(), source).initCause(e);
+                throw new DataStoreReferencingException(getLocale(), StoreProvider.NAME, getDisplayName(), source).initCause(e);
             } catch (UnsupportedOperationException e) {
                 /*
                  * Failed to set the temporal components if the sis-temporal module was
@@ -506,7 +597,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;
@@ -540,182 +631,31 @@ public final class Store extends Feature
     /**
      * Returns the stream of features.
      *
+     * @param  parallel  {@code true} for a parallel stream, or {@code false} for a sequential stream.
      * @return a stream over all features in the CSV file.
+     * @throws DataStoreException if an error occurred while creating the feature stream.
      *
      * @todo Needs to reset the position when doing another pass on the features.
+     * @todo If sequential order, publish Feature as soon as identifier changed.
      */
     @Override
-    public Stream<Feature> features() {
-        return StreamSupport.stream(new Iter(), false);
-    }
-
-    /**
-     * Implementation of the iterator returned by {@link #features()}.
-     */
-    private final class Iter implements Spliterator<Feature> {
-        /**
-         * Converters from string representations to the values to store in the {@link #values} array.
-         */
-        private final ObjectConverter<String,?>[] converters;
-
-        /**
-         * All values found in a row. We need to remember those values between different executions
-         * of the {@link #tryAdvance(Consumer)} method because the Moving Feature Specification said:
-         * "If the value equals the previous value, the text for the value can be omitted."
-         */
-        private final Object[] values;
-
-        /**
-         * Name of the property where to store a value.
-         */
-        private final String[] propertyNames;
-
-        /**
-         * Creates a new iterator.
-         */
-        @SuppressWarnings({"unchecked", "rawtypes", "fallthrough"})
-        Iter() {
-            final Collection<? extends PropertyType> properties = featureType.getProperties(true);
-            converters    = new ObjectConverter[properties.size()];
-            values        = new Object[converters.length];
-            propertyNames = new String[converters.length];
-            int i = -1;
-            for (final PropertyType p : properties) {
-                propertyNames[++i] = p.getName().tip().toString();
-                /*
-                 * According Moving Features specification:
-                 *   Column 0 is the feature identifier (mfidref). There is nothing special to do here.
-                 *   Column 1 is the start time.
-                 *   Column 2 is the end time.
-                 *   Column 3 is the trajectory.
-                 *   Columns 4+ are custom attributes.
-                 */
-                final ObjectConverter<String,?> c;
-                switch (i) {
-                    case 1: // Fall through
-                    case 2: {
-                        if (timeEncoding != null) {
-                            c = timeEncoding;
-                            break;
-                        }
-                        /*
-                         * If there is no time columns, then this column may be the trajectory (note that allowing
-                         * CSV files without time is obviously a departure from Moving Features specification.
-                         * The intend is to have a CSV format applicable to other features than moving ones).
-                         * Fall through in order to process trajectory.
-                         */
-                    }
-                    case 3: {
-                        if (hasTrajectories) {
-                            c = GeometryParser.INSTANCE;
-                            break;
-                        }
-                        /*
-                         * If there is no trajectory columns, than this column is a custum attribute.
-                         * CSV files without trajectories are not compliant with Moving Feature spec.,
-                         * but we try to keep this reader a little bit more generic.
-                         */
-                    }
-                    default: {
-                        c = ObjectConverters.find(String.class, ((AttributeType) p).getValueClass());
-                        break;
-                    }
-                }
-                converters[i] = c;
-            }
-        }
-
-        /**
-         * Executes the given action for the next feature or for all remaining features.
-         *
-         * <p><b>Multi-threading:</b>
-         * There is no need for {@code synchronize(Store.this)} statement since this method uses only final and
-         * either immutable or thread-safe objects from {@link Store}. The only object that need synchronization
-         * is {@link Store#source}, which is already synchronized.</p>
-         *
-         * @param  action  the action to execute.
-         * @param  all     {@code true} for executing the given action on all remaining features.
-         * @return {@code false} if there is no remaining feature after this method call.
-         * @throws IOException if an I/O error occurred while reading a feature.
-         * @throws IllegalArgumentException if parsing of a number failed, or other error.
-         * @throws DateTimeException if parsing of a date failed.
-         */
-        private boolean read(final Consumer<? super Feature> action, boolean all) throws IOException {
-            final FixedSizeList elements = new FixedSizeList(values);
-            String line;
-            while ((line = source.readLine()) != null) {
-                split(line, elements);
-                final Feature feature = featureType.newInstance();
-                int i, n = elements.size();
-                for (i=0; i<n; i++) {
-                    values[i] = converters[i].apply((String) values[i]);
-                    feature.setPropertyValue(propertyNames[i], values[i]);
-                }
-                n = values.length;
-                for (; i<n; i++) {
-                    // For omitted elements, reuse previous value.
-                    feature.setPropertyValue(propertyNames[i], values[i]);
-                }
-                action.accept(feature);
-                if (!all) return true;
-                elements.clear();
-            }
-            return false;
-        }
-
-        /**
-         * Executes the given action only on the next feature, if any.
-         */
-        @Override
-        public boolean tryAdvance(final Consumer<? super Feature> action) {
-            try {
-                return read(action, false);
-            } catch (IOException | IllegalArgumentException | DateTimeException e) {
-                throw new BackingStoreException(canNotParseFile(), e);
-            }
-        }
-
-        /**
-         * Executes the given action on all remaining features.
-         */
-        @Override
-        public void forEachRemaining(final Consumer<? super Feature> action) {
-            try {
-                read(action, true);
-            } catch (IOException | IllegalArgumentException | DateTimeException e) {
-                throw new BackingStoreException(canNotParseFile(), e);
-            }
-        }
-
-        /**
-         * Current implementation can not split this iterator.
-         */
-        @Override
-        public Spliterator<Feature> trySplit() {
-            return null;
-        }
-
-        /**
-         * We do not know the number of features.
-         */
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-
-        /**
-         * Returns the characteristics of the iteration over feature instances.
-         * The iteration is assumed {@link #ORDERED} in the declaration order in the CSV file.
-         * The iteration is {@link #NONNULL} (i.e. {@link #tryAdvance(Consumer)} is not allowed
-         * to return null value) and {@link #IMMUTABLE} (i.e. we do not support modification of
-         * the CSV file while an iteration is in progress).
-         *
-         * @return characteristics of iteration over the features in the CSV file.
-         */
-        @Override
-        public int characteristics() {
-            return ORDERED | NONNULL | IMMUTABLE;
+    public synchronized Stream<Feature> features(final boolean parallel) throws DataStoreException {
+        /*
+         * If the user asks for one feature instance per line, then we can return a FeatureIter instance directly.
+         * Since each feature is fully constructed from a single line and each line are read atomically, we can
+         * parallelize this mode.
+         */
+        if (dissociate) {
+            return StreamSupport.stream(new FeatureIterator(this), parallel);
+        }
+        if (movingFeatures == null) try {
+            final MovingFeatureIterator iter = new MovingFeatureIterator(this);
+            iter.readMoving(null, true);
+            movingFeatures = UnmodifiableArrayList.wrap(iter.createMovingFeatures());
+        } catch (IOException | IllegalArgumentException | DateTimeException e) {
+            throw new DataStoreException(canNotParseFile(), e);
         }
+        return movingFeatures.stream();
     }
 
     /**
@@ -786,6 +726,34 @@ public final class Store extends Feature
     }
 
     /**
+     * Returns {@code true} if {@link #featureType} contains a trajectory column.
+     */
+    final boolean hasTrajectories() {
+        return hasTrajectories;
+    }
+
+    /**
+     * Returns the number of dimensions other than time in the coordinate reference system.
+     */
+    final int spatialDimensionCount() {
+        return spatialDimensionCount;
+    }
+
+    /**
+     * Returns an indication of how time is encoded in the CSV file, or {@code null} if there is no time.
+     */
+    final TimeEncoding timeEncoding() {
+        return timeEncoding;
+    }
+
+    /**
+     * Reads the next line from the source CSV file.
+     */
+    final String readLine() throws IOException {
+        return source.readLine();
+    }
+
+    /**
      * Returns an error message for a duplicated element.
      */
     private String duplicated(final String name) {
@@ -797,8 +765,7 @@ public final class Store extends Feature
      * The error message will contain the line number if available.
      */
     final String canNotParseFile() {
-        final Object[] parameters = IOUtilities.errorMessageParameters("CSV", getDisplayName(), source);
-        return errors().getString(IOUtilities.errorMessageKey(parameters), parameters);
+        return IOUtilities.canNotReadFile(getLocale(), StoreProvider.NAME, getDisplayName(), source);
     }
 
     /**
@@ -809,6 +776,16 @@ public final class Store extends Feature
     }
 
     /**
+     * Logs a warning as if it originated from the {@link #features(boolean)} method.
+     * This is a callback method for {@link FeatureIterator}.
+     */
+    final void log(final LogRecord warning) {
+        warning.setSourceClassName(Store.class.getName());
+        warning.setSourceMethodName("features");
+        listeners.warning(warning);
+    }
+
+    /**
      * Closes this data store and releases any underlying resources.
      *
      * @throws DataStoreException if an error occurred while closing this data store.

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -42,6 +42,11 @@ import org.apache.sis.internal.storage.w
 @Capabilities(Capability.READ)
 public final class StoreProvider extends DataStoreProvider {
     /**
+     * The format names for static features and moving features.
+     */
+    static final String NAME = "CSV", MOVING = "CSV-MF";
+
+    /**
      * The object to use for verifying if the first keyword is the expected one.
      */
     private static final class Peek extends FirstKeywordPeek {
@@ -108,7 +113,7 @@ public final class StoreProvider extends
      */
     @Override
     public String getShortName() {
-        return "CSV";
+        return NAME;
     }
 
     /**
@@ -133,6 +138,6 @@ public final class StoreProvider extends
      */
     @Override
     public DataStore open(final StorageConnector connector) throws DataStoreException {
-        return new Store(this, connector);
+        return new Store(this, connector, false);
     }
 }

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -20,6 +20,7 @@ import javax.measure.Unit;
 import javax.measure.quantity.Time;
 import org.opengis.referencing.datum.TemporalDatum;
 import org.apache.sis.internal.converter.SurjectiveConverter;
+import org.apache.sis.internal.util.StandardDateFormat;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.measure.Units;
 
@@ -96,7 +97,12 @@ class TimeEncoding extends SurjectiveCon
     public Instant apply(final String time) {
         final double value = Double.parseDouble(time) * interval;
         final long millis = Math.round(value);
-        return Instant.ofEpochMilli(millis + origin).plusNanos(Math.round((value - millis)*1E6));
+        return Instant.ofEpochMilli(millis + origin)
+                      .plusNanos(Math.round((value - millis) * StandardDateFormat.NANOS_PER_MILLISECOND));
+        /*
+         * Performance note: the call to .plusNano(…) will usually return the same 'Instant' instance
+         * (without creating new object) since the time granularity is rarely finer than milliseconds.
+         */
     }
 
     /**

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -29,6 +29,7 @@ import java.nio.DoubleBuffer;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.SeekableByteChannel;
 import org.apache.sis.internal.storage.Resources;
+import org.apache.sis.io.InvalidSeekException;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.Debug;
 
@@ -879,7 +880,7 @@ public class ChannelDataInput extends Ch
             /*
              * Requested position is before the current buffer limits and we can not seek.
              */
-            throw new IOException(Resources.format(Resources.Keys.StreamIsForwardOnly_1, filename));
+            throw new InvalidSeekException(Resources.format(Resources.Keys.StreamIsForwardOnly_1, filename));
         }
         clearBitOffset();
     }

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/HyperRectangleReader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/HyperRectangleReader.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/HyperRectangleReader.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/HyperRectangleReader.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -45,8 +45,11 @@ public final class HyperRectangleReader
 
     /**
      * The {@code input} position of the first sample (ignoring sub-area and sub-sampling).
+     * This is the {@code origin} argument given to the constructor, copied verbatim.
+     * This field is public for callers wanting to order {@code HyperRectangleReader} instances
+     * in increasing file offset order, for more sequential reading (less seek operations).
      */
-    private final long origin;
+    public final long origin;
 
     /**
      * Creates a new reader for the given input and source region.

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -528,6 +528,23 @@ public final class IOUtilities extends S
     }
 
     /**
+     * Returns the error message for a file that can not be parsed.
+     * The error message will contain the line number if available.
+     *
+     * @param  locale    the language for the error message.
+     * @param  format    abbreviation of the file format (e.g. "CSV", "GML", "WKT", <i>etc</i>).
+     * @param  filename  name of the file or the data store.
+     * @param  store     the input or output object, or {@code null}.
+     * @return the parameters for a localized error message for a file that can not be processed.
+     *
+     * @since 0.8
+     */
+    public static String canNotReadFile(final Locale locale, final String format, final String filename, final Object store) {
+        final Object[] parameters = errorMessageParameters(format, filename, store);
+        return Resources.forLocale(locale).getString(errorMessageKey(parameters), parameters);
+    }
+
+    /**
      * Returns the {@link Resources.Keys} value together with the parameters given by {@code errorMessageParameters(…)}.
      *
      * @param   parameters  the result of {@code errorMessageParameters(…)} method call.

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -26,23 +26,25 @@ 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.DataStore;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.internal.referencing.DefinitionVerifier;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.CharSequences;
-import org.apache.sis.referencing.CRS;
 
 
 /**
  * A data store which creates data objects from a WKT definition.
- * This {@code DataStore} implementation is basically a facade for the {@link CRS#fromWKT(String)} method.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
@@ -118,17 +120,35 @@ final class Store extends DataStore {
             } finally {
                 in.close();
             }
+            /*
+             * At this point we copied all the file content into a String. This string usually contain exactly
+             * one WKT definitions, but this DataStore nevertheless allows an arbitrary number of consecutive
+             * definitions.
+             */
             final ParsePosition pos = new ParsePosition(0);
             final WKTFormat parser = new WKTFormat(null, null);
             do {
-                objects.add(parser.parse(wkt, pos));
+                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) {
-                    final LogRecord record = new LogRecord(Level.WARNING, warnings.toString());
-                    record.setSourceClassName(Store.class.getName());
-                    record.setSourceMethodName("getMetadata");          // Public facade for this method.
-                    listeners.warning(record);
+                    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);
                 }
             } while (pos.getIndex() < wkt.length());
         } catch (ParseException e) {
@@ -139,6 +159,16 @@ final class Store extends DataStore {
     }
 
     /**
+     * Reports a warning.
+     */
+    private void log(final LogRecord record) {
+        record.setSourceClassName(Store.class.getName());
+        record.setSourceMethodName("getMetadata");          // Public facade for the parse() method.
+        record.setLoggerName(Loggers.WKT);
+        listeners.warning(record);
+    }
+
+    /**
      * Returns the metadata associated to the parsed objects, or {@code null} if none.
      * The current implementation retains only instances of {@link ReferenceSystem}
      * and ignore other cases.

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -26,7 +26,9 @@ import java.io.IOException;
 import javax.xml.bind.JAXBException;
 import javax.xml.transform.stream.StreamSource;
 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.xml.XML;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.StorageConnector;
@@ -34,6 +36,8 @@ import org.apache.sis.storage.DataStoreE
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.util.logging.WarningListener;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.internal.referencing.DefinitionVerifier;
 
 import static java.util.Collections.singleton;
 
@@ -124,6 +128,7 @@ final class Store extends DataStore {
 
                 /** Reports the occurrence of a non-fatal error during XML unmarshalling. */
                 @Override public void warningOccured(final Object source, final LogRecord warning) {
+                    warning.setLoggerName(Loggers.XML);
                     listeners.warning(warning);
                 }
             });
@@ -150,6 +155,26 @@ final class Store extends DataStore {
         } catch (JAXBException | IOException e) {
             throw new DataStoreException(Errors.format(Errors.Keys.CanNotRead_1, getDisplayName()), e);
         }
+        if (object instanceof CoordinateReferenceSystem) try {
+            final DefinitionVerifier v = DefinitionVerifier.withAuthority((CoordinateReferenceSystem) object, null, false);
+            if (v != null) {
+                log(v.warning(false));
+            }
+        } catch (FactoryException e) {
+            listeners.warning(null, e);
+        }
+    }
+
+    /**
+     * Reports a warning, if non-null.
+     */
+    private void log(final LogRecord record) {
+        if (record != null) {
+            record.setSourceClassName(Store.class.getName());
+            record.setSourceMethodName("getMetadata");          // Public facade for the parse() method.
+            record.setLoggerName(Loggers.XML);
+            listeners.warning(record);
+        }
     }
 
     /**

Modified: sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -474,8 +474,6 @@ public class StorageConnector implements
             ByteBuffer buffer = getOption(OptionKey.BYTE_BUFFER);
             if (buffer == null) {
                 buffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
-                // TODO: we do not create direct buffer yet, but this is something
-                // we may want to consider in a future SIS version.
             }
             if (asImageInputStream) {
                 asDataInput = new ChannelImageInputStream(name, channel, buffer, false);

Modified: sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.storage.csv;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.io.StringReader;
 import org.opengis.metadata.Metadata;
@@ -25,8 +26,11 @@ import org.apache.sis.storage.DataStoreE
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
+import com.esri.core.geometry.Point2D;
+import com.esri.core.geometry.Polyline;
 
 import static org.junit.Assert.*;
+import static java.util.Collections.singletonList;
 import static org.apache.sis.test.TestUtilities.date;
 import static org.apache.sis.test.TestUtilities.getSingleton;
 
@@ -48,6 +52,11 @@ import org.opengis.feature.AttributeType
  */
 public final strictfp class StoreTest extends TestCase {
     /**
+     * {@code true} if testing a moving feature, or {@code false} (the default) if testing a static feature.
+     */
+    private boolean isMovingFeature;
+
+    /**
      * An example of Moving Features file.
      * Derived from the example provided in OGC 14-084r2.
      */
@@ -77,7 +86,7 @@ public final strictfp class StoreTest ex
     @Test
     public void testGetMetadata() throws DataStoreException {
         final Metadata metadata;
-        try (Store store = new Store(null, new StorageConnector(testData()))) {
+        try (Store store = new Store(null, new StorageConnector(testData()), true)) {
             metadata = store.getMetadata();
         }
         final Extent extent = getSingleton(getSingleton(metadata.getIdentificationInfo()).getExtents());
@@ -90,16 +99,16 @@ public final strictfp class StoreTest ex
     }
 
     /**
-     * Verifies the feature type, then tests {@link Store#features()}.
+     * Verifies the feature type, then tests {@link Store#features(boolean)}.
      *
      * @throws DataStoreException if an error occurred while parsing the data.
      */
     @Test
-    public void testGetFeatures() throws DataStoreException {
-        try (Store store = new Store(null, new StorageConnector(testData()))) {
-            verifyFeatureType(store.featureType);
+    public void testStaticFeatures() throws DataStoreException {
+        try (Store store = new Store(null, new StorageConnector(testData()), true)) {
+            verifyFeatureType(store.featureType, double[].class, 1);
             assertEquals("foliation", Foliation.TIME, store.foliation);
-            final Iterator<Feature> it = store.features().iterator();
+            final Iterator<Feature> it = store.features(false).iterator();
             assertPropertyEquals(it.next(), "a", "12:33:51", "12:36:11", new double[] {11, 2, 12, 3},        "walking", 1);
             assertPropertyEquals(it.next(), "b", "12:33:51", "12:36:51", new double[] {10, 2, 11, 3},        "walking", 2);
             assertPropertyEquals(it.next(), "a", "12:36:11", "12:36:51", new double[] {12, 3, 10, 3},        "walking", 2);
@@ -109,16 +118,44 @@ public final strictfp class StoreTest ex
     }
 
     /**
+     * Tests reading the data as a moving features. In the following data:
+     *
+     * {@preformat text
+     *     a,  10, 150, 11.0 2.0 12.0 3.0, walking, 1
+     *     b,  10, 190, 10.0 2.0 11.0 3.0, walking, 2
+     *     a, 150, 190, 12.0 3.0 10.0 3.0
+     *     c,  10, 190, 12.0 1.0 10.0 2.0 11.0 3.0, vehicle, 1
+     * }
+     *
+     * the two rows for the "a" features shall be merged in a single trajectory.
+     *
+     * @throws DataStoreException if an error occurred while parsing the data.
+     */
+    @Test
+    public void testMovingFeatures() throws DataStoreException {
+        isMovingFeature = true;
+        try (Store store = new Store(null, new StorageConnector(testData()), false)) {
+            verifyFeatureType(store.featureType, Polyline.class, Integer.MAX_VALUE);
+            assertEquals("foliation", Foliation.TIME, store.foliation);
+            final Iterator<Feature> it = store.features(false).iterator();
+            assertPropertyEquals(it.next(), "a", "12:33:51", "12:36:51", new double[] {11, 2, 12, 3, 10, 3}, singletonList("walking"), Arrays.asList(1, 2));
+            assertPropertyEquals(it.next(), "b", "12:33:51", "12:36:51", new double[] {10, 2, 11, 3},        singletonList("walking"), singletonList(2));
+            assertPropertyEquals(it.next(), "c", "12:33:51", "12:36:51", new double[] {12, 1, 10, 2, 11, 3}, singletonList("vehicle"), singletonList(1));
+            assertFalse(it.hasNext());
+        }
+    }
+
+    /**
      * Verifies that the feature type is equal to the expected one.
      */
-    private static void verifyFeatureType(final FeatureType type) {
+    private static void verifyFeatureType(final FeatureType type, final Class<?> geometryType, final int maxOccurs) {
         final Iterator<? extends PropertyType> it = type.getProperties(true).iterator();
-        assertPropertyTypeEquals((AttributeType<?>) it.next(), "mfidref",       String.class,   1);
-        assertPropertyTypeEquals((AttributeType<?>) it.next(), "startTime",     Instant.class,  1);
-        assertPropertyTypeEquals((AttributeType<?>) it.next(), "endTime",       Instant.class,  1);
-        assertPropertyTypeEquals((AttributeType<?>) it.next(), "trajectory",    double[].class, 1);
-        assertPropertyTypeEquals((AttributeType<?>) it.next(), "state",         String.class,   0);
-        assertPropertyTypeEquals((AttributeType<?>) it.next(), "\"type\" code", Integer.class,  0);
+        assertPropertyTypeEquals((AttributeType<?>) it.next(), "mfidref",       String.class,   1, 1);
+        assertPropertyTypeEquals((AttributeType<?>) it.next(), "startTime",     Instant.class,  1, 1);
+        assertPropertyTypeEquals((AttributeType<?>) it.next(), "endTime",       Instant.class,  1, 1);
+        assertPropertyTypeEquals((AttributeType<?>) it.next(), "trajectory",    geometryType,   1, 1);
+        assertPropertyTypeEquals((AttributeType<?>) it.next(), "state",         String.class,   0, maxOccurs);
+        assertPropertyTypeEquals((AttributeType<?>) it.next(), "\"type\" code", Integer.class,  0, maxOccurs);
         assertFalse(it.hasNext());
     }
 
@@ -126,26 +163,42 @@ public final strictfp class StoreTest ex
      * Asserts that the given property type has the given information.
      */
     private static void assertPropertyTypeEquals(final AttributeType<?> p,
-            final String name, final Class<?> valueClass, final int minOccurs)
+            final String name, final Class<?> valueClass, final int minOccurs, final int maxOccurs)
     {
         assertEquals("name",       name,       p.getName().toString());
         assertEquals("valueClass", valueClass, p.getValueClass());
         assertEquals("minOccurs",  minOccurs,  p.getMinimumOccurs());
-        assertEquals("maxOccurs",  1,          p.getMaximumOccurs());
+        assertEquals("maxOccurs",  maxOccurs,  p.getMaximumOccurs());
     }
 
     /**
      * Asserts that the property of the given name in the given feature has expected information.
      */
-    private static void assertPropertyEquals(final Feature f, final String mfidref,
+    private void assertPropertyEquals(final Feature f, final String mfidref,
             final String startTime, final String endTime, final double[] trajectory,
-            final String state, final int typeCode)
+            final Object state, final Object typeCode)
     {
-        assertEquals     ("mfidref",    mfidref,               f.getPropertyValue("mfidref"));
-        assertEquals     ("startTime",  instant(startTime),    f.getPropertyValue("startTime"));
-        assertEquals     ("endTime",    instant(endTime),      f.getPropertyValue("endTime"));
-        assertEquals     ("state",      state,                 f.getPropertyValue("state"));
-        assertEquals     ("typeCode",   typeCode,              f.getPropertyValue("\"type\" code"));
-        assertArrayEquals("trajectory", trajectory, (double[]) f.getPropertyValue("trajectory"), STRICT);
+        assertEquals("mfidref",   mfidref,            f.getPropertyValue("mfidref"));
+        assertEquals("startTime", instant(startTime), f.getPropertyValue("startTime"));
+        assertEquals("endTime",   instant(endTime),   f.getPropertyValue("endTime"));
+        assertEquals("state",     state,              f.getPropertyValue("state"));
+        assertEquals("typeCode",  typeCode,           f.getPropertyValue("\"type\" code"));
+        if (isMovingFeature) {
+            assertPolylineEquals(trajectory, (Polyline) f.getPropertyValue("trajectory"));
+        } else {
+            assertArrayEquals("trajectory", trajectory, (double[]) f.getPropertyValue("trajectory"), STRICT);
+        }
+    }
+
+    /**
+     * Asserts that the given polyline contains the expected coordinate values.
+     */
+    private static void assertPolylineEquals(final double[] trajectory, final Polyline polyline) {
+        assertEquals("pointCount", trajectory.length / 2, polyline.getPointCount());
+        for (int i=0; i < trajectory.length;) {
+            final Point2D xy = polyline.getXY(i / 2);
+            assertEquals("x", trajectory[i++], xy.x, STRICT);
+            assertEquals("y", trajectory[i++], xy.y, STRICT);
+        }
     }
 }

Modified: sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -34,6 +34,7 @@ import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
+import static org.junit.Assume.*;
 import static org.opengis.test.Assert.*;
 
 
@@ -41,7 +42,7 @@ import static org.opengis.test.Assert.*;
  * Tests {@link StorageConnector}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -179,7 +180,11 @@ public final strictfp class StorageConne
         /*
          * Request again the InputStream and read the same amount of bytes than above. The intend of this test
          * is to verify that StorageConnector has reseted the InputStream position before to return it.
+         * Note that this test requires InputStream implementations supporting mark/reset operations
+         * (which is the case when the resource is an ordinary file, not an entry inside a JAR file),
+         * otherwise the call to connection.getStorageAs(…) throws a DataStoreException.
          */
+        assumeTrue("Can not use a JAR file entry for this test.", in.markSupported());
         assertSame(in, connection.getStorageAs(InputStream.class));
         final byte[] actual = new byte[sample.length];
         assertEquals("Should read all requested bytes.", actual.length, in.read(actual));

Modified: sis/branches/JDK9/storage/sis-xmlstore/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-xmlstore/pom.xml?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-xmlstore/pom.xml (original)
+++ sis/branches/JDK9/storage/sis-xmlstore/pom.xml Wed Jul 26 16:14:09 2017
@@ -112,6 +112,11 @@ Read and write files in the GPX format.
       <artifactId>sis-storage</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>com.esri.geometry</groupId>
+      <artifactId>esri-geometry-api</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>

Modified: sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -17,9 +17,9 @@
 package org.apache.sis.internal.storage.gpx;
 
 import java.util.Map;
+import java.util.Iterator;
 import java.util.Collection;
 import java.util.Collections;
-import com.esri.core.geometry.Polyline;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValueGroup;
 import org.apache.sis.feature.AbstractAttribute;
@@ -27,6 +27,7 @@ import org.apache.sis.feature.AbstractOp
 import org.apache.sis.feature.DefaultAttributeType;
 import org.apache.sis.internal.feature.AttributeConvention;
 import org.apache.sis.internal.feature.FeatureUtilities;
+import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
@@ -38,22 +39,30 @@ import org.opengis.feature.AttributeType
 
 /**
  * Creates a single (Multi){@code Polyline} instance from a sequence of points or polylines stored in another property.
- * This base class expects a sequence of {@link Polyline} as input, but subclass will expect other kind of geometries.
+ * This base class expects a sequence of {@code Point} or {@code Polyline} instances as input.
  * The single (Multi){@code Polyline} instance is re-computed every time this property is requested.
  *
- * <div class="note"><b>Example:</b>
+ * <div class="note"><b>Examples:</b>
+ * <p><i>Polylines created from points:</i>
+ * a boat that record it's position every hour.
+ * The list of all positions is stored in an attribute with [0 … ∞] cardinality.
+ * This class will extract each position and create a line as a new attribute.
+ * Any change applied to the positions will be visible on the line.</p>
+ *
+ * <p><i>Polylines created from other polylines:</i>
  * a boat that record track every hour.
  * The list of all tracks is stored in an attribute with [0 … ∞] cardinality.
  * This class will extract each track and create a polyline as a new attribute.
- * Any change applied to the tracks will be visible on the polyline.
+ * Any change applied to the tracks will be visible on the polyline.</p>
  * </div>
  *
  * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
  * @since   0.8
  * @module
  */
-class GroupAsPolylineOperation extends AbstractOperation {
+final class GroupAsPolylineOperation extends AbstractOperation {
     /**
      * For cross-version compatibility.
      */
@@ -65,27 +74,38 @@ class GroupAsPolylineOperation extends A
     private static final ParameterDescriptorGroup EMPTY_PARAMS = FeatureUtilities.parameters("GroupPolylines");
 
     /**
-     * The type of the values computed by this operation. The name of this type presumes
-     * that the result will be assigned to the "geometry" attribute of the feature type.
+     * Name of the property to follow in order to get the geometries to add to a polyline.
+     * This property shall be a feature association, usually with [0 … ∞] cardinality.
      */
-    static final AttributeType<Polyline> RESULT_TYPE = new DefaultAttributeType<>(
-            Collections.singletonMap(NAME_KEY, AttributeConvention.ENVELOPE_PROPERTY), Polyline.class, 1, 1, null);
+    private final String association;
 
     /**
-     * Name of the property to follow in order to get the geometries to add to a polyline.
-     * This property shall be a feature association, usually with [0 … ∞] cardinality.
+     * The expected result type to be returned by {@link #getResult()}.
      */
-    final String association;
+    private final AttributeType<?> result;
 
     /**
      * Creates a new operation which will look for geometries in the given feature association.
      *
      * @param  identification  name and other information to be given to this operation.
      * @param  association     name of the property to follow in order to get the geometries to add to a polyline.
+     * @param  result          the expected result type to be returned by {@link #getResult()}.
      */
-    GroupAsPolylineOperation(final Map<String,?> identification, final String association) {
+    GroupAsPolylineOperation(final Map<String,?> identification, final String association, final AttributeType<?> result) {
         super(identification);
         this.association = association;
+        this.result = result;
+    }
+
+    /**
+     * Creates the {@code result} argument for the constructor. This creation is provided in a separated method
+     * because the same instance will be shared by many {@code GroupAsPolylineOperation} instances.
+     *
+     * @param  geometries  accessor to the geometry implementation in use (Java2D, ESRI or JTS).
+     */
+    static <G> AttributeType<? extends G> getResult(final Geometries<G> geometries) {
+        return new DefaultAttributeType<>(Collections.singletonMap(NAME_KEY, AttributeConvention.ENVELOPE_PROPERTY),
+                geometries.polylineClass, 1, 1, null);
     }
 
     /**
@@ -100,8 +120,8 @@ class GroupAsPolylineOperation extends A
      * Returns the expected result type.
      */
     @Override
-    public final AttributeType<Polyline> getResult() {
-        return RESULT_TYPE;
+    public final AttributeType<?> getResult() {
+        return result;
     }
 
     /**
@@ -110,19 +130,9 @@ class GroupAsPolylineOperation extends A
      * the result will be recomputed.
      */
     @Override
+    @SuppressWarnings({"rawtypes", "unchecked"})
     public final Property apply(Feature feature, ParameterValueGroup parameters) {
-        return new Result(feature);
-    }
-
-    /**
-     * Invoked for every geometric objects to put in a single polyline.
-     *
-     * @param addTo     where to add the geometry object.
-     * @param geometry  the point or polyline to add to {@code addTo}.
-     * @param isFirst   whether {@code geometry} is the first object added to the given polyline.
-     */
-    void addGeometry(final Polyline addTo, final Object geometry, final boolean isFirst) {
-        addTo.add((Polyline) geometry, false);
+        return new Result(feature, association, result);
     }
 
 
@@ -132,8 +142,10 @@ class GroupAsPolylineOperation extends A
      * Note that the cache is not used when {@link #apply(Feature, ParameterValueGroup)} is invoked,
      * causing a new value to be computed again. The intend is to behave as if the operation has been
      * executed at {@code apply(…)} invocation time, even if we deferred the actual execution.
+     *
+     * @param  <G>  the root geometry class (implementation-dependent).
      */
-    private final class Result extends AbstractAttribute<Polyline> {
+    private static final class Result<G> extends AbstractAttribute<G> {
         /**
          * For cross-version compatibility.
          */
@@ -145,31 +157,43 @@ class GroupAsPolylineOperation extends A
         private final Feature feature;
 
         /**
+         * Name of the property to follow in order to get the geometries to add to a polyline.
+         * This property shall be a feature association, usually with [0 … ∞] cardinality.
+         */
+        private final String association;
+
+        /**
          * The result, computed when first needed.
          */
-        private transient Polyline geometry;
+        private transient G geometry;
 
         /**
          * Creates a new result for an execution on the given feature.
          * The actual computation is deferred to the first call of {@link #getValue()}.
          */
-        Result(final Feature feature) {
-            super(RESULT_TYPE);
+        Result(final Feature feature, final String association, final AttributeType<G> result) {
+            super(result);
             this.feature = feature;
+            this.association = association;
         }
 
         /**
-         * Computes the geometry from all points of polylines found in the associated feature.
+         * Computes the geometry from all points or polylines found in the associated feature.
          */
         @Override
-        public Polyline getValue() {
+        public G getValue() {
             if (geometry == null) {
-                boolean isFirst = true;
-                geometry = new Polyline();
-                for (final Object child : (Collection<?>) feature.getPropertyValue(association)) {
-                    addGeometry(geometry, ((Feature) child).getPropertyValue("sis:geometry"), isFirst);
-                    isFirst = false;
-                }
+                final Iterator<?> it = ((Collection<?>) feature.getPropertyValue(association)).iterator();
+                final Object geom = Geometries.mergePolylines(new Iterator<Object>() {
+                    @Override public boolean hasNext() {
+                        return it.hasNext();
+                    }
+
+                    @Override public Object next() {
+                        return ((Feature) it.next()).getPropertyValue("sis:geometry");
+                    }
+                });
+                geometry = getType().getValueClass().cast(geom);
             }
             return geometry;
         }
@@ -178,7 +202,7 @@ class GroupAsPolylineOperation extends A
          * Does not allow modification of this attribute.
          */
         @Override
-        public void setValue(Polyline value) {
+        public void setValue(G value) {
             throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, Attribute.class));
         }
     }

Modified: sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -25,7 +25,6 @@ import java.net.URISyntaxException;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.bind.JAXBException;
-import com.esri.core.geometry.Point;
 import org.apache.sis.storage.gps.Fix;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
@@ -108,7 +107,7 @@ final class Reader extends StaxStreamRea
      * Returns {@code true} if the given namespace is a GPX namespace or is null.
      */
     private static boolean isGPX(final String ns) {
-        return (ns == null) || ns.startsWith(Tags.NAMESPACE + "/GPX/");
+        return (ns == null) || ns.startsWith(Tags.NAMESPACE);
     }
 
     /**
@@ -408,9 +407,10 @@ parse:  while (reader.hasNext()) {
             throw new DataStoreContentException(errors().getString(Errors.Keys.MandatoryAttribute_2,
                     (lat == null) ? Attributes.LATITUDE : Attributes.LONGITUDE, tagName));
         }
-        final Feature feature = ((Store) owner).types.wayPoint.newInstance();
+        final Types types = ((Store) owner).types;
+        final Feature feature = types.wayPoint.newInstance();
         feature.setPropertyValue("sis:identifier", index);
-        feature.setPropertyValue("sis:geometry", new Point(parseDouble(lon), parseDouble(lat)));
+        feature.setPropertyValue("sis:geometry", types.geometries.createPoint(parseDouble(lon), parseDouble(lat)));
         List<Link> links = null;
         while (true) {
             /*

Modified: sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Store.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -17,6 +17,8 @@
 package org.apache.sis.internal.storage.gpx;
 
 import java.net.URISyntaxException;
+import org.opengis.util.NameFactory;
+import org.opengis.util.FactoryException;
 import org.opengis.metadata.Metadata;
 import org.opengis.metadata.distribution.Format;
 import org.apache.sis.storage.StorageConnector;
@@ -24,10 +26,14 @@ import org.apache.sis.storage.DataStoreE
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.storage.ConcurrentReadException;
 import org.apache.sis.storage.IllegalNameException;
+import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.storage.xml.stream.StaxDataStore;
 import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Version;
+import org.apache.sis.setup.OptionKey;
+import org.apache.sis.setup.GeometryLibrary;
+import org.apache.sis.util.iso.DefaultNameFactory;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.distribution.DefaultFormat;
@@ -84,7 +90,14 @@ public final class Store extends StaxDat
      */
     public Store(final StoreProvider provider, final StorageConnector connector) throws DataStoreException {
         super(provider, connector);
-        types = Types.DEFAULT;
+        final GeometryLibrary library = connector.getOption(OptionKey.GEOMETRY_LIBRARY);
+        if (library == null || Types.DEFAULT.geometries.library == library) {
+            types = Types.DEFAULT;
+        } else try {
+            types = new Types(DefaultFactories.forBuildin(NameFactory.class, DefaultNameFactory.class), null, library);
+        } catch (FactoryException e) {
+            throw new DataStoreException(e);
+        }
     }
 
     /**
@@ -169,11 +182,12 @@ public final class Store extends StaxDat
     /**
      * Returns the stream of features.
      *
+     * @param  parallel  ignored in current implementation.
      * @return a stream over all features in the XML file.
      * @throws DataStoreException if an error occurred while creating the feature stream.
      */
     @Override
-    public synchronized Stream<Feature> features() throws DataStoreException {
+    public synchronized Stream<Feature> features(final boolean parallel) throws DataStoreException {
         Reader r = reader;
         reader = null;
         if (r == null) try {

Modified: sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Tags.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Tags.java?rev=1803070&r1=1803069&r2=1803070&view=diff
==============================================================================
--- sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Tags.java [UTF-8] (original)
+++ sis/branches/JDK9/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Tags.java [UTF-8] Wed Jul 26 16:14:09 2017
@@ -33,17 +33,22 @@ final class Tags extends Static {
     /**
      * GPX scope name used for feature type names.
      */
-    static final String NAMESPACE = "http://www.topografix.com";
+    static final String PREFIX = "gpx";
+
+    /**
+     * GPX XML namespace (common root to all versions).
+     */
+    static final String NAMESPACE = "http://www.topografix.com/GPX/";
 
     /**
      * GPX 1.0 XML namespace (v1.0).
      */
-    static final String NAMESPACE_V10 = "http://www.topografix.com/GPX/1/0";
+    static final String NAMESPACE_V10 = NAMESPACE + "1/0";
 
     /**
      * GPX 1.1 XML namespace (v1.1).
      */
-    static final String NAMESPACE_V11 = "http://www.topografix.com/GPX/1/1";
+    static final String NAMESPACE_V11 = NAMESPACE + "1/1";
 
     /** Main GPX XML tags.              */  static final String GPX             = "gpx";
     /** A tag used a bit everywhere.    */  static final String NAME            = "name";



Mime
View raw message