sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1734173 - in /sis/branches/JDK8/storage/sis-storage: ./ src/main/java/org/apache/sis/internal/storage/csv/ src/test/java/org/apache/sis/internal/storage/csv/
Date Tue, 08 Mar 2016 22:13:49 GMT
Author: desruisseaux
Date: Tue Mar  8 22:13:49 2016
New Revision: 1734173

URL: http://svn.apache.org/viewvc?rev=1734173&view=rev
Log:
Initial draft of a getFeatures() method. This is an experimental API restricted to the internal
package for now (see the numerous "TODO" comments).
This experiment allows us to start thinking about what should be the DataStore public API.
Such public API is not planed for Apache SIS 0.7 release
(it would hopefully be provided in SIS 0.8), but in the meantime having an internal API enable
experiments.

Added:
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Foliation.java
  (with props)
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java
  (with props)
Modified:
    sis/branches/JDK8/storage/sis-storage/pom.xml
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
    sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java

Modified: sis/branches/JDK8/storage/sis-storage/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/pom.xml?rev=1734173&r1=1734172&r2=1734173&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/pom.xml (original)
+++ sis/branches/JDK8/storage/sis-storage/pom.xml Tue Mar  8 22:13:49 2016
@@ -126,6 +126,7 @@ Provides the interfaces and base classes
       <artifactId>sis-feature</artifactId>
       <version>${project.version}</version>
     </dependency>
+
     <!-- Test dependencies -->
     <dependency>
       <groupId>org.apache.sis.core</groupId>

Added: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Foliation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Foliation.java?rev=1734173&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Foliation.java
(added)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Foliation.java
[UTF-8] Tue Mar  8 22:13:49 2016
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.storage.csv;
+
+
+/**
+ * Appearing order of trajectories.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+enum Foliation {
+    /**
+     * Trajectories are ordered by time.
+     */
+    TIME,
+
+    /**
+     * Elements which are parts of one track are ordered by time.
+     */
+    SEQUENTIAL
+}

Propchange: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Foliation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Foliation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

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=1734173&r1=1734172&r2=1734173&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] Tue Mar  8 22:13:49 2016
@@ -18,9 +18,9 @@ package org.apache.sis.internal.storage.
 
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Map;
-import java.util.LinkedHashMap;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.Date;
 import java.util.Locale;
 import java.util.logging.Level;
@@ -39,6 +39,7 @@ import javax.measure.quantity.Duration;
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.PropertyType;
+import org.opengis.feature.AttributeType;
 import org.opengis.metadata.Metadata;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -51,13 +52,14 @@ import org.apache.sis.referencing.Common
 import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
 import org.apache.sis.internal.storage.MetadataHelper;
 import org.apache.sis.geometry.GeneralEnvelope;
-import org.apache.sis.measure.Units;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.StorageConnector;
 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.resources.IndexedResourceBundle;
 
@@ -120,41 +122,6 @@ public final class Store extends DataSto
     private final DefaultMetadata metadata;
 
     /**
-     * Values for {@link #order} specifying the appearing order of trajectories.
-     */
-    private static final byte ORDER_TIME = 1, ORDER_SEQUENTIAL = 2;
-
-    /**
-     * Appearing order of trajectories: 0 = undefined, 1 = ordered by time,
-     * 2 = elements which are parts of one track are ordered by time.
-     *
-     * @see #parseFoliation(List)
-     */
-    private final byte order;
-
-    /**
-     * Values for {@link #timeEncoding} specifying how time is encoded in the CSV file.
-     */
-    private static final byte TIME_RELATIVE = 1, TIME_ABSOLUTE = 2;
-
-    /**
-     * A code for the time encoding: 0 = no time, 1 = relative time, 2 = absolute time.
-     * Relative times are formatted as number of seconds or minutes since an epoch.
-     * Absolute times are formatted as ISO dates.
-     */
-    private byte timeEncoding;
-
-    /**
-     * Date of value zero on the time axis, in milliseconds since January 1st 1970 at midnight
UTC.
-     */
-    private long timeOrigin;
-
-    /**
-     * Number of milliseconds between two consecutive integer values on the time axis.
-     */
-    private double timeInterval;
-
-    /**
      * The three- or four-dimensional envelope together with the CRS.
      * This envelope contains a vertical component if the feature trajectories are 3D,
      * and a temporal component if the CSV file contains a start time and end time.
@@ -175,7 +142,24 @@ public final class Store extends DataSto
      *
      * @todo We should not keep them in memory, but instead use some kind of iterator or
stream.
      */
