mirror of https://github.com/apache/activemq.git
Merge pull request #842 from eolivelli/AMQ-8613
AMQ-8613 Improve performance of selectors with a big sequence of OR and AND logical expressions
This commit is contained in:
commit
7006570c1d
|
@ -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<BooleanExpression> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue