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 <martin.desruisse...@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.

Reply via email to