You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2021/09/09 14:11:27 UTC

[sis] 02/03: Filter implementations override Predicate.and/or/not methods.

This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 3b0f5c0e9303cd2d08f623e192c1a91f3a3a8751
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Sep 9 12:38:36 2021 +0200

    Filter implementations override Predicate.and/or/not methods.
---
 .../apache/sis/filter/BinaryGeometryFilter.java    |  3 +-
 .../org/apache/sis/filter/ComparisonFilter.java    |  3 +-
 .../apache/sis/filter/DefaultFilterFactory.java    | 32 ++++++++
 .../java/org/apache/sis/filter/FilterNode.java     | 90 ++++++++++++++++++++++
 .../org/apache/sis/filter/IdentifierFilter.java    |  3 +-
 .../java/org/apache/sis/filter/LikeFilter.java     |  3 +-
 .../java/org/apache/sis/filter/LogicalFilter.java  | 25 +++++-
 .../java/org/apache/sis/filter/Optimization.java   | 50 ++++++++++++
 .../org/apache/sis/filter/LogicalFilterTest.java   | 10 +++
 9 files changed, 208 insertions(+), 11 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java
index e1afc00..cd60f3f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryGeometryFilter.java
@@ -27,7 +27,6 @@ import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.internal.feature.GeometryWrapper;
 import org.apache.sis.internal.feature.SpatialOperationContext;
 import org.apache.sis.internal.feature.AttributeConvention;
-import org.apache.sis.internal.filter.Node;
 import org.apache.sis.util.ArgumentChecks;
 
 // Branch-dependent imports
@@ -58,7 +57,7 @@ import org.opengis.feature.PropertyNotFoundException;
  * @since 1.1
  * @module
  */
