Author: davsclaus
Date: Tue Aug 24 18:18:41 2010
New Revision: 988647
URL: http://svn.apache.org/viewvc?rev=988647&view=rev
Log:
CAMEL-3075: Simple language now supports using unlimited and,or operators.
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerPollStrategyTest.java
camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java
camel/trunk/camel-core/src/test/resources/log4j.properties
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java?rev=988647&r1=988646&r2=988647&view=diff
==============================================================================
---
camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java
(original)
+++
camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java
Tue Aug 24 18:18:41 2010
@@ -30,6 +30,7 @@ import org.apache.camel.builder.Expressi
import org.apache.camel.builder.PredicateBuilder;
import org.apache.camel.builder.ValueBuilder;
import org.apache.camel.spi.Language;
+import org.apache.camel.util.KeyValueHolder;
import org.apache.camel.util.ObjectHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -41,27 +42,49 @@ import static org.apache.camel.language.
public abstract class SimpleLanguageSupport implements Language, IsSingleton {
// this is a regex for a given group in a simple expression that uses
operators
- protected static final String GROUP_PATTERN =
+ protected static final String OPERATOR_REGEX =
"\\$\\{(\\S+)\\}\\s+(==|>|>=|<|<=|!=|contains|not contains|regex|not
regex|in|not in|is|not is|range|not range)\\s+('.*?'|\\S+)";
// this is the operator reg ex pattern used to match if a given expression
is operator based or not
- protected static final Pattern PATTERN = Pattern.compile("^(" +
GROUP_PATTERN + ")(\\s+(and|or)\\s+(" + GROUP_PATTERN + "))?$");
+ protected static final Pattern OPERATOR_PATTERN =
Pattern.compile(OPERATOR_REGEX);
+
+ // two specialized pattern for matching/finding multiple expressions
combined using multiple and|or operators
+ protected static final Pattern ANDOR_PATTERN =
Pattern.compile("\\s+(and|or)\\s+" + OPERATOR_REGEX);
+ protected static final Pattern START_ANDOR_PATTERN = Pattern.compile("^" +
OPERATOR_REGEX + "\\s+(and|or)\\s+.*$");
// this is special for the range operator where you define the range as
from..to (where from and to are numbers)
protected static final Pattern RANGE_PATTERN =
Pattern.compile("^(\\d+)(\\.\\.)(\\d+)$");
protected final Log log = LogFactory.getLog(getClass());
+ /**
+ * A holder class to hold an operator and the expression.
+ * <p/>
+ * This is used for expression with multiple expressions grouped using
and/or operators
+ */
+ private final class ExpressionGroup extends
KeyValueHolder<SimpleLanguageOperator, Expression> {
+
+ public ExpressionGroup(SimpleLanguageOperator key, Expression value) {
+ super(key, value);
+ }
+
+ @Override
+ public String toString() {
+ return getKey() + " " + getValue();
+ }
+ }
+
public Predicate createPredicate(String expression) {
return PredicateBuilder.toPredicate(createExpression(expression));
}
public Expression createExpression(String expression) {
- Matcher matcher = PATTERN.matcher(expression);
- if (matcher.matches()) {
+ Matcher matcher = OPERATOR_PATTERN.matcher(expression);
+ Matcher startMatcher = START_ANDOR_PATTERN.matcher(expression);
+ if (matcher.matches() || startMatcher.matches()) {
if (log.isDebugEnabled()) {
- log.debug("Expression is evaluated as simple expression with
operator: " + expression);
+ log.debug("Expression is evaluated as simple (with operator)
expression: " + expression);
}
- return createOperatorExpression(matcher, expression);
+ return createOperatorExpression(matcher, startMatcher, expression);
} else if (expression.indexOf("${") >= 0) {
if (log.isDebugEnabled()) {
log.debug("Expression is evaluated as simple (strict)
expression: " + expression);
@@ -75,54 +98,80 @@ public abstract class SimpleLanguageSupp
}
}
- private Expression createOperatorExpression(final Matcher matcher, final
String expression) {
- int groupCount = matcher.groupCount();
+ private Expression createOperatorExpression(Matcher matcher, Matcher
startMatcher, String expression) {
+ Expression answer = null;
- if (log.isTraceEnabled()) {
- log.trace("Matcher expression: " + expression);
- log.trace("Matcher group count: " + groupCount);
- for (int i = 0; i < matcher.groupCount() + 1; i++) {
- String group = matcher.group(i);
- if (log.isTraceEnabled()) {
- log.trace("Matcher group #" + i + ": " + group);
- }
- }
+ if (startMatcher.matches()) {
+ answer = doCreateOperatorExpression(expression,
startMatcher.group(1), startMatcher.group(2), startMatcher.group(3));
+ } else if (matcher.matches()) {
+ answer = doCreateOperatorExpression(expression, matcher.group(1),
matcher.group(2), matcher.group(3));
}
- // a simple expression with operator can either be a single group or a
dual group
- String operatorText = matcher.group(6);
- if (operatorText == null) {
- // single group
- return doCreateOperatorExpression(expression, matcher.group(2),
matcher.group(3), matcher.group(4));
- } else {
- // dual group with an and/or operator between the two groups
- final Expression first = doCreateOperatorExpression(expression,
matcher.group(2), matcher.group(3), matcher.group(4));
- final SimpleLanguageOperator operator = asOperator(operatorText);
- final Expression last = doCreateOperatorExpression(expression,
matcher.group(8), matcher.group(9), matcher.group(10));
-
- // create a compound predicate to combine the two groups with the
operator
- final Predicate compoundPredicate;
- if (operator == AND) {
- compoundPredicate =
PredicateBuilder.and(PredicateBuilder.toPredicate(first),
PredicateBuilder.toPredicate(last));
- } else if (operator == OR) {
- compoundPredicate =
PredicateBuilder.or(PredicateBuilder.toPredicate(first),
PredicateBuilder.toPredicate(last));
- } else {
+ // append any additional operators
+ answer = appendAdditionalOperatorExpressions(answer, expression);
+
+ return answer;
+ }
+
+ private Expression appendAdditionalOperatorExpressions(final Expression
answer, final String expression) {
+ Matcher matcher = ANDOR_PATTERN.matcher(expression);
+
+ // now go through the and/or and append those sub expressions
+ final List<ExpressionGroup> expressions = new
ArrayList<ExpressionGroup>();
+ while (matcher.find()) {
+ dumpMatcher(matcher);
+
+ // we only support AND/OR operator between expression groups
+ final SimpleLanguageOperator operator =
asOperator(matcher.group(1));
+ if (operator != AND && operator != OR) {
throw new IllegalArgumentException("Syntax error in
expression: " + expression
+ ". Expected operator as either and/or but was: " +
operator);
}
+ final Expression exp = doCreateOperatorExpression(expression,
matcher.group(2), matcher.group(3), matcher.group(4));
+
+ // add this group
+ expressions.add(new ExpressionGroup(operator, exp));
+ }
- // return the expression that evaluates this expression
- return new Expression() {
- public <T> T evaluate(Exchange exchange, Class<T> type) {
- boolean matches = compoundPredicate.matches(exchange);
- return
exchange.getContext().getTypeConverter().convertTo(type, matches);
+ // return the expression that evaluates the entire expression with
multiple groups
+ return new Expression() {
+ public <T> T evaluate(Exchange exchange, Class<T> type) {
+ boolean matches =
PredicateBuilder.toPredicate(answer).matches(exchange);
+ for (ExpressionGroup group : expressions) {
+ boolean result =
PredicateBuilder.toPredicate(group.getValue()).matches(exchange);
+ if (group.getKey() == AND) {
+ matches &= result;
+ } else {
+ matches |= result;
+ }
}
+ return
exchange.getContext().getTypeConverter().convertTo(type, matches);
+ }
- @Override
- public String toString() {
- return first + " " + operator + " " + last;
+ @Override
+ public String toString() {
+ StringBuilder msg = new StringBuilder(answer.toString());
+ for (ExpressionGroup group : expressions) {
+ msg.append(" ");
+ msg.append(group.getKey());
+ msg.append(" ");
+ msg.append(group.getValue());
}
- };
+ return msg.toString();
+ }
+ };
+ }
+
+ private void dumpMatcher(Matcher matcher) {
+ if (log.isTraceEnabled()) {
+ log.trace("Matcher start: " + matcher.start());
+ log.trace("Matcher end: " + matcher.end());
+ log.trace("Matcher group: " + matcher.group());
+ log.trace("Matcher group count: " + matcher.groupCount());
+ for (int i = 0; i < matcher.groupCount() + 1; i++) {
+ String group = matcher.group(i);
+ log.trace("Matcher group #" + i + ": " + group);
+ }
}
}
Modified:
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerPollStrategyTest.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerPollStrategyTest.java?rev=988647&r1=988646&r2=988647&view=diff
==============================================================================
---
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerPollStrategyTest.java
(original)
+++
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileConsumerPollStrategyTest.java
Tue Aug 24 18:18:41 2010
@@ -56,7 +56,7 @@ public class FileConsumerPollStrategyTes
assertMockEndpointsSatisfied();
// give file consumer a bit time
- Thread.sleep(1000);
+ Thread.sleep(1500);
assertTrue(event.startsWith("rollbackcommit"));
}
Modified:
camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java?rev=988647&r1=988646&r2=988647&view=diff
==============================================================================
---
camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java
(original)
+++
camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java
Tue Aug 24 18:18:41 2010
@@ -47,6 +47,46 @@ public class SimpleOperatorTest extends
assertExpression("${in.header.foo} == abc and ${in.header.bar} < 200",
true);
}
+ public void testTwoAnd() throws Exception {
+ exchange.getIn().setBody("Hello World");
+ assertExpression("${in.header.foo} == abc and ${in.header.bar} == 123
and ${body} == 'Hello World'", true);
+ assertExpression("${in.header.foo} == 'abc' and ${in.header.bar} ==
123 and ${body} == 'Hello World'", true);
+ assertExpression("${in.header.foo} == abc and ${in.header.bar} == 123
and ${body} == 'Bye World'", false);
+ assertExpression("${in.header.foo} == 'abc' and ${in.header.bar} ==
123 and ${body} == 'Bye World'", false);
+ }
+
+ public void testThreeAnd() throws Exception {
+ exchange.getIn().setBody("Hello World");
+ assertExpression("${in.header.foo} == abc and ${in.header.bar} == 123
and ${body} == 'Hello World' and ${in.header.xx}} == null", true);
+ assertExpression("${in.header.foo} == 'abc' and ${in.header.bar} ==
123 and ${body} == 'Hello World' and ${in.header.xx}} == null", true);
+ }
+
+ public void testTwoOr() throws Exception {
+ exchange.getIn().setBody("Hello World");
+ assertExpression("${in.header.foo} == abc or ${in.header.bar} == 44 or
${body} == 'Bye World'", true);
+ assertExpression("${in.header.foo} == 'abc' or ${in.header.bar} == 44
or ${body} == 'Bye World'", true);
+ assertExpression("${in.header.foo} == xxx or ${in.header.bar} == 44 or
${body} == 'Bye World'", false);
+ assertExpression("${in.header.foo} == 'xxx' or ${in.header.bar} == 44
or ${body} == 'Bye World'", false);
+ assertExpression("${in.header.foo} == xxx or ${in.header.bar} == 44 or
${body} == 'Hello World'", true);
+ assertExpression("${in.header.foo} == 'xxx' or ${in.header.bar} == 44
or ${body} == 'Hello World'", true);
+ assertExpression("${in.header.foo} == xxx or ${in.header.bar} == 123
or ${body} == 'Bye World'", true);
+ assertExpression("${in.header.foo} == 'xxx' or ${in.header.bar} == 123
or ${body} == 'Bye World'", true);
+ }
+
+ public void testThreeOr() throws Exception {
+ exchange.getIn().setBody("Hello World");
+ assertExpression("${in.header.foo} == xxx or ${in.header.bar} == 44 or
${body} == 'Bye Moon' or ${body} contains 'World'", true);
+ assertExpression("${in.header.foo} == 'xxx' or ${in.header.bar} == 44
or ${body} == 'Bye Moon' or ${body} contains 'World'", true);
+ assertExpression("${in.header.foo} == xxx or ${in.header.bar} == 44 or
${body} == 'Bye Moon' or ${body} contains 'Moon'", false);
+ assertExpression("${in.header.foo} == 'xxx' or ${in.header.bar} == 44
or ${body} == 'Bye Moon' or ${body} contains 'Moon'", false);
+ assertExpression("${in.header.foo} == abc or ${in.header.bar} == 44 or
${body} == 'Bye Moon' or ${body} contains 'Moon'", true);
+ assertExpression("${in.header.foo} == 'abc' or ${in.header.bar} == 44
or ${body} == 'Bye Moon' or ${body} contains 'Moon'", true);
+ assertExpression("${in.header.foo} == xxx or ${in.header.bar} == 123
or ${body} == 'Bye Moon' or ${body} contains 'Moon'", true);
+ assertExpression("${in.header.foo} == 'xxx' or ${in.header.bar} == 123
or ${body} == 'Bye Moon' or ${body} contains 'Moon'", true);
+ assertExpression("${in.header.foo} == xxx or ${in.header.bar} == 44 or
${body} == 'Hello World' or ${body} contains 'Moon'", true);
+ assertExpression("${in.header.foo} == 'xxx' or ${in.header.bar} == 44
or ${body} == 'Hello World' or ${body} contains 'Moon'", true);
+ }
+
public void testAndWithQuotation() throws Exception {
assertExpression("${in.header.foo} == 'abc' and ${in.header.bar} ==
'123'", true);
assertExpression("${in.header.foo} == 'abc' and ${in.header.bar} ==
'444'", false);
Modified: camel/trunk/camel-core/src/test/resources/log4j.properties
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/resources/log4j.properties?rev=988647&r1=988646&r2=988647&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/resources/log4j.properties (original)
+++ camel/trunk/camel-core/src/test/resources/log4j.properties Tue Aug 24
18:18:41 2010
@@ -26,6 +26,7 @@ log4j.logger.org.apache.camel.impl.Defau
#log4j.logger.org.apache.camel.impl.converter.DefaultTypeConverter=TRACE
#log4j.logger.org.apache.camel=DEBUG
+#log4j.logger.org.apache.camel.language.simple=TRACE
#log4j.logger.org.apache.camel.component=TRACE
#log4j.logger.org.apache.camel.component.seda=TRACE
#log4j.logger.org.apache.camel.impl.DefaultUnitOfWork=TRACE