You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2009/05/22 20:42:18 UTC

svn commit: r777654 - in /camel/trunk/camel-core/src: main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java test/java/org/apache/camel/language/SimpleOperatorTest.java

Author: davsclaus
Date: Fri May 22 18:42:18 2009
New Revision: 777654

URL: http://svn.apache.org/viewvc?rev=777654&view=rev
Log:
CAMEL-1637: Added support for and,or to concat two expressions with the simple language.

Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java?rev=777654&r1=777653&r2=777654&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java Fri May 22 18:42:18 2009
@@ -35,11 +35,22 @@
  *   <li>not is: tested for not if type is an instanceof the given type</li>
  *   <li>range : tested for if it is within the provided range</li>
  *   <li>not range : tested for not if it is within the provided range</li>
+ *   <li>and : and operator to combine two groups of expressions</li>
+ *   <li>or : or operator to combine two groups of expressions</li>
  * </ul>
+ * <p/>
+ * The <tt>and</tt> and <tt>or</tt> operator is special as they are used as optional operator to combine two expressions.
+ * This allows you to build combiled expressions. Currently only one and/or operator is supported, but this might change
+ * in the future.
+ * <br/>
+ * For example we can create this compound expression that has two groups that is combined with the and operator:
+ * <tt>${in.header.action} == 'login' and ${in.header.password} != null</tt>
+ * <br/>
  */
 public enum SimpleLangaugeOperator {
 
-    EQ, GT, GTE, LT, LTE, NOT, CONTAINS, NOT_CONTAINS, REGEX, NOT_REGEX, IN, NOT_IN, IS, NOT_IS, RANGE, NOT_RANGE;
+    EQ, GT, GTE, LT, LTE, NOT, CONTAINS, NOT_CONTAINS, REGEX, NOT_REGEX,
+    IN, NOT_IN, IS, NOT_IS, RANGE, NOT_RANGE, AND, OR;
 
     public static SimpleLangaugeOperator asOperator(String text) {
         if ("==".equals(text)) {
@@ -74,6 +85,10 @@
             return RANGE;
         } else if ("not range".equals(text)) {
             return NOT_RANGE;
+        } else if ("and".equals(text)) {
+            return AND;
+        } else if ("or".equals(text)) {
+            return OR;
         }
         throw new IllegalArgumentException("Operator not supported: " + text);
     }
@@ -111,6 +126,10 @@
             return "range";
         } else if (operator == NOT_RANGE) {
             return "not range";
+        } else if (operator == AND) {
+            return "and";
+        } else if (operator == OR) {
+            return "or";
         }
         return "";
     }

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=777654&r1=777653&r2=777654&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 Fri May 22 18:42:18 2009
@@ -40,8 +40,14 @@
  */
 public abstract class SimpleLanguageSupport implements Language, IsSingleton {
 
-    protected static final Pattern PATTERN = Pattern.compile(
-            "^\\$\\{(.+)\\}\\s+(==|>|>=|<|<=|!=|contains|not contains|regex|not regex|in|not in|is|not is|range|not range)\\s+(.+)$");
+    // this is a regex for a given group in a simple expression that uses operators
+    private static final String GROUP_PATTERN =
+        "\\$\\{(\\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 + "))?$");
+
+    // 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());
 
@@ -70,35 +76,73 @@
     }
 
     private Expression createOperatorExpression(final Matcher matcher, final String expression) {
-        final Expression left = createSimpleExpression(matcher.group(1), true);
-        final SimpleLangaugeOperator operator = asOperator(matcher.group(2));
+        int groupCount = matcher.groupCount();
 
-        // the right hand side expression can either be a constant expression wiht ' '
-        // or another simple expression using ${ } placeholders
-        String text = matcher.group(3);
+        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);
+                }
+            }
+        }
 