-    private final Map<String,Feature> features;
+    private final List<Feature> features;
+
+    /**
+     * {@code true} if {@link #featureType} contains a trajectory column.
+     */
+    private boolean hasTrajectories;
+
+    /**
+     * Appearing order of trajectories, or {@code null} if unspecified.
+     *
+     * @see #parseFoliation(List)
+     */
+    private final Foliation foliation;
+
+    /**
+     * Specifies how time is encoded in the CSV file, or {@code null} if there is no time.
+     */
+    private TimeEncoding timeEncoding;
 
     /**
      * Creates a new CSV store from the given file, URL or stream.
@@ -196,7 +180,7 @@ public final class Store extends DataSto
         source = (r instanceof BufferedReader) ? (BufferedReader) r : new LineNumberReader(r);
         GeneralEnvelope envelope    = null;
         FeatureType     featureType = null;
-        byte            order       = 0;
+        Foliation       foliation   = null;
         try {
             final List<String> elements = new ArrayList<>();
             source.mark(1024);
@@ -222,13 +206,16 @@ public final class Store extends DataSto
                             throw new DataStoreException(duplicated("@columns"));
                         }
                         featureType = parseFeatureType(elements);
+                        if (foliation == null) {
+                            foliation = Foliation.TIME;
+                        }
                         break;
                     }
                     case "@foliation": {
-                        if (order != 0) {
+                        if (foliation != null) {
                             throw new DataStoreException(duplicated("@foliation"));
                         }
-                        order = parseFoliation(elements);
+                        foliation = parseFoliation(elements);
                         break;
                     }
                     default: {
@@ -248,9 +235,9 @@ public final class Store extends DataSto
         }
         this.envelope    = envelope;
         this.featureType = featureType;
-        this.order       = order;
+        this.foliation   = foliation;
         this.metadata    = MetadataHelper.createForTextFile(connector);
-        this.features    = new LinkedHashMap<>();
+        this.features    = new ArrayList<>();
     }
 
     /**
@@ -284,8 +271,8 @@ public final class Store extends DataSto
                         case "second":   /* Already SI.SECOND. */ break;
                         case "minute":   timeUnit = NonSI.MINUTE; break;
                         case "hour":     timeUnit = NonSI.HOUR;   break;
-                        case "absolute": isTimeAbsolute = true;   // Fall through
                         case "day":      timeUnit = NonSI.DAY;    break;
+                        case "absolute": isTimeAbsolute = true;   break;
                         default: throw new DataStoreException(errors().getString(Errors.Keys.UnknownUnit_1,
unit));
                     }
                     // Fall through
@@ -328,27 +315,15 @@ public final class Store extends DataSto
             }
             final GeodeticObjectBuilder builder = new GeodeticObjectBuilder();
             if (startTime != null) {
-                TemporalCRS temporal = null;
+                final TemporalCRS temporal;
                 if (isTimeAbsolute) {
-                    /*
-                     * If time is absolute (i.e. is formatted as an ISO date), then the origin
does not matter.
-                     * In such case we favor the first pre-defined TemporalCRS with same
unit of measurement.
-                     */
-                    for (final CommonCRS.Temporal c : CommonCRS.Temporal.values()) {
-                        final TemporalCRS candidate = c.crs();
-                        if (timeUnit.equals(candidate.getCoordinateSystem().getAxis(0).getUnit()))
{
-                            temporal = candidate;
-                            break;
-                        }
-                    }
-                }
-                if (temporal == null) {
+                    temporal = TimeEncoding.DEFAULT.crs();
+                    timeEncoding = TimeEncoding.ABSOLUTE;
+                } else {
                     temporal = builder.createTemporalCRS(Date.from(startTime), timeUnit);
+                    timeEncoding = new TimeEncoding(temporal.getDatum(), timeUnit);
                 }
                 components[count++] = temporal;
-                timeOrigin   = temporal.getDatum().getOrigin().getTime();
-                timeInterval = timeUnit.getConverterTo(Units.MILLISECOND).convert(1);
-                timeEncoding = isTimeAbsolute ? TIME_ABSOLUTE : TIME_RELATIVE;
             }
             crs = builder.addName(name).createCompoundCRS(ArraysExt.resize(components, count));
             /*
@@ -369,8 +344,8 @@ public final class Store extends DataSto
                 }
             }
             if (startTime != null && endTime != null) {
-                envelope.setRange(spatialDimension, (startTime.toEpochMilli() - timeOrigin)
/ timeInterval,
-                                                      (endTime.toEpochMilli() - timeOrigin)
/ timeInterval);
+                envelope.setRange(spatialDimension, timeEncoding.toCRS(startTime.toEpochMilli()),
+                                                    timeEncoding.toCRS(endTime.toEpochMilli()));
             }
         }
         return envelope;
@@ -427,8 +402,10 @@ public final class Store extends DataSto
                     case 1: minOccurrence = 1; break;
                     case 2: {
                         if (name.equalsIgnoreCase("trajectory")) {
-                            if (timeEncoding != 0) {
-                                properties.add(createProperty("time", long[].class, 1));
+                            hasTrajectories = true;
+                            if (timeEncoding != null) {
+                                properties.add(createProperty("startTime", Instant.class,
1));
+                                properties.add(createProperty(  "endTime", Instant.class,
1));
                             }
                             type = double[].class;
                             minOccurrence = 1;
@@ -462,16 +439,11 @@ public final class Store extends DataSto
      * @param  elements The line elements. The first elements should be {@code "@foliation"}.
      * @return The foliation metadata.
      */
