diff --git a/activemq-client/src/main/java/org/apache/activemq/filter/LogicExpression.java b/activemq-client/src/main/java/org/apache/activemq/filter/LogicExpression.java index fdc022baef..e9145a9717 100644 --- a/activemq-client/src/main/java/org/apache/activemq/filter/LogicExpression.java +++ b/activemq-client/src/main/java/org/apache/activemq/filter/LogicExpression.java @@ -17,78 +17,171 @@ package org.apache.activemq.filter; import javax.jms.JMSException; +import java.util.ArrayList; +import java.util.List; /** - * A filter performing a comparison of two objects - * - * + * A sequence of expressions, to be combined with OR or AND conjunctions. + * */ -public abstract class LogicExpression extends BinaryExpression implements BooleanExpression { +public abstract class LogicExpression implements BooleanExpression { + + protected final List expressions = new ArrayList<>(2); + + private LogicExpression(BooleanExpression lvalue, BooleanExpression rvalue) { + expressions.add(lvalue); + expressions.add(rvalue); + } + + protected void addExpression(BooleanExpression expression) { + expressions.add(expression); + } + + public BooleanExpression getLeft() { + if (expressions.size() == 2) { + return expressions.get(0); + } + throw new IllegalStateException("This expression is not binary: " + this); + } + + public BooleanExpression getRight() { + if (expressions.size() == 2) { + return expressions.get(1); + } + throw new IllegalStateException("This expression is not binary: " + this); + } /** - * @param left - * @param right + * Returns the symbol that represents this binary expression. For example, addition is + * represented by "+" + * + * @return */ - public LogicExpression(BooleanExpression left, BooleanExpression right) { - super(left, right); + public abstract String getExpressionSymbol(); + + @Override + public String toString() { + if (expressions.size() == 2) { + return "( " + expressions.get(0) + " " + getExpressionSymbol() + " " + expressions.get(1) + " )"; + } + StringBuilder result = new StringBuilder("("); + int count = 0; + for (BooleanExpression expression : expressions) { + if (count++ > 0) { + result.append(" " + getExpressionSymbol() + " "); + } + result.append(expression.toString()); + } + result.append(")"); + return result.toString(); } public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { - return new LogicExpression(lvalue, rvalue) { - - public Object evaluate(MessageEvaluationContext message) throws JMSException { - - Boolean lv = (Boolean)left.evaluate(message); - if (lv != null && lv.booleanValue()) { - return Boolean.TRUE; - } - Boolean rv = (Boolean)right.evaluate(message); - if (rv != null && rv.booleanValue()) { - return Boolean.TRUE; - } - if (lv == null || rv == null) { - return null; - } - return Boolean.FALSE; - } - - public String getExpressionSymbol() { - return "OR"; - } - }; + if (lvalue instanceof ORExpression) { + ORExpression orExpression = (ORExpression) lvalue; + orExpression.addExpression(rvalue); + return orExpression; + } else { + return new ORExpression(lvalue, rvalue); + } } public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { - return new LogicExpression(lvalue, rvalue) { + if (lvalue instanceof ANDExpression) { + ANDExpression orExpression = (ANDExpression) lvalue; + orExpression.addExpression(rvalue); + return orExpression; + } else { + return new ANDExpression(lvalue, rvalue); + } + } - public Object evaluate(MessageEvaluationContext message) throws JMSException { + @Override + public abstract Object evaluate(MessageEvaluationContext message) throws JMSException; - Boolean lv = (Boolean)left.evaluate(message); + @Override + public abstract boolean matches(MessageEvaluationContext message) throws JMSException; + public static class ORExpression extends LogicExpression { + + public ORExpression(BooleanExpression lvalue, BooleanExpression rvalue) { + super(lvalue, rvalue); + } + + @Override + public Object evaluate(MessageEvaluationContext message) throws JMSException { + boolean someNulls = false; + for (BooleanExpression expression : expressions) { + Boolean lv = (Boolean)expression.evaluate(message); + if (lv != null && lv.booleanValue()) { + return Boolean.TRUE; + } + if (lv == null) { + someNulls = true; + } + } + if (someNulls) { + return null; + } + return Boolean.FALSE; + } + + @Override + public boolean matches(MessageEvaluationContext message) throws JMSException { + for (BooleanExpression expression : expressions) { + boolean lv = expression.matches(message); + if (lv) { + return true; + } + } + return false; + } + + @Override + public String getExpressionSymbol() { + return "OR"; + } + + } + + private static class ANDExpression extends LogicExpression { + + public ANDExpression(BooleanExpression lvalue, BooleanExpression rvalue) { + super(lvalue, rvalue); + } + + @Override + public Object evaluate(MessageEvaluationContext message) throws JMSException { + boolean someNulls = false; + for (BooleanExpression expression : expressions) { + Boolean lv = (Boolean)expression.evaluate(message); if (lv != null && !lv.booleanValue()) { return Boolean.FALSE; } - Boolean rv = (Boolean)right.evaluate(message); - if (rv != null && !rv.booleanValue()) { - return Boolean.FALSE; + if (lv == null) { + someNulls = true; } - if (lv == null || rv == null) { - return null; + } + if (someNulls) { + return null; + } + return Boolean.TRUE; + } + + @Override + public boolean matches(MessageEvaluationContext message) throws JMSException { + for (BooleanExpression expression : expressions) { + boolean lv = expression.matches(message); + if (!lv) { + return false; } - return Boolean.TRUE; } + return true; + } - public String getExpressionSymbol() { - return "AND"; - } - }; + @Override + public String getExpressionSymbol() { + return "AND"; + } } - - public abstract Object evaluate(MessageEvaluationContext message) throws JMSException; - - public boolean matches(MessageEvaluationContext message) throws JMSException { - Object object = evaluate(message); - return object != null && object == Boolean.TRUE; - } - } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/selector/SelectorTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/selector/SelectorTest.java index 3ad84302f5..00d71a2bfb 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/selector/SelectorTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/selector/SelectorTest.java @@ -40,7 +40,10 @@ public class SelectorTest extends TestCase { assertSelector(message, "(trueProp OR falseProp) AND trueProp", true); assertSelector(message, "(trueProp OR falseProp) AND falseProp", false); assertSelector(message, "trueProp", true); - + assertSelector(message, "(falseProp OR falseProp OR falseProp OR falseProp OR falseProp OR falseProp OR trueProp)", true); + assertSelector(message, "(falseProp OR falseProp OR falseProp OR falseProp OR falseProp OR falseProp OR falseProp)", false); + assertSelector(message, "(trueProp AND trueProp AND trueProp AND trueProp AND trueProp AND trueProp AND falseProp)", false); + assertSelector(message, "(trueProp AND trueProp AND trueProp AND trueProp AND trueProp AND trueProp AND trueProp)", true); } public void testXPathSelectors() throws Exception {