+        // 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 SimpleLangaugeOperator 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 {
+                throw new IllegalArgumentException("Syntax error in expression: " + expression
+                    + ". Expected operator as either and/or but was: " + operator);
+            }
+
+            // 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);
+                }
+
+                @Override
+                public String toString() {
+                    return first + " " + operator + " " + last;
+                }
+            };
+        }
+    }
+
+    private Expression doCreateOperatorExpression(final String expression, final String leftText,
+                                                  final String operatorText, final String rightText) {
+        // left value is always a simple expression
+        final Expression left = createSimpleExpression(leftText, true);
+        final SimpleLangaugeOperator operator = asOperator(operatorText);
+
+        // the right hand side expression can either be a constant expression with or without enclosing ' '
+        // or another simple expression using ${ } placeholders
         final Expression right;
-        final Expression rightConverted;
         final Boolean isNull;
         // special null handling
-        if ("null".equals(text) || "'null'".equals(text)) {
+        if ("null".equals(rightText) || "'null'".equals(rightText)) {
             isNull = Boolean.TRUE;
-            right = createConstantExpression(null);
-            rightConverted = right;
+            right = createSimpleOrConstantExpression(null);
         } else {
             isNull = Boolean.FALSE;
-            // text can either be a constant enclosed by ' ' or another expression using ${ } placeholders
-            String constant = ObjectHelper.between(text, "'", "'");
-            if (constant == null) {
-                // if no ' ' around then fallback to the text itself
-                constant = text;
-            }
-            String simple = ObjectHelper.between(text, "${", "}");
-
-            right = simple != null ? createSimpleExpression(simple, true) : createConstantExpression(constant);
-            // to support numeric comparions using > and < operators we must convert the right hand side
-            // to the same type as the left
-            rightConverted = ExpressionBuilder.convertToExpression(right, left);
+            right = createSimpleOrConstantExpression(rightText);
         }
 
         return new Expression() {
@@ -112,19 +156,19 @@
                     // special for not EQ null
                     predicate = PredicateBuilder.isNotNull(left);
                 } else if (operator == EQ) {
-                    predicate = PredicateBuilder.isEqualTo(left, rightConverted);
+                    predicate = PredicateBuilder.isEqualTo(left, right);
                 } else if (operator == GT) {
-                    predicate = PredicateBuilder.isGreaterThan(left, rightConverted);
+                    predicate = PredicateBuilder.isGreaterThan(left, right);
                 } else if (operator == GTE) {
-                    predicate = PredicateBuilder.isGreaterThanOrEqualTo(left, rightConverted);
+                    predicate = PredicateBuilder.isGreaterThanOrEqualTo(left, right);
                 } else if (operator == LT) {
-                    predicate = PredicateBuilder.isLessThan(left, rightConverted);
+                    predicate = PredicateBuilder.isLessThan(left, right);
                 } else if (operator == LTE) {
-                    predicate = PredicateBuilder.isLessThanOrEqualTo(left, rightConverted);
+                    predicate = PredicateBuilder.isLessThanOrEqualTo(left, right);
                 } else if (operator == NOT) {
-                    predicate = PredicateBuilder.isNotEqualTo(left, rightConverted);
+                    predicate = PredicateBuilder.isNotEqualTo(left, right);
                 } else if (operator == CONTAINS || operator == NOT_CONTAINS) {
-                    predicate = PredicateBuilder.contains(left, rightConverted);
+                    predicate = PredicateBuilder.contains(left, right);
                     if (operator == NOT_CONTAINS) {
                         predicate = PredicateBuilder.not(predicate);
                     }
@@ -228,6 +272,22 @@
         return ExpressionBuilder.concatExpression(results, expression);
     }
 
+    protected Expression createSimpleOrConstantExpression(String text) {
+        if (text != null) {
+            String simple = ObjectHelper.between(text, "${", "}");
+            if (simple != null) {
+                return createSimpleExpression(simple, true);
+            }
+
+            simple = ObjectHelper.between(text, "'", "'");
+            if (simple != null) {
+                return createConstantExpression(simple);
+            }
+        }
+
+        return createConstantExpression(text);
+    }
+
     protected Expression createConstantExpression(String expression, int start, int end) {
         return ExpressionBuilder.constantExpression(expression.substring(start, end));
     }

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=777654&r1=777653&r2=777654&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 Fri May 22 18:42:18 2009
@@ -32,6 +32,33 @@
         return jndi;
     }
 
+    public void tesValueWithSpace() throws Exception {
+        exchange.getIn().setBody("Hello Big World");
+        assertExpression("${in.body} == 'Hello Big World'", true);
+    }
+
+    public void testAnd() throws Exception {
+        assertExpression("${in.header.foo} == abc and ${in.header.bar} == 123", true);
+        assertExpression("${in.header.foo} == abc and ${in.header.bar} == 444", false);
+        assertExpression("${in.header.foo} == def and ${in.header.bar} == 123", false);
+        assertExpression("${in.header.foo} == def and ${in.header.bar} == 444", false);
+
+        assertExpression("${in.header.foo} == abc and ${in.header.bar} > 100", true);
+        assertExpression("${in.header.foo} == abc and ${in.header.bar} < 200", true);
+    }
+
+    public void testOr() throws Exception {
+        assertExpression("${in.header.foo} == abc or ${in.header.bar} == 123", true);
+        assertExpression("${in.header.foo} == abc or ${in.header.bar} == 444", true);
+        assertExpression("${in.header.foo} == def or ${in.header.bar} == 123", true);
+        assertExpression("${in.header.foo} == def or ${in.header.bar} == 444", false);
+
+        assertExpression("${in.header.foo} == abc or ${in.header.bar} < 100", true);
+        assertExpression("${in.header.foo} == abc or ${in.header.bar} < 200", true);
+        assertExpression("${in.header.foo} == def or ${in.header.bar} < 200", true);
+        assertExpression("${in.header.foo} == def or ${in.header.bar} < 100", false);
+    }
+
     public void testEqualOperator() throws Exception {
         // string to string comparison
         assertExpression("${in.header.foo} == 'abc'", true);
@@ -255,7 +282,7 @@
         assertExpression("${in.header.foo} not is Integer", true);
 
         try {
-            assertExpression("${in.header.foo} is not com.mycompany.DoesNotExist", false);
+            assertExpression("${in.header.foo} not is com.mycompany.DoesNotExist", false);
             fail("Should have thrown an exception");
         } catch (IllegalArgumentException e) {
             assertTrue(e.getMessage().startsWith("Syntax error"));
@@ -287,18 +314,16 @@
         }
 
         try {
-            assertExpression("${in.header.foo} range 100 200", false);
-            fail("Should have thrown an exception");
-        } catch (IllegalArgumentException e) {
-            assertTrue(e.getMessage().startsWith("Syntax error"));
-        }
-
-        try {
             assertExpression("${in.header.foo} range 100.200", false);
             fail("Should have thrown an exception");
         } catch (IllegalArgumentException e) {
             assertTrue(e.getMessage().startsWith("Syntax error"));
         }
+
+        assertExpression("${in.header.bar} range 100..200 and ${in.header.foo} == abc" , true);
+        assertExpression("${in.header.bar} range 200..300 and ${in.header.foo} == abc" , false);
+        assertExpression("${in.header.bar} range 200..300 or ${in.header.foo} == abc" , true);
+        assertExpression("${in.header.bar} range 200..300 or ${in.header.foo} == def" , false);
     }
 
     public void testNotRange() throws Exception {
@@ -326,13 +351,6 @@
         }
 
         try {
-            assertExpression("${in.header.foo} not range 100 200", false);
-            fail("Should have thrown an exception");
-        } catch (IllegalArgumentException e) {
-            assertTrue(e.getMessage().startsWith("Syntax error"));
-        }
-
-        try {
             assertExpression("${in.header.foo} not range 100.200", false);
             fail("Should have thrown an exception");
         } catch (IllegalArgumentException e) {