-    private byte parseFoliation(final List<String> elements) throws DataStoreException
{
+    private Foliation parseFoliation(final List<String> elements) {
         if (elements.size() >= 2) {
-            final String value = elements.get(1);
-            switch (value.toLowerCase(Locale.US)) {
-                case "time":       break;
-                case "sequential": return ORDER_SEQUENTIAL;
-                default: throw new DataStoreException(errors().getString(Errors.Keys.UnknownEnumValue_2,
"order", value));
-            }
+            return Foliation.valueOf(elements.get(1).toUpperCase(Locale.US));
         }
-        return ORDER_TIME;      // Default value.
+        return Foliation.TIME;      // Default value.
     }
 
     /**
@@ -494,6 +466,104 @@ public final class Store extends DataSto
     }
 
     /**
+     * Returns an iterator over the features.
+     *
+     * @todo THIS IS AN EXPERIMENTAL API. We may change the return type to {@link java.util.stream.Stream}
later.
+     * @todo Current implementation is inefficient. We should not parse all features immediately.
+     *
+     * @return An iterator over all features in the CSV file.
+     * @throws DataStoreException if an error occurred while creating the iterator.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes", "fallthrough"})
+    public Iterator<Feature> getFeatures() throws DataStoreException {
+        if (features.isEmpty()) try {
+            final Collection<? extends PropertyType> properties = featureType.getProperties(false);
+            final ObjectConverter<String,?>[] converters = new ObjectConverter[properties.size()];
+            final String[]     propertyNames   = new String[converters.length];
+            final boolean      hasTrajectories = this.hasTrajectories;
+            final TimeEncoding timeEncoding    = this.timeEncoding;
+            final List<String> values          = new ArrayList<>();
+            int i = -1;
+            for (final PropertyType p : properties) {
+                propertyNames[++i] = p.getName().tip().toString();
+                switch (i) {    // This switch shall follow the same cases than the swith
in the loop.
+                    case 1:
+                    case 2: if (timeEncoding != null) continue;     // else fall through
+                    case 3: if (hasTrajectories) continue;
+                }
+                converters[i] = ObjectConverters.find(String.class, ((AttributeType) p).getValueClass());
+            }
+            /*
+             * Above lines prepared the constants. Now parse all lines.
+             * TODO: We should move the code below this point in a custom Iterator implementation.
+             */
+            String line;
+            while ((line = source.readLine()) != null) {
+                split(line, values);
+                final int length = Math.min(propertyNames.length, values.size());
+                if (length != 0) {
+                    final Feature feature = featureType.newInstance();
+                    for (i=0; i<length; i++) {
+                        final String text = values.get(i);
+                        final String name = propertyNames[i];
+                        final Object value;
+                        /*
+                         * 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 custum attributes.
+                         *
+                         * TODO: we should replace that switch case by custom ObjectConverter.
+                         */
+                        switch (i) {
+                            case 1:
+                            case 2: {
+                                if (timeEncoding != null) {
+                                    if (timeEncoding == TimeEncoding.ABSOLUTE) {
+                                        value = Instant.parse(text).toEpochMilli();
+                                    } else {
+                                        value = Instant.ofEpochMilli(timeEncoding.toMillis(Double.parseDouble(text)));
+                                    }
+                                    break;
+                                }
+                                /*
+                                 * If there is no time columns, then this column may 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) {
+                                    value = CharSequences.parseDoubles(text, ORDINATE_SEPARATOR);
+                                    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: {
+                                value = converters[i].apply(text);
+                                break;
+                            }
+                        }
+                        feature.setPropertyValue(name, value);
+                    }
+                    features.add(feature);
+                }
+                values.clear();
+            }
+        } catch (IOException | IllegalArgumentException | DateTimeException e) {
+            throw new DataStoreException(errors().getString(Errors.Keys.CanNotParseFile_2,
"CSV", name), e);
+        }
+        return features.iterator();
+    }
+
+    /**
      * Splits the content of the given line around the column separator.
      * Quotes are taken in account. The elements are added in the given list.
      *
@@ -518,7 +588,7 @@ public final class Store extends DataSto
                 }
                 case SEPARATOR: {
                     if (!isQuoting) {
-                        elements.add(extract(line, startAt, i, hasQuotes));
+                        elements.add(decode(line, startAt, i, hasQuotes));
                         startAt = i+1;
                         hasQuotes = false;
                     }
@@ -526,13 +596,17 @@ public final class Store extends DataSto
                 }
             }
         }
-        elements.add(extract(line, startAt, length, hasQuotes));
+        elements.add(decode(line, startAt, length, hasQuotes));
     }
 
     /**
      * Extracts a substring from the given line and replaces double quotes by single quotes.
+     *
+     * @todo Needs also to check escape characters {@code \s \t \b &lt; &gt; &amp;
&quot; &apos;}.
+     * @todo Should modify double quote policy: process only if the text had quotes at the
beginning and end.
+     *       Those "todo" should be done only when we detected that the CSV file is a moving
features file.
      */
-    private static String extract(CharSequence text, final int lower, final int upper, final
boolean hasQuotes) {
+    private static String decode(CharSequence text, final int lower, final int upper, final
boolean hasQuotes) {
         if (hasQuotes) {
             final StringBuilder buffer = new StringBuilder(upper - lower).append(text, lower,
upper);
             for (int i=0; i<buffer.length(); i++) {

Added: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java?rev=1734173&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java
(added)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java
[UTF-8] Tue Mar  8 22:13:49 2016
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.storage.csv;
+
+import javax.measure.unit.Unit;
+import javax.measure.unit.NonSI;
+import javax.measure.quantity.Duration;
+import org.opengis.referencing.datum.TemporalDatum;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.measure.Units;
+
+
+/**
+ * Specifies how time is encoded in the CSV file.
+ * Time values are formatted as numbers of seconds or minutes since an epoch,
+ * except in the special case of {@link #ABSOLUTE} encoding.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+final class TimeEncoding {
+    /**
+     * The temporal coordinate reference system to use for {@link #ABSOLUTE} time encoding.
+     */
+    static final CommonCRS.Temporal DEFAULT = CommonCRS.Temporal.TRUNCATED_JULIAN;
+
+    /**
+     * Times are formatted as ISO dates.
+     */
+    static final TimeEncoding ABSOLUTE = new TimeEncoding(DEFAULT.datum(), NonSI.DAY);
+
+    /**
+     * Date of value zero on the time axis, in milliseconds since January 1st 1970 at midnight
UTC.
+     */
+    private final long origin;
+
+    /**
+     * Number of milliseconds between two consecutive integer values on the time axis.
+     */
+    private final double interval;
+
+    /**
+     * Creates a new time encoding.
+     */
+    TimeEncoding(final TemporalDatum datum, final Unit<Duration> unit) {
+        this.origin   = datum.getOrigin().getTime();
+        this.interval = unit.getConverterTo(Units.MILLISECOND).convert(1);
+    }
+
+    /**
+     * Converts the given timestamp to the values used in the temporal coordinate reference
system.
+     *
+     * @param time Number of milliseconds elapsed since January 1st, 1970 midnight UTC.
+     * @return The value to use with the temporal coordinate reference system.
+     */
+    final double toCRS(final long time) {
+        return (time - origin) / interval;
+    }
+
+    /**
+     * Reverse of {@link #toCRS(long)}.
+     *
+     * @param time The value used with the temporal coordinate reference system.
+     * @return Number of milliseconds elapsed since January 1st, 1970 midnight UTC.
+     */
+    final long toMillis(final double time) {
+        return Math.round(time * interval) + origin;
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/TimeEncoding.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java?rev=1734173&r1=1734172&r2=1734173&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
[UTF-8] Tue Mar  8 22:13:49 2016
@@ -16,7 +16,9 @@
  */
 package org.apache.sis.internal.storage.csv;
 
+import java.util.Iterator;
 import java.io.StringReader;
+import org.opengis.feature.Feature;
 import org.opengis.metadata.Metadata;
 import org.opengis.metadata.extent.GeographicBoundingBox;
 import org.opengis.metadata.extent.SpatialTemporalExtent;
@@ -72,4 +74,33 @@ public final class StoreTest extends Tes
         assertNull("Should not have a vertical extent.", extent.getVerticalExtent());
         assertNotNull("Should have a temporal extent", extent.getExtent());
     }
+
+    /**
+     * Tests {@link Store#getFeatures()}.
+     *
+     * @throws DataStoreException if an error occurred while parsing the data.
+     */
+    @Test
+    public void testGetFeatures() throws DataStoreException {
+        try (Store store = new Store(new StorageConnector(new StringReader(TEST_DATA))))
{
+            final Iterator<Feature> it = store.getFeatures();
+            assertFeatureEquals(it.next(), "a", new double[] {11, 2, 12, 3},        "walking",
1);
+            assertFeatureEquals(it.next(), "b", new double[] {10, 2, 11, 3},        "walking",
2);
+            assertFeatureEquals(it.next(), "a", new double[] {12, 3, 10, 3},        "walking",
2);
+            assertFeatureEquals(it.next(), "c", new double[] {12, 1, 10, 2, 11, 3}, "vehicle",
1);
+            assertFalse(it.hasNext());
+        }
+    }
+
+    /**
+     * Asserts that the given feature has the given properties.
+     */
+    private static void assertFeatureEquals(final Feature f, final String mfidref,
+            final double[] trajectory, final String state, final int typeCode)
+    {
+        assertEquals     ("mfidref",    mfidref,  f.getPropertyValue("mfidref"));
+        assertEquals     ("state",      state,    f.getPropertyValue("state"));
+        assertEquals     ("typeCode",   typeCode, f.getPropertyValue("\"type\" code"));
+        assertArrayEquals("trajectory", trajectory, (double[]) f.getPropertyValue("trajectory"),
STRICT);
+    }
 }



Mime
View raw message