package org.infinispan.objectfilter.impl.predicateindex.be; import java.util.List; import org.infinispan.objectfilter.impl.predicateindex.FilterEvalContext; import org.infinispan.objectfilter.impl.predicateindex.IntervalPredicate; import org.infinispan.objectfilter.impl.predicateindex.Predicate; /** * A PredicateNode is a leaf node in a BETree that holds a Predicate instance. A PredicateNode instance is never reused * inside the same BETree or shared between multiple BETrees, but an entire BETree could be shared by multiple filters. * Multiple PredicateNodes could share the same Predicate instance. * * @author anistor@redhat.com * @since 7.0 */ public final class PredicateNode<AttributeId extends Comparable<AttributeId>> extends BENode { // the predicate can be shared by multiple PredicateNodes private final Predicate<?> predicate; /** * Indicates if the Predicate's condition is negated. This can be true only for condition predicates, never for * interval predicates. */ private final boolean isNegated; private final List<AttributeId> attributePath; public PredicateNode(BENode parent, Predicate<?> predicate, boolean isNegated, List<AttributeId> attributePath) { super(parent); if (isNegated && predicate instanceof IntervalPredicate) { throw new IllegalArgumentException("Interval predicates should not be negated"); } this.predicate = predicate; this.isNegated = isNegated; this.attributePath = attributePath; } public Predicate<?> getPredicate() { return predicate; } public boolean isNegated() { return isNegated; } public List<AttributeId> getAttributePath() { return attributePath; } @Override public void handleChildValue(BENode child, boolean childValue, FilterEvalContext evalContext) { if (child != null) { throw new IllegalArgumentException("Predicates have value but do not have children"); } final int value = childValue ? BETree.EXPR_TRUE : BETree.EXPR_FALSE; if (isEvaluationComplete(evalContext)) { if (predicate.isRepeated() && evalContext.treeCounters[startIndex] == value) { // receiving the same value multiple times is fine if this is a repeated condition return; } throw new IllegalStateException("This should never be called again if the state of this node was previously decided."); } if (parent == null) { evalContext.treeCounters[startIndex] = value; suspendSubscription(evalContext); } else { parent.handleChildValue(this, childValue, evalContext); } } @Override public void suspendSubscription(FilterEvalContext ctx) { if (predicate.isRepeated()) { ctx.matcherContext.addSuspendedSubscription(predicate); } } @Override public String toString() { return "PredicateNode{" + "attributePath=" + attributePath + ", isNegated=" + isNegated + ", predicate=" + predicate + '}'; } }