sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1831113 - in /sis/branches/JDK8: core/sis-feature/src/main/java/org/apache/sis/internal/feature/ core/sis-utility/src/main/java/org/apache/sis/util/collection/ storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ storage/sis-...
Date Mon, 07 May 2018 17:32:23 GMT
Author: desruisseaux
Date: Mon May  7 17:32:22 2018
New Revision: 1831113

URL: http://svn.apache.org/viewvc?rev=1831113&view=rev
Log:
Review of org.apache.sis.internal.storage.query package.

Added:
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSetView.java
      - copied, changed from r1831112, sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQueryFeatureSet.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/package-info.java   (with props)
Removed:
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQueryFeatureSet.java
Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/package-info.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/package-info.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SortByComparator.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java
    sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java [UTF-8] Mon May  7 17:32:22 2018
@@ -18,6 +18,10 @@ package org.apache.sis.internal.feature;
 
 import java.util.Map;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import org.opengis.util.GenericName;
 import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
@@ -36,7 +40,7 @@ import org.opengis.feature.PropertyType;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.8
  * @module
  */
@@ -90,4 +94,33 @@ public final class FeatureUtilities exte
         }
         return null;
     }
+
+    /**
+     * Gets the name of all given properties. If any property is null or has a null name,
+     * then the corresponding entry in the returned array will be null.
+     *
+     * @param  properties  the properties for which to get the names, or {@code null}.
+     * @return the name of all given properties, or {@code null} if the given list was null.
+     */
+    public static String[] getNames(final Collection<? extends PropertyType> properties) {
+        if (properties == null) {
+            return null;
+        }
+        final String[] names = new String[properties.size()];
+        final Iterator<? extends PropertyType> it = properties.iterator();
+        for (int i=0; i < names.length; i++) {
+            final PropertyType property = it.next();
+            if (property != null) {
+                final GenericName name = property.getName();
+                if (name != null) {
+                    names[i] = name.toString();
+                }
+            }
+        }
+        // Should not have any element left, unless collection size changed during iteration.
+        if (it.hasNext()) {
+            throw new ConcurrentModificationException();
+        }
+        return names;
+    }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/package-info.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/package-info.java [UTF-8] Mon May  7 17:32:22 2018
@@ -26,6 +26,7 @@
  * may change in incompatible ways in any future version without notice.
  *
  * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   0.7
  * @module

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] Mon May  7 17:32:22 2018
@@ -19,6 +19,7 @@ package org.apache.sis.util.collection;
 import java.util.Map;
 import java.util.Set;
 import java.util.List;
+import java.util.Iterator;
 import java.util.Collection;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.ArgumentChecks;
@@ -33,7 +34,7 @@ import org.apache.sis.internal.util.Unmo
  * in this class implement the {@code CheckedContainer} interface.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.4
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -268,4 +269,37 @@ public final class Containers extends St
         }
         return count + r;
     }
+
+    /**
+     * Compares element-by-element the values provided by two iterators, in iteration order. Let {@code o1} be an
+     * element from the first iterator and {@code o2} the element at the same position from the second iterator.
+     * This method returns the result of the first {@code o1.compareTo(o2)} call which returned a value different
+     * than zero. If all {@code o1.compareTo(o2)} calls returned zero, then this method returns -1 if {@code it1}
+     * iteration finished before {@code it2}, +1 if {@code it2} iteration finished before {@code it1}, or 0 if both
+     * iterators finished in same time.
+     *
+     * <p>Iterators may return null elements. Null elements are considered "after" any non-null element.</p>
+     *
+     * @param  <E>  the type of elements returned by the iterators.
+     * @param  it1  the first iterator (can not be null).
+     * @param  it2  the second iterator (can not be null).
+     * @return -1 if the content given by the first iterator is considered "before" the content given by the second
+     *         iterator, +1 if considered "after", or 0 if considered equal.
+     *
+     * @since 1.0
+     */
+    public static <E extends Comparable<E>> int compare(final Iterator<E> it1, final Iterator<? extends E> it2) {
+        while (it1.hasNext()) {
+            if (!it2.hasNext()) return +1;          // it1 longer than it2.
+            final E o1 = it1.next();
+            final E o2 = it2.next();
+            if (o1 != o2) {
+                if (o1 == null) return +1;
+                if (o2 == null) return -1;
+                final int c = o1.compareTo(o2);
+                if (c != 0) return c;
+            }
+        }
+        return it2.hasNext() ? -1 : 0;
+    }
 }

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/package-info.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/package-info.java [UTF-8] Mon May  7 17:32:22 2018
@@ -51,7 +51,7 @@
  * </ul>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java [UTF-8] Mon May  7 17:32:22 2018
@@ -45,6 +45,16 @@ public abstract class AbstractFeatureSet
     }
 
     /**
+     * Creates a new feature set with the same warning listeners than the given resource,
+     * or {@code null} if the listeners are unknown.
+     *
+     * @param resource  the resources from which to get the listeners, or {@code null} if none.
+     */
+    protected AbstractFeatureSet(final FeatureSet resource) {
+        super(resource);
+    }
+
+    /**
      * Requests a subset of features and/or feature properties from this resource.
      * The default implementation try to execute the queries by filtering the
      * {@linkplain #features(boolean) stream of features}, which may be inefficient.
@@ -58,7 +68,7 @@ public abstract class AbstractFeatureSet
     @Override
     public FeatureSet subset(final Query query) throws DataStoreException {
         if (query instanceof SimpleQuery) {
-            return SimpleQuery.executeOnCPU(this, (SimpleQuery) query);
+            return ((SimpleQuery) query).execute(this);
         } else {
             return FeatureSet.super.subset(query);
         }

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractResource.java [UTF-8] Mon May  7 17:32:22 2018
@@ -57,6 +57,16 @@ public abstract class AbstractResource i
     }
 
     /**
+     * Creates a new resource with the same warning listeners than the given resource,
+     * or {@code null} if the listeners are unknown.
+     *
+     * @param resource  the resources from which to get the listeners, or {@code null} if none.
+     */
+    protected AbstractResource(final Resource resource) {
+        listeners = (resource instanceof AbstractResource) ? ((AbstractResource) resource).listeners : null;
+    }
+
+    /**
      * Returns the locale for error messages or warnings.
      * Returns {@code null} if no locale is explicitly defined.
      *

Copied: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSetView.java (from r1831112, sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQueryFeatureSet.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSetView.java?p2=sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSetView.java&p1=sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQueryFeatureSet.java&r1=1831112&r2=1831113&rev=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQueryFeatureSet.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSetView.java [UTF-8] Mon May  7 17:32:22 2018
@@ -16,67 +16,90 @@
  */
 package org.apache.sis.internal.storage.query;
 
