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.