| /* |
| * 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.List; |
| import java.util.Collection; |
| import java.util.Objects; |
| import java.util.Optional; |
| import org.apache.sis.xml.NilReason; |
| import org.apache.sis.filter.internal.Node; |
| |
| // Specific to the main branch: |
| import org.apache.sis.pending.geoapi.filter.ComparisonOperatorName; |
| |
| |
| /** |
| * Base class for expressions, comparators or filters performing operations on one expressions. |
| * The nature of the operation depends on the subclass. |
| * |
| * @author Johann Sorel (Geomatys) |
| * @author Martin Desruisseaux (Geomatys) |
| * |
| * @param <R> the type of resources (e.g. {@code Feature}) used as inputs. |
| * @param <V> the type of value computed by the expression. |
| */ |
| class UnaryFunction<R,V> extends Node { |
| /** |
| * For cross-version compatibility. |
| */ |
| private static final long serialVersionUID = 2020526901451551162L; |
| |
| /** |
| * The expression to be used by this operator. |
| * |
| * @see #getExpression() |
| */ |
| @SuppressWarnings("serial") // Most SIS implementations are serializable. |
| protected final Expression<R, ? extends V> expression; |
| |
| /** |
| * Creates a new unary operator. |
| */ |
| UnaryFunction(final Expression<R, ? extends V> expression) { |
| this.expression = Objects.requireNonNull(expression); |
| } |
| |
| /** |
| * Returns the class of resources expected by this filter. |
| * Defined for {@link Filter#getResourceClass()} implementations. |
| * |
| * @return type of resources accepted by this filter, or {@code null} if inconsistent. |
| */ |
| public final Class<? super R> getResourceClass() { |
| return expression.getResourceClass(); |
| } |
| |
| /** |
| * Returns the expression used as parameter by this function. |
| * Defined for {@link Expression#getParameters()} implementations. |
| */ |
| public final List<Expression<R,?>> getParameters() { |
| return getExpressions(); |
| } |
| |
| /** |
| * Returns the expression used as parameter by this filter. |
| * Defined for {@link Filter#getExpressions()} implementations. |
| * |
| * @return a list of size 1 containing the singleton expression. |
| */ |
| public final List<Expression<R,?>> getExpressions() { |
| return List.of(expression); |
| } |
| |
| /** |
| * Returns the expression used by this operator possibly completed in subclasses with other parameters. |
| * This is used for {@link #toString()}, {@link #hashCode()} and {@link #equals(Object)} implementations. |
| */ |
| @Override |
| protected Collection<?> getChildren() { |
| return getExpressions(); |
| } |
| |
| |
| /** |
| * Filter operator that checks if an expression's value is {@code null}. A {@code null} |
| * is equivalent to no value present. The value 0 is a valid value and is not considered |
| * {@code null}. |
| * |
| * @param <R> the type of resources used as inputs. |
| */ |
| static final class IsNull<R> extends UnaryFunction<R,Object> |
| implements Filter<R>, Optimization.OnFilter<R> |
| { |
| /** For cross-version compatibility. */ |
| private static final long serialVersionUID = 2960285515924533419L; |
| |
| /** Creates a new operator. */ |
| IsNull(final Expression<R,?> expression) { |
| super(expression); |
| } |
| |
| @Override public ComparisonOperatorName getOperatorType() { |
| return ComparisonOperatorName.PROPERTY_IS_NULL; |
| } |
| |
| /** Creates a new filter of the same type but different parameters. */ |
| @Override public Filter<R> recreate(final Expression<R,?>[] effective) { |
| return new IsNull<>(effective[0]); |
| } |
| |
| /** Identification of the operation. */ |
| @Override protected char symbol() { |
| return '∅'; |
| } |
| |
| /** Evaluate this filter on the given object. */ |
| @Override public boolean test(final R object) { |
| return expression.apply(object) == null; |
| } |
| } |
| |
| |
| /** |
| * Filter operator that checks if an expression's value is nil. |
| * The difference with {@link IsNull} is that a value should exist but |
| * cannot be provided for the reason given by {@link #getNilReason()}. |
| * |
| * @param <R> the type of resources used as inputs. |
| */ |
| static final class IsNil<R> extends UnaryFunction<R,Object> |
| implements Filter<R>, Optimization.OnFilter<R> |
| { |
| /** For cross-version compatibility. */ |
| private static final long serialVersionUID = -7540765433296725888L; |
| |
| /** The reason why the value is nil, or {@code null} for accepting any reason. */ |
| private final String nilReason; |
| |
| /** Creates a new operator. */ |
| IsNil(final Expression<R,?> expression, final String nilReason) { |
| super(expression); |
| this.nilReason = nilReason; |
| } |
| |
| @Override public ComparisonOperatorName getOperatorType() { |
| return ComparisonOperatorName.PROPERTY_IS_NIL; |
| } |
| |
| /** Creates a new filter of the same type but different parameters. */ |
| @Override public Filter<R> recreate(final Expression<R,?>[] effective) { |
| return new IsNil<>(effective[0], nilReason); |
| } |
| |
| /** Returns the reason why the value is nil. */ |
| public Optional<String> getNilReason() { |
| return Optional.ofNullable(nilReason); |
| } |
| |
| /** Evaluate this filter on the given object. */ |
| @Override public boolean test(final R object) { |
| final NilReason value = NilReason.forObject(expression.apply(object)); |
| if (value == null) return false; |
| if (nilReason == null) return true; |
| final String explanation = value.equals(NilReason.OTHER) ? value.getOtherExplanation() : value.toString(); |
| return nilReason.equalsIgnoreCase(explanation); |
| } |
| } |
| } |