-import java.util.Collections;
 import java.util.List;
-import java.util.function.Function;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import org.opengis.geometry.Envelope;
+import org.opengis.metadata.Metadata;
+import org.apache.sis.internal.feature.FeatureUtilities;
+import org.apache.sis.internal.storage.AbstractFeatureSet;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
-import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.Query;
-import org.apache.sis.storage.UnsupportedQueryException;
-import org.apache.sis.storage.event.ChangeEvent;
-import org.apache.sis.storage.event.ChangeListener;
+
+// Branch-dependent imports
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
 import org.opengis.filter.Filter;
 import org.opengis.filter.sort.SortBy;
-import org.opengis.geometry.Envelope;
-import org.opengis.metadata.Metadata;
-import org.opengis.util.GenericName;
+import org.opengis.filter.expression.Expression;
+
 
 /**
+ * The result of {@link SimpleQuery#execute(FeatureSet)} executed using Java {@link Stream} methods.
+ * Queries executed by this class do not benefit from accelerations provided for example by databases.
+ * This class should be used only as a fallback when the query can not be executed natively by
+ * {@link FeatureSet#subset(Query)}.
  *
- * @author Johann Sorel (Geomatys)
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
  */
-final class SimpleQueryFeatureSet implements FeatureSet {
-
+final class FeatureSetView extends AbstractFeatureSet {
+    /**
+     * The set of feature instances to filter, sort or process.
+     */
     private final FeatureSet source;
+
+    /**
+     * The query for filtering the source set of features.
+     */
     private final SimpleQuery query;
+
+    /**
+     * The type of features in this set. May or may not be the same as {@link #source}.
+     * This is computed when first needed.
+     */
     private FeatureType resultType;
+
+    /**
+     * A description of this set of features, computed when first needed.
+     */
     private DefaultMetadata metadata;
 
-    public SimpleQueryFeatureSet(FeatureSet source, SimpleQuery query) {
+    /**
+     * Creates a new set of features by filtering the given set using the given query.
+     */
+    FeatureSetView(final FeatureSet source, final SimpleQuery query) {
+        super(source);
         this.source = source;
         this.query = query;
     }
 
+    /**
+     * Returns {@code null} since computing the envelope would be costly.
+     */
     @Override
-    public Envelope getEnvelope() throws DataStoreException {
+    public Envelope getEnvelope() {
         return null;
     }
 
+    /**
+     * Computes information about this resource.
+     * Current implementation sets only the resource name.
+     */
     @Override
     public synchronized Metadata getMetadata() throws DataStoreException {
         if (metadata == null) {
-            final FeatureType type = getType();
-
+            final DefaultCitation citation = new DefaultCitation(getType().getName().toInternationalString());
             final DefaultDataIdentification identification = new DefaultDataIdentification();
-            final NamedIdentifier identifier = new NamedIdentifier(type.getName());
-            final DefaultCitation citation = new DefaultCitation(type.getName().toString());
-            citation.setIdentifiers(Collections.singleton(identifier));
             identification.setCitation(citation);
 
             final DefaultMetadata metadata = new DefaultMetadata();
-            metadata.setIdentificationInfo(Collections.singleton(identification));
+            metadata.getIdentificationInfo().add(identification);
             metadata.freeze();
 
             this.metadata = metadata;
@@ -84,84 +107,70 @@ final class SimpleQueryFeatureSet implem
         return metadata;
     }
 
+    /**
+     * Returns a description of properties that are common to all features in this dataset.
+     */
     @Override
     public synchronized FeatureType getType() throws DataStoreException {
         if (resultType == null) {
-            resultType = SimpleQuery.expectedType(source.getType(), query);
+            resultType = query.expectedType(source.getType());
         }
         return resultType;
     }
 
+    /**
+     * Returns a stream of all features contained in this dataset.
+     */
     @Override
-    public FeatureSet subset(Query query) throws UnsupportedQueryException, DataStoreException {
-        if (query instanceof SimpleQuery) {
-            return SimpleQuery.executeOnCPU(this, (SimpleQuery) query);
-        }
-        return FeatureSet.super.subset(query);
-    }
-
-    @Override
-    public Stream<Feature> features(boolean parallel) throws DataStoreException {
-
+    public Stream<Feature> features(final boolean parallel) throws DataStoreException {
         Stream<Feature> stream = source.features(parallel);
-
-        //apply filter
+        /*
+         * Apply filter.
+         */
         final Filter filter = query.getFilter();
         if (!Filter.INCLUDE.equals(filter)) {
             stream = stream.filter(filter::evaluate);
         }
-
-        //apply sort by
+        /*
+         * Apply sorting.
+         */
         final SortBy[] sortBy = query.getSortBy();
         if (sortBy.length > 0) {
             stream = stream.sorted(new SortByComparator(sortBy));
         }
-
-        //apply offset
+        /*
+         * Apply offset.
+         */
         final long offset = query.getOffset();
         if (offset > 0) {
             stream = stream.skip(offset);
         }
-
-        //apply limit
+        /*
+         * Apply limit.
+         */
         final long limit = query.getLimit();
         if (limit >= 0) {
             stream = stream.limit(limit);
         }
-
-        //transform feature
+        /*
+         * Transform feature instances.
+         */
         final List<SimpleQuery.Column> columns = query.getColumns();
         if (columns != null) {
-            final SimpleQuery.Column[] cols = columns.toArray(new SimpleQuery.Column[0]);
+            final Expression[] expressions = new Expression[columns.size()];
+            for (int i=0; i<expressions.length; i++) {
+                expressions[i] = columns.get(i).expression;
+            }
             final FeatureType type = getType();
-            final String[] names = type.getProperties(false).stream()
-                    .map(PropertyType::getName)
-                    .map(GenericName::tip)
-                    .map(Object::toString)
-                    .collect(Collectors.toList())
-                    .toArray(new String[0]);
-
-            stream = stream.map(new Function<Feature, Feature>() {
-                @Override
-                public Feature apply(Feature t) {
-                    final Feature f = type.newInstance();
-                    for (int i=0;i<cols.length;i++) {
-                        f.setPropertyValue(names[i], cols[i].expression.evaluate(t));
-                    }
-                    return f;
+            final String[] names = FeatureUtilities.getNames(type.getProperties(false));
+            stream = stream.map(t -> {
+                final Feature f = type.newInstance();
+                for (int i=0; i < expressions.length; i++) {
+                    f.setPropertyValue(names[i], expressions[i].evaluate(t));
                 }
+                return f;
             });
         }
-
         return stream;
     }
-
-    @Override
-    public <T extends ChangeEvent> void addListener(ChangeListener<? super T> listener, Class<T> eventType) {
-    }
-
-    @Override
-    public <T extends ChangeEvent> void removeListener(ChangeListener<? super T> listener, Class<T> eventType) {
-    }
-
 }

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java [UTF-8] Mon May  7 17:32:22 2018
@@ -17,324 +17,409 @@
 package org.apache.sis.internal.storage.query;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
-import org.opengis.filter.Filter;
-import org.opengis.filter.expression.Expression;
-import org.opengis.filter.sort.SortBy;
 import org.opengis.util.GenericName;
 import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.internal.feature.FeatureExpression;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.storage.Query;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.Debug;
 import org.apache.sis.util.iso.Names;
+import org.apache.sis.util.resources.Errors;
+
+// Branch-dependent imports
+import org.opengis.filter.Filter;
+import org.opengis.filter.sort.SortBy;
+import org.opengis.filter.expression.Expression;
+import org.opengis.feature.FeatureType;
+import org.opengis.feature.PropertyType;
+import org.opengis.feature.AttributeType;
+import org.opengis.feature.FeatureAssociationRole;
+
 
 /**
- * A simple query mimics SQL SELECT using OGC Filter and Expressions.
+ * Mimics {@code SQL SELECT} statements using OGC Filter and Expressions.
+ * Information stored in this query can be used directly with {@link java.util.stream.Stream} API.
  *
- * @author Johann Sorel (Geomatys)
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
  */
 public class SimpleQuery implements Query {
+    /**
+     * Sentinel limit value for queries of unlimited length.
+     * This value can be given to {@link #setLimit(long)} or retrieved from {@link #getLimit()}.
+     */
+    private static final long UNLIMITED = -1;
 
-    private static final SortBy[] EMPTY_SORTBY = new SortBy[0];
+    /**
+     * The columns to retrieve, or {@code null} if all columns shall be included in the query.
+     *
+     * @see #getColumns()
+     * @see #setColumns(Column...)
+     */
+    private Column[] columns;
 
-    private List<Column> columns;
-    private Filter filter = Filter.INCLUDE;
-    private long offset;
-    private long limit = -1;
-    private SortBy[] sortBy = EMPTY_SORTBY;
-    private final Map<String,Object> hints = new HashMap<>();
+    /**
+     * The filter for trimming feature instances.
+     *
+     * @see #getFilter()
+     * @see #setFilter(Filter)
+     */
+    private Filter filter;
 
-    public SimpleQuery() {
-    }
+    /**
+     * The number of records to skip from the beginning.
+     *
+     * @see #getOffset()
+     * @see #setOffset(long)
+     * @see java.util.stream.Stream#skip(long)
+     */
+    private long skip;
 
     /**
-     * Set query columns.
-     * A query column may use a simple or complex expression and a alias
-     * to create a new type of returned feature.<br>
+     * The maximum number of records contained in the {@code FeatureSet}.
      *
-     * @return query columns or null to get all feature properties.
+     * @see #getLimit()
+     * @see #setLimit(long)
+     * @see java.util.stream.Stream#limit(long)
      */
-    public List<Column> getColumns() {
-        return columns;
+    private long limit;
+
+    /**
+     * The expressions to use for sorting the feature instances.
+     *
+     * @see #getSortBy()
+     * @see #setSortBy(SortBy...)
+     */
+    private SortBy[] sortBy;
+
+    /**
+     * Creates a new query retrieving no column and applying no filter.
+     */
+    public SimpleQuery() {
+        filter = Filter.INCLUDE;
+        sortBy = SortBy.UNSORTED;
+        limit  = UNLIMITED;
     }
 
     /**
-     * Returns the query columns.
-     * @param columns query expressions or null to get all properties.
+     * Sets the columns to retrieve, or {@code null} if all columns shall be included in the query.
+     * A query column may use a simple or complex expression and an alias to create a new type of
+     * property in the returned features.
+     * This is equivalent to the column names in the {@code SELECT} clause of a SQL statement.
+     *
+     * @param columns columns to retrieve, or null to retrieve all properties.
      */
-    public void setColumns(List<Column> columns) {
+    @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
+    public void setColumns(Column... columns) {
+        columns = columns.clone();
+        for (int i=0; i<columns.length; i++) {
+            ArgumentChecks.ensureNonNullElement("columns", i, columns[i]);
+        }
         this.columns = columns;
     }
 
     /**
-     * Get query filter.
-     * The filter is used to trim features, features who do not pass the filter
-     * are discarded.<br>
-     * Discarded features are not counted is there is a query limit defined.
+     * Returns the columns to retrieve, or {@code null} if all columns shall be included in the query.
+     * This is the columns specified in the last call to {@link #setColumns(Column...)}.
      *
-     * @return query filter, never null
+     * @return columns to retrieve, or null to retrieve all feature properties.
      */
-    public Filter getFilter() {
-        return filter;
+    public List<Column> getColumns() {
+        return UnmodifiableArrayList.wrap(columns);
     }
 
     /**
-     * Set query filter.
+     * Sets a filter for trimming feature instances.
+     * Features that do not pass the filter are discarded.
+     * Discarded features are not counted for the {@linkplain #setLimit(long) query limit}.
      *
-     * @param filter not null, use Filter.INCLUDE for all results
+     * @param  filter  the filter, or {@link Filter#INCLUDE} if none.
      */
-    public void setFilter(Filter filter) {
+    public void setFilter(final Filter filter) {
+        ArgumentChecks.ensureNonNull("filter", filter);
         this.filter = filter;
     }
 
     /**
-     * Returns the query offset.
-     * The offset is the number of records to skip from the beginning.<br>
-     * Offset and limit are often combined to obtain paging.
+     * Returns the filter for trimming feature instances.
+     * This is the value specified in the last call to {@link #setFilter(Filter)}.
      *
-     * @return offset
+     * @return the filter, or {@link Filter#INCLUDE} if none.
      */
-    public long getOffset() {
-        return offset;
+    public Filter getFilter() {
+        return filter;
     }
 
     /**
-     * Set query start offset.
+     * Sets the number of records to skip from the beginning.
+     * Offset and limit are often combined to obtain paging.
+     * The offset can not be negative.
      *
-     * @param offset zero or positive
+     * <p>Note that setting this property can be costly on parallelized streams.
+     * See {@link java.util.stream.Stream#skip(long)} for more information.</p>
+     *
+     * @param  skip  the number of records to skip from the beginning.
      */
-    public void setOffset(long offset) {
-        this.offset = offset;
+    public void setOffset(final long skip) {
+        ArgumentChecks.ensurePositive("skip", skip);
+        this.skip = skip;
     }
 
     /**
-     * Returns the query limit.
-     * The limit is the maximum number of records that will contain the FeatureSet.<br>
-     * Offset and limit are often combined to obtain paging.
+     * Returns the number of records to skip from the beginning.
+     * This is the value specified in the last call to {@link #setOffset(long)}.
      *
-     * @return limit or -1 for unlimited
+     * @return the number of records to skip from the beginning.
      */
-    public long getLimit() {
-        return limit;
+    public long getOffset() {
+        return skip;
     }
 
     /**
-     * Set query limit.
+     * Set the maximum number of records contained in the {@code FeatureSet}.
+     * Offset and limit are often combined to obtain paging.
+     *
+     * <p>Note that setting this property can be costly on parallelized streams.
+     * See {@link java.util.stream.Stream#limit(long)} for more information.</p>
      *
-     * @param limit positive or -1 for unlimited
+     * @param  limit  maximum number of records contained in the {@code FeatureSet}, or {@link #UNLIMITED}.
      */
-    public void setLimit(long limit) {
+    public void setLimit(final long limit) {
+        if (limit != UNLIMITED) {
+            ArgumentChecks.ensurePositive("limit", limit);
+        }
         this.limit = limit;
     }
 
     /**
-     * Returns the query sort by parameters.
-     * SortBy objects are used to order Features returned by the FeatureSet.<br>
-     * The first SortBy is applied first then the others as in SQL.
+     * Returns the maximum number of records contained in the {@code FeatureSet}.
+     * This is the value specified in the last call to {@link #setLimit(long)}.
      *
-     * @return sort by array, never null, can be empty
+     * @return maximum number of records contained in the {@code FeatureSet}, or {@link #UNLIMITED}.
      */
-    public SortBy[] getSortBy() {
-        return sortBy == EMPTY_SORTBY ? EMPTY_SORTBY : sortBy.clone();
+    public long getLimit() {
+        return limit;
     }
 
     /**
-     * Set query sort by elements.
+     * Sets the expressions to use for sorting the feature instances.
+     * {@code SortBy} objects are used to order the {@link org.opengis.feature.Feature} instances
+     * returned by the {@link org.apache.sis.storage.FeatureSet}. {@code SortBy} clauses are applied
+     * in declaration order, like SQL.
      *
-     * @param sortBy
+     * @param  sortBy  expressions to use for sorting the feature instances.
      */
+    @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
     public void setSortBy(SortBy... sortBy) {
-        this.sortBy = sortBy == null ? EMPTY_SORTBY : sortBy;
+        if (sortBy == null || sortBy.length == 0) {
+            sortBy = SortBy.UNSORTED;
+        } else {
+            sortBy = sortBy.clone();
+            for (int i=0; i < sortBy.length; i++) {
+                ArgumentChecks.ensureNonNullElement("sortBy", i, sortBy[i]);
+            }
+        }
+        this.sortBy = sortBy;
     }
 
     /**
-     * Different FeatureSet may have more capabilities then what is provided
-     * with the SimpleQuery class.<br>
-     * Hints allow the user to pass more query parameters.<br>
-     * Unsupported hints will be ignored by the FeatureSet.<br>
-     * The returned map is modifiable.
+     * Returns the expressions to use for sorting the feature instances.
+     * They are the values specified in the last call to {@link #setSortBy(SortBy...)}.
      *
-     * @return modifiable map of query hints
+     * @return expressions to use for sorting the feature instances, or an empty array if none.
      */
-    public Map<String, Object> getHints() {
-        return hints;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 97 * hash + Objects.hashCode(this.columns);
-        hash = 97 * hash + Objects.hashCode(this.filter);
-        hash = 97 * hash + (int) (this.offset ^ (this.offset >>> 32));
-        hash = 97 * hash + (int) (this.limit ^ (this.limit >>> 32));
-        hash = 97 * hash + Arrays.deepHashCode(this.sortBy);
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final SimpleQuery other = (SimpleQuery) obj;
-        if (this.offset != other.offset) {
-            return false;
-        }
-        if (this.limit != other.limit) {
-            return false;
-        }
-        if (!Objects.equals(this.columns, other.columns)) {
-            return false;
-        }
-        if (!Objects.equals(this.filter, other.filter)) {
-            return false;
-        }
-        if (!Arrays.deepEquals(this.sortBy, other.sortBy)) {
-            return false;
-        }
-        if (!Objects.equals(this.hints, other.hints)) {
-            return false;
-        }
-        return true;
+    public SortBy[] getSortBy() {
+        return (sortBy.length == 0) ? SortBy.UNSORTED : sortBy.clone();
     }
 
-
     /**
-     * A query column.
-     * Just an expression and an optional alias.
+     * A property or expression to be retrieved by a {@code Query}, together with the name to assign to it.
+     * Columns can be given to the {@link SimpleQuery#setColumns(Column...)} method.
      */
     public static class Column {
+        /**
+         * The literal, property name or more complex expression to be retrieved by a {@code Query}.
+         */
         public final Expression expression;
+
+        /**
+         * The name to assign to the expression result, or {@code null} if unspecified.
+         */
         public final GenericName alias;
 
-        public Column(Expression expression) {
+        /**
+         * Creates a new column with the given expression and no name.
+         *
+         * @param expression  the literal, property name or expression to be retrieved by a {@code Query}.
+         */
+        public Column(final Expression expression) {
             ArgumentChecks.ensureNonNull("expression", expression);
             this.expression = expression;
             this.alias = null;
         }
 
-        public Column(Expression expression, GenericName alias) {
+        /**
+         * Creates a new column with the given expression and the given name.
+         *
+         * @param expression  the literal, property name or expression to be retrieved by a {@code Query}.
+         * @param alias       the name to assign to the expression result, or {@code null} if unspecified.
+         */
+        public Column(final Expression expression, final GenericName alias) {
             ArgumentChecks.ensureNonNull("expression", expression);
             this.expression = expression;
             this.alias = alias;
         }
 
-        public Column(Expression expression, String alias) {
+        /**
+         * Creates a new column with the given expression and the given name.
+         * This constructor creates a {@link org.opengis.util.LocalName} from the given string.
+         *
+         * @param expression  the literal, property name or expression to be retrieved by a {@code Query}.
+         * @param alias       the name to assign to the expression result, or {@code null} if unspecified.
+         */
+        public Column(final Expression expression, final String alias) {
             ArgumentChecks.ensureNonNull("expression", expression);
-            this.alias = alias == null ? null : Names.createLocalName(null, null, alias);
             this.expression = expression;
+            this.alias = (alias != null) ? Names.createLocalName(null, null, alias) : null;
         }
 
         /**
-         * Returns the column expected property type.
-         * @param type
-         * @return
+         * Returns the expected property type for this column.
+         *
+         * @see SimpleQuery#expectedType(FeatureType)
          */
-        public PropertyType expectedType(FeatureType type) {
+        final PropertyType expectedType(final FeatureType type) {
             PropertyType resultType;
             if (expression instanceof FeatureExpression) {
                 resultType = ((FeatureExpression) expression).expectedType(type);
             } else {
+                // TODO: remove this hack if we can get more type-safe Expression.
                 resultType = expression.evaluate(type, PropertyType.class);
             }
-            if (alias != null) {
-                //rename result type
-                if (resultType instanceof AttributeType) {
-                    resultType = new FeatureTypeBuilder().addAttribute((AttributeType<?>) resultType).setName(alias).build();
-                } else if (resultType instanceof FeatureAssociationRole) {
-                    resultType = new FeatureTypeBuilder().addAssociation((FeatureAssociationRole) resultType).setName(alias).build();
-                } else {
-                    throw new BackingStoreException("Expression "+expression+" returned an unexpected property type result "+resultType);
+            if (alias != null && !alias.equals(resultType.getName())) {
+                // Rename the result type.
+                resultType = new FeatureTypeBuilder().addProperty(resultType).setName(alias).build();
+                if (!(resultType instanceof AttributeType<?>) && !(resultType instanceof FeatureAssociationRole)) {
+                    throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyValueClass_3,
+                                alias, AttributeType.class, Classes.getStandardType(Classes.getClass(resultType))));
                 }
             }
             return resultType;
         }
 
+        /**
+         * Returns a hash code value for this column.
+         *
+         * @return a hash code value.
+         */
         @Override
         public int hashCode() {
-            int hash = 3;
-            hash = 29 * hash + Objects.hashCode(this.expression);
-            hash = 29 * hash + Objects.hashCode(this.alias);
-            return hash;
+            return 37 * expression.hashCode() + Objects.hashCode(alias);
         }
 
+        /**
+         * Compares this column with the given object for equality.
+         *
+         * @param  obj  the object to compare with this column.
+         * @return whether the two objects are equal.
+         */
         @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
+        public boolean equals(final Object obj) {
+            if (obj == this) {
                 return true;
             }
-            if (obj == null) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
+            if (obj != null && getClass() == obj.getClass()) {
+                final Column other = (Column) obj;
+                return expression.equals(other.expression) && Objects.equals(alias, other.alias);
             }
-            final Column other = (Column) obj;
-            if (!Objects.equals(this.expression, other.expression)) {
-                return false;
-            }
-            if (!Objects.equals(this.alias, other.alias)) {
-                return false;
+            return false;
+        }
+
+        /**
+         * Returns a string representation of this column for debugging purpose.
+         *
+         * @return a string representation of this column.
+         */
+        @Debug
+        @Override
+        public String toString() {
+            final StringBuilder b = new StringBuilder(getClass().getSimpleName()).append('[');
+            if (alias != null) {
+                b.append('"').append(alias).append('"');
             }
-            return true;
+            return b.append(']').toString();
         }
     }
 
     /**
-     * Execute the query on the CPU.
-     * <p>
-     * All operations are processed in java on the CPU, this may use considerable
-     * resources. Consider giving the query to the FeatureSet to allow it to
-     * optimize the query.
-     * <p>
-     * <p>
-     * The returned FeatureSet do not cache the resulting Features, the query is
-     * processed on each call to features() method.
-     * </p>
+     * Applies this query on the given feature set. The default implementation executes the query using the default
+     * {@link java.util.stream.Stream} methods.  Queries executed by this method may not benefit from accelerations
+     * provided for example by databases. This method should be used only as a fallback when the query can not be
+     * executed natively by {@link FeatureSet#subset(Query)}.
+     *
+     * <p>The returned {@code FeatureSet} does not cache the resulting {@code Feature} instances;
+     * the query is processed on every call to the {@link FeatureSet#features(boolean)} method.</p>
      *
-     * @param source base FeatureSet to process.
-     * @param query Query to apply on source
-     * @return resulting query FeatureSet
+     * @param  source  the set of features to filter, sort or process.
+     * @return a view over the given feature set containing only the filtered feature instances.
      */
-    public static FeatureSet executeOnCPU(FeatureSet source, SimpleQuery query) {
-        return new SimpleQueryFeatureSet(source, query);
+    public FeatureSet execute(final FeatureSet source) {
+        ArgumentChecks.ensureNonNull("source", source);
+        return new FeatureSetView(source, this);
     }
 
     /**
-     * Evaluate the expected returned type of a simple query.
-     *
-     * @param source
-     * @param query
-     * @return
+     * Returns the expected property type for this query executed on features of the given type.
      */
-    public static FeatureType expectedType(FeatureType source, SimpleQuery query) {
-
-        final List<Column> columns = query.getColumns();
-        if (columns == null) return source;
-
-        final FeatureTypeBuilder ftb = new FeatureTypeBuilder();
-        ftb.setName(source.getName());
-        for (Column col : columns) {
+    final FeatureType expectedType(final FeatureType source) {
+        if (columns == null) {
+            return source;          // All columns included: result is of the same type.
+        }
+        final FeatureTypeBuilder ftb = new FeatureTypeBuilder().setName(source.getName());
+        for (final Column col : columns) {
             ftb.addProperty(col.expectedType(source));
         }
         return ftb.build();
     }
+
+    /**
+     * Returns a hash code value for this query.
+     *
+     * @return a hash value for this query.
+     */
+    @Override
+    public int hashCode() {
+        return 97 * Arrays.hashCode(columns) + 31 * filter.hashCode()
+                + 7 * Arrays.hashCode(sortBy) + Long.hashCode(limit ^ skip);
+    }
+
+    /**
+     * Compares this query with the given object for equality.
+     *
+     * @param  obj  the object to compare with this query.
+     * @return whether the two objects are equal.
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj != null && getClass() == obj.getClass()) {
+            final SimpleQuery other = (SimpleQuery) obj;
+            return skip  == other.skip &&
+                   limit == other.limit &&
+                   filter.equals(other.filter) &&
+                   Arrays.equals(columns, other.columns) &&
+                   Arrays.equals(sortBy,  other.sortBy);
+        }
+        return true;
+    }
 }

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SortByComparator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SortByComparator.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SortByComparator.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SortByComparator.java [UTF-8] Mon May  7 17:32:22 2018
@@ -16,87 +16,101 @@
  */
 package org.apache.sis.internal.storage.query;
 
-import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
+import java.util.Iterator;
+import org.apache.sis.util.collection.Containers;
+
+// Branch-dependent imports
 import org.opengis.feature.Feature;
-import org.opengis.filter.expression.PropertyName;
 import org.opengis.filter.sort.SortBy;
 import org.opengis.filter.sort.SortOrder;
+import org.opengis.filter.expression.Expression;
+
 
 /**
- * Comparator to sort Features with a given array of query SortBy[].
+ * Comparator sorting features by an array of {@code SortBy} expressions, applied in order.
  *
- * @author Johann Sorel (Geomatys)
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
+ *
+ * @todo Current implementation has unchecked casts. Fixing that may require a revision of filter interfaces.
+ *       See <a href="https://github.com/opengeospatial/geoapi/issues/32">GeoAPI issue #32</a>.
  */
-public final class SortByComparator implements Comparator<Feature> {
+final class SortByComparator implements Comparator<Feature> {
+    /**
+     * The expression to evaluate for getting the values to sort.
+     */
+    private final Expression[] properties;
 
-    private final SortBy[] orders;
+    /**
+     * {@code false} for ascending order, {@code true} for descending order.
+     * If unspecified or unknown, we assume ascending order.
+     */
+    private final boolean[] descending;
 
-    public SortByComparator(final SortBy... orders) {
-        if (orders == null || orders.length == 0) {
-            throw new IllegalArgumentException("SortBy array can not be null or empty.");
+    /**
+     * Creates a new comparator for the given sort expressions.
+     * It is caller responsibility to ensure that the given array is non-empty.
+     */
+    SortByComparator(final SortBy[] orders) {
+        properties = new Expression[orders.length];
+        descending = new boolean   [orders.length];
+        for (int i=0; i<orders.length; i++) {
+            final SortBy order = orders[i];
+            properties[i] = order.getPropertyName();
+            descending[i] = SortOrder.DESCENDING.equals(order.getSortOrder());
         }
-
-        this.orders = orders;
     }
 
     /**
-     * {@inheritDoc }
+     * Compares two features for order. Returns -1 if {@code f1} should be sorted before {@code f2},
+     * +1 if {@code f2} should be after {@code f1}, or 0 if both are equal. Null features are sorted
+     * after all non-null features, regardless sorting order.
      */
     @Override
     public int compare(final Feature f1, final Feature f2) {
-
-        for (final SortBy order : orders) {
-            final PropertyName property = order.getPropertyName();
-            Object val1 = property.evaluate(f1);
-            Object val2 = property.evaluate(f2);
-            if (val1 instanceof Collection) {
-                //TODO find a correct way to compare collection values
-                //pick the first value
-                if (((Collection) val1).isEmpty()) {
-                    val1 = null;
-                } else {
-                    val1 = ((Collection) val1).iterator().next();
-                }
-            }
-            if (val2 instanceof Collection) {
-                //TODO find a correct way to compare collection values
-                //pick the first value
-                if (((Collection) val2).isEmpty()) {
-                    val2 = null;
-                } else {
-                    val2 = ((Collection) val2).iterator().next();
+        if (f1 != f2) {
+            if (f1 == null) return +1;
+            if (f2 == null) return -1;
+            for (int i=0; i<properties.length; i++) {
+                final Expression property = properties[i];
+                Comparable<?> o1 = (Comparable<?>) property.evaluate(f1);
+                Comparable<?> o2 = (Comparable<?>) property.evaluate(f2);
+                if (o1 != o2) {
+                    if (o1 == null) return +1;
+                    if (o2 == null) return -1;
+                    final int result;
+                    /*
+                     * No @SuppressWarnings("unchecked") below: those casts are really unsafe;
+                     * we can not make them safe with current Filter API. See GeoAPI issue #32.
+                     */
+                    if (o1 instanceof Iterable<?>) {
+                        result = Containers.compare(((Iterable) o1).iterator(), iterator(o2));
+                    } else if (o2 instanceof Iterable<?>) {
+                        result = Containers.compare(iterator(o1), ((Iterable) o2).iterator());
+                    } else {
+                        result = ((Comparable) o1).compareTo(o2);
+                    }
+                    if (result != 0) {
+                        return descending[i] ? -result : result;
+                    }
                 }
             }
-
-            final Comparable o1 = Comparable.class.cast(val1);
-            final Comparable o2 = Comparable.class.cast(val2);
-
-            if (o1 == null) {
-                if (o2 == null) {
-                    continue;
-                }
-                return -1;
-            } else if (o2 == null) {
-                return 1;
-            }
-
-            final int result;
-            if (order.getSortOrder() == SortOrder.ASCENDING) {
-                result = o1.compareTo(o2);
-            } else {
-                result = o2.compareTo(o1);
-            }
-
-            if (result != 0) {
-                return result;
-            }
         }
-
         return 0;
     }
 
+    /**
+     * Returns an iterator for the given object.
+     *
+     * @todo Intentionally raw return type, but no {@literal @SuppressWarning} annotation because this
+     *       is a real problem with current Filter API which needs to be fixed. See GeoAPI issue #32.
+     */
+    private static Iterator iterator(final Object o) {
+        return (o instanceof Iterable<?>) ? ((Iterable<?>) o).iterator() : Collections.singleton(o).iterator();
+    }
 }

Added: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/package-info.java?rev=1831113&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/package-info.java (added)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/package-info.java [UTF-8] Mon May  7 17:32:22 2018
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/**
+ * Default implementation of query operations.
+ *
+ * <STRONG>Do not use!</STRONG>
+ *
+ * This package is for internal use by SIS only. Classes in this package
+ * may change in incompatible ways in any future version without notice.
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+package org.apache.sis.internal.storage.query;

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

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

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/Query.java [UTF-8] Mon May  7 17:32:22 2018
@@ -33,15 +33,17 @@ import org.opengis.feature.Feature;
  * <code>{@linkplain java.util.function.Predicate}&lt;{@linkplain Feature}&gt;</code>
  * while the second domain is equivalent to using
  * <code>{@linkplain java.util.function.UnaryOperator}&lt;{@linkplain Feature}&gt;</code>.
- * It is technically possible to use {@code Query} for performing more generic feature transformations,
+ *
+ * <div class="note"><b>Note:</b>
+ * it is technically possible to use {@code Query} for performing more generic feature transformations,
  * for example inserting new properties computed from other properties, but such {@code Query} usages
  * should be rare since transformations (or more generic processing) are the topic of another package.
  * Queries are rather descriptive objects used by {@link FeatureSet} to optimize search operations
- * as much as possible on the resource, using for example caches and indexes.
+ * as much as possible on the resource, using for example caches and indexes.</div>
  *
- * <p>Compared to the SQL language, {@code Query} contains the information in the {@code SELECT} and
+ * Compared to the SQL language, {@code Query} contains the information in the {@code SELECT} and
  * {@code WHERE} clauses of a SQL statement. A {@code Query} typically contains filtering capabilities
- * and (sometime) simple attribute transformations. Well known query languages include SQL and CQL.</p>
+ * and (sometime) simple attribute transformations. Well known query languages include SQL and CQL.
  *
  * @author Johann Sorel (Geomatys)
  * @version 0.8

Modified: sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java?rev=1831113&r1=1831112&r2=1831113&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/query/SimpleQueryTest.java [UTF-8] Mon May  7 17:32:22 2018
@@ -24,24 +24,28 @@ import org.apache.sis.internal.storage.M
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.test.TestCase;
-import static org.junit.Assert.*;
 import org.junit.Test;
-import org.opengis.feature.AttributeType;
+
+import static org.junit.Assert.*;
+
+// Branch-dependent imports
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.PropertyType;
+import org.opengis.feature.AttributeType;
 import org.opengis.filter.MatchAction;
 import org.opengis.filter.sort.SortOrder;
 
+
 /**
  * Tests {@link SimpleQuery}.
  *
- * @author Johann Sorel (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
  */
-public class SimpleQueryTest extends TestCase {
+public final strictfp class SimpleQueryTest extends TestCase {
 
     private static final FeatureType TYPE;
     private static final Feature[] FEATURES;
@@ -76,7 +80,7 @@ public class SimpleQueryTest extends Tes
     /**
      * Verify query limit.
      *
-     * @throws DataStoreException
+     * @throws DataStoreException if an error occurred while executing the query.
      */
     @Test
     public void testLimit() throws DataStoreException {
@@ -84,7 +88,7 @@ public class SimpleQueryTest extends Tes
         final SimpleQuery query = new SimpleQuery();
         query.setLimit(2);
 
-        final FeatureSet fs = SimpleQuery.executeOnCPU(FEATURESET, query);
+        final FeatureSet fs = query.execute(FEATURESET);
         final Feature[] result = fs.features(false).collect(Collectors.toList()).toArray(new Feature[0]);
 
         assertEquals(FEATURES[0], result[0]);
@@ -94,7 +98,7 @@ public class SimpleQueryTest extends Tes
     /**
      * Verify query offset.
      *
-     * @throws DataStoreException
+     * @throws DataStoreException if an error occurred while executing the query.
      */
     @Test
     public void testOffset() throws DataStoreException {
@@ -102,7 +106,7 @@ public class SimpleQueryTest extends Tes
         final SimpleQuery query = new SimpleQuery();
         query.setOffset(2);
 
-        final FeatureSet fs = SimpleQuery.executeOnCPU(FEATURESET, query);
+        final FeatureSet fs = query.execute(FEATURESET);
         final Feature[] result = fs.features(false).collect(Collectors.toList()).toArray(new Feature[0]);
 
         assertEquals(FEATURES[2], result[0]);
@@ -113,7 +117,7 @@ public class SimpleQueryTest extends Tes
     /**
      * Verify query sortby.
      *
-     * @throws DataStoreException
+     * @throws DataStoreException if an error occurred while executing the query.
      */
     @Test
     public void testSortBy() throws DataStoreException {
@@ -125,7 +129,7 @@ public class SimpleQueryTest extends Tes
                 factory.sort("value2", SortOrder.DESCENDING)
         );
 
-        final FeatureSet fs = SimpleQuery.executeOnCPU(FEATURESET, query);
+        final FeatureSet fs = query.execute(FEATURESET);
         final Feature[] result = fs.features(false).collect(Collectors.toList()).toArray(new Feature[0]);
 
         assertEquals(FEATURES[3], result[0]);
@@ -138,7 +142,7 @@ public class SimpleQueryTest extends Tes
     /**
      * Verify query filter.
      *
-     * @throws DataStoreException
+     * @throws DataStoreException if an error occurred while executing the query.
      */
     @Test
     public void testFilter() throws DataStoreException {
@@ -147,7 +151,7 @@ public class SimpleQueryTest extends Tes
         final SimpleQuery query = new SimpleQuery();
         query.setFilter(factory.equal(factory.property("value1"), factory.literal(2), true, MatchAction.ALL));
 
-        final FeatureSet fs = SimpleQuery.executeOnCPU(FEATURESET, query);
+        final FeatureSet fs = query.execute(FEATURESET);
         final Feature[] result = fs.features(false).collect(Collectors.toList()).toArray(new Feature[0]);
 
         assertEquals(FEATURES[1], result[0]);
@@ -157,21 +161,19 @@ public class SimpleQueryTest extends Tes
     /**
      * Verify query columns.
      *
-     * @throws DataStoreException
+     * @throws DataStoreException if an error occurred while executing the query.
      */
     @Test
     public void testColumns() throws DataStoreException {
         final DefaultFilterFactory factory = new DefaultFilterFactory();
 
         final SimpleQuery query = new SimpleQuery();
-        query.setColumns(Arrays.asList(
-                new SimpleQuery.Column(factory.property("value1"), (String)null),
-                new SimpleQuery.Column(factory.property("value1"), "renamed1"),
-                new SimpleQuery.Column(factory.literal("a literal"), "computed")
-            ));
+        query.setColumns(new SimpleQuery.Column(factory.property("value1"), (String)null),
+                         new SimpleQuery.Column(factory.property("value1"), "renamed1"),
+                         new SimpleQuery.Column(factory.literal("a literal"), "computed"));
         query.setLimit(1);
 
-        final FeatureSet fs = SimpleQuery.executeOnCPU(FEATURESET, query);
+        final FeatureSet fs = query.execute(FEATURESET);
         final Feature[] results = fs.features(false).collect(Collectors.toList()).toArray(new Feature[0]);
         assertEquals(1, results.length);
 



Mime
View raw message