-abstract class BinaryGeometryFilter<R,G> extends Node implements SpatialOperator<R>, Optimization.OnFilter<R> {
+abstract class BinaryGeometryFilter<R,G> extends FilterNode<R> implements SpatialOperator<R>, Optimization.OnFilter<R> {
     /**
      * For cross-version compatibility.
      */
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java
index 76d4a0b..b6a8f0a 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFilter.java
@@ -35,7 +35,6 @@ import java.time.chrono.ChronoLocalDateTime;
 import java.time.chrono.ChronoZonedDateTime;
 import java.time.temporal.ChronoField;
 import java.time.temporal.Temporal;
-import org.apache.sis.internal.filter.Node;
 import org.apache.sis.math.Fraction;
 import org.apache.sis.util.ArgumentChecks;
 
@@ -786,7 +785,7 @@ abstract class ComparisonFilter<R> extends BinaryFunction<R,Object,Object>
      *
      * @see org.apache.sis.filter.LogicalFilter.And
      */
-    static final class Between<R> extends Node implements BetweenComparisonOperator<R> {
+    static final class Between<R> extends FilterNode<R> implements BetweenComparisonOperator<R> {
         /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = -2434954008425799595L;
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
index 029eb4e..f028cb8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
@@ -430,6 +430,22 @@ public abstract class DefaultFilterFactory<R,G,T> extends AbstractFactory implem
     }
 
     /**
+     * Creates a {@code AND} filter between two filters.
+     *
+     * @param  operand1  the first operand of the AND operation.
+     * @param  operand2  the second operand of the AND operation.
+     * @return a filter evaluating {@code operand1 AND operand2}.
+     *
+     * @see LogicalOperatorName#AND
+     */
+    @Override
+    public LogicalOperator<R> and(final Filter<? super R> operand1, final Filter<? super R> operand2) {
+        ArgumentChecks.ensureNonNull("operand1", operand1);
+        ArgumentChecks.ensureNonNull("operand2", operand2);
+        return new LogicalFilter.And<>(operand1, operand2);
+    }
+
+    /**
      * Creates a {@code AND} filter between two or more filters.
      *
      * @param  operands  a collection of at least 2 operands.
@@ -444,6 +460,22 @@ public abstract class DefaultFilterFactory<R,G,T> extends AbstractFactory implem
     }
 
     /**
+     * Creates a {@code OR} filter between two filters.
+     *
+     * @param  operand1  the first operand of the OR operation.
+     * @param  operand2  the second operand of the OR operation.
+     * @return a filter evaluating {@code operand1 OR operand2}.
+     *
+     * @see LogicalOperatorName#OR
+     */
+    @Override
+    public LogicalOperator<R> or(final Filter<? super R> operand1, final Filter<? super R> operand2) {
+        ArgumentChecks.ensureNonNull("operand1", operand1);
+        ArgumentChecks.ensureNonNull("operand2", operand2);
+        return new LogicalFilter.Or<>(operand1, operand2);
+    }
+
+    /**
      * Creates a {@code OR} filter between two or more filters.
      *
      * @param  operands  a collection of at least 2 operands.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/FilterNode.java b/core/sis-feature/src/main/java/org/apache/sis/filter/FilterNode.java
new file mode 100644
index 0000000..8a1186a
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/FilterNode.java
@@ -0,0 +1,90 @@
+/*
+ * 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.filter;
+
+import java.util.function.Predicate;
+import org.apache.sis.internal.filter.Node;
+
+// Branch-dependent imports
+import org.opengis.filter.Filter;
+
+
+/**
+ * Base class of some (not all) nodes that are filters. This base class overrides {@link Predicate}
+ * methods for building other {@link Filter} objects instead than default Java implementations that
+ * Apache SIS can not recognize.
+ *
+ * <p><b>Note:</b> this class duplicates the method definition in {@link Optimization.OnFilter}.
+ * This duplication exists because not all filter implementations extends this class, and not all
+ * implementations implement the {@link Optimization.OnFilter} interface.</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ *
+ * @param  <R>  the type of resources (e.g. {@link org.opengis.feature.Feature}) used as inputs.
+ *
+ * @since 1.1
+ * @module
+ */
+abstract class FilterNode<R> extends Node implements Filter<R> {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -1272149643938168189L;
+
+    /**
+     * Creates a new node.
+     */
+    FilterNode() {
+    }
+
+    /**
+     * Returns the {@code AND} logical operation between this filter and the given predicate.
+     * This method duplicates the {@link Optimization.OnFilter#and(Predicate)} method, but is
+     * defined because not all subclasses implement the {@code Optimization} inner interface.
+     */
+    @Override
+    public final Predicate<R> and(final Predicate<? super R> other) {
+        if (other instanceof Filter<?>) {
+            return new LogicalFilter.And<>(this, (Filter<? super R>) other);
+        } else {
+            return Filter.super.and(other);
+        }
+    }
+
+    /**
+     * Returns the {@code OR} logical operation between this filter and the given predicate.
+     * This method duplicates the {@link Optimization.OnFilter#or(Predicate)} method, but is
+     * defined because not all subclasses implement the {@code Optimization} inner interface.
+     */
+    @Override
+    public final Predicate<R> or(final Predicate<? super R> other) {
+        if (other instanceof Filter<?>) {
+            return new LogicalFilter.Or<>(this, (Filter<? super R>) other);
+        } else {
+            return Filter.super.and(other);
+        }
+    }
+
+    /**
+     * Returns the logical negation of this filter.
+     */
+    @Override
+    public final Predicate<R> negate() {
+        return new LogicalFilter.Not<>(this);
+    }
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java
index 96b87dd..74b4c65 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/IdentifierFilter.java
@@ -20,7 +20,6 @@ import java.util.List;
 import java.util.Collection;
 import java.util.Collections;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.internal.filter.Node;
 import org.apache.sis.internal.feature.AttributeConvention;
 
 // Branch-dependent imports
@@ -42,7 +41,7 @@ import org.opengis.filter.ResourceId;
  * @since 1.1
  * @module
  */
-final class IdentifierFilter<R extends Feature> extends Node implements ResourceId<R> {
+final class IdentifierFilter<R extends Feature> extends FilterNode<R> implements ResourceId<R> {
     /**
      * For cross-version compatibility.
      */
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java
index 019b264..96c335c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/LikeFilter.java
@@ -20,7 +20,6 @@ import java.util.List;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.regex.Pattern;
-import org.apache.sis.internal.filter.Node;
 import org.apache.sis.util.ArgumentChecks;
 
 // Branch-dependent imports
@@ -41,7 +40,7 @@ import org.opengis.filter.LikeOperator;
  * @since 1.1
  * @module
  */
-final class LikeFilter<R> extends Node implements LikeOperator<R>, Optimization.OnFilter<R> {
+final class LikeFilter<R> extends FilterNode<R> implements LikeOperator<R>, Optimization.OnFilter<R> {
     /**
      * For cross-version compatibility.
      */
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java b/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java
index ef2b878..fe849e4 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/LogicalFilter.java
@@ -21,7 +21,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.internal.filter.Node;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.util.resources.Errors;
@@ -45,7 +44,7 @@ import org.opengis.filter.LogicalOperatorName;
  * @since 1.1
  * @module
  */
-abstract class LogicalFilter<R> extends Node implements LogicalOperator<R>, Optimization.OnFilter<R> {
+abstract class LogicalFilter<R> extends FilterNode<R> implements LogicalOperator<R>, Optimization.OnFilter<R> {
     /**
      * For cross-version compatibility.
      */
@@ -74,6 +73,16 @@ abstract class LogicalFilter<R> extends Node implements LogicalOperator<R>, Opti
     }
 
     /**
+     * Creates a new logical operator with the two given operands.
+     * This method does not verify if the operands are non-null;
+     * this check should be already done by the caller.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    LogicalFilter(final Filter<? super R> operand1, final Filter<? super R> operand2) {
+        operands = new Filter[] {operand1, operand2};
+    }
+
+    /**
      * Creates a new logical operator of the same kind than this operator.
      *
      * @param  op  operands of the new operator.
@@ -111,6 +120,11 @@ abstract class LogicalFilter<R> extends Node implements LogicalOperator<R>, Opti
             super(op);
         }
 
+        /** Creates a new operator for the two given operands. */
+        And(final Filter<? super R> operand1, final Filter<? super R> operand2) {
+            super(operand1, operand2);
+        }
+
         /** Creates a new logical operator of the same kind than this operator. */
         @Override protected LogicalFilter<R> createSameType(Collection<? extends Filter<? super R>> op) {
             return new And<>(op);
@@ -155,6 +169,11 @@ abstract class LogicalFilter<R> extends Node implements LogicalOperator<R>, Opti
             super(op);
         }
 
+        /** Creates a new operator for the two given operands. */
+        Or(final Filter<? super R> operand1, final Filter<? super R> operand2) {
+            super(operand1, operand2);
+        }
+
         /** Creates a new logical operator of the same kind than this operator. */
         @Override protected LogicalFilter<R> createSameType(Collection<? extends Filter<? super R>> op) {
             return new Or<>(op);
@@ -190,7 +209,7 @@ abstract class LogicalFilter<R> extends Node implements LogicalOperator<R>, Opti
     /**
      * The negation filter (¬).
      */
-    static final class Not<R> extends Node implements LogicalOperator<R>, Optimization.OnFilter<R> {
+    static final class Not<R> extends FilterNode<R> implements LogicalOperator<R>, Optimization.OnFilter<R> {
         /** For cross-version compatibility. */
         private static final long serialVersionUID = -1296823195138427781L;
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java b/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java
index 2ea41df..ccd3fd7 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/Optimization.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.ConcurrentModificationException;
+import java.util.function.Predicate;
 import org.opengis.util.CodeList;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.CollectionsExt;
@@ -230,6 +231,55 @@ public class Optimization {
         default Filter<R> recreate(Expression<? super R, ?>[] effective) {
             return this;
         }
+
+        /**
+         * Returns the {@code AND} logical operation between this filter and the given predicate.
+         * If the given predicate is an instance of {@link Filter}, then the returned predicate
+         * is an instance of {@code Optimization.OnFilter}.
+         *
+         * @param  other  the other predicate.
+         * @return the {@code AND} logical operation between this filter and the given predicate.
+         *
+         * @see DefaultFilterFactory#and(Filter, Filter)
+         */
+        @Override
+        default Predicate<R> and(final Predicate<? super R> other) {
+            if (other instanceof Filter<?>) {
+                return new LogicalFilter.And<>(this, (Filter<? super R>) other);
+            } else {
+                return Filter.super.and(other);
+            }
+        }
+
+        /**
+         * Returns the {@code OR} logical operation between this filter and the given predicate.
+         * If the given predicate is an instance of {@link Filter}, then the returned predicate
+         * is an instance of {@code Optimization.OnFilter}.
+         *
+         * @param  other  the other predicate.
+         * @return the {@code OR} logical operation between this filter and the given predicate.
+         *
+         * @see DefaultFilterFactory#or(Filter, Filter)
+         */
+        @Override
+        default Predicate<R> or(final Predicate<? super R> other) {
+            if (other instanceof Filter<?>) {
+                return new LogicalFilter.Or<>(this, (Filter<? super R>) other);
+            } else {
+                return Filter.super.and(other);
+            }
+        }
+
+        /**
+         * Returns the logical negation of this filter.
+         * The returned predicate is an instance of {@code Optimization.OnFilter}.
+         *
+         * @return the logical negation of this filter.
+         */
+        @Override
+        default Predicate<R> negate() {
+            return new LogicalFilter.Not<>(this);
+        }
     }
 
     /**
diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/LogicalFilterTest.java b/core/sis-feature/src/test/java/org/apache/sis/filter/LogicalFilterTest.java
index 242a31d..073c715 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/filter/LogicalFilterTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/LogicalFilterTest.java
@@ -92,6 +92,16 @@ public final strictfp class LogicalFilterTest extends TestCase {
     }
 
     /**
+     * Verifies that {@link Filter#negate()} is overridden.
+     */
+    @Test
+    public void testNegate() {
+        final Literal<Feature,String>  literal = factory.literal("text");
+        final Filter<Feature>          operand = factory.isNull(literal);
+        assertInstanceOf("Predicate.negate()", LogicalFilter.Not.class, operand.negate());
+    }
+
+    /**
      * Implementation of {@link #testAnd()} and {@link #testOr()}.
      *
      * @param  binary    the function creating a logical operator from two operands.