CAMEL-9980: Allow to call OGNL on simple bodyAs function

Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/eb85d3d3
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/eb85d3d3
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/eb85d3d3

Branch: refs/heads/master
Commit: eb85d3d3edc23b641adcfa7fd86b52e33a512a03
Parents: eb54d2b
Author: Claus Ibsen <davscl...@apache.org>
Authored: Sun May 22 09:54:20 2016 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Sun May 22 10:36:17 2016 +0200

----------------------------------------------------------------------
 .../apache/camel/builder/ExpressionBuilder.java | 69 ++++++++++++++++++++
 .../simple/ast/SimpleFunctionExpression.java    | 30 +++++++--
 .../camel/language/simple/SimpleTest.java       | 55 +++++++++++-----
 3 files changed, 132 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/eb85d3d3/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java 
b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
index 0e30aa6..3200990 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
@@ -995,6 +995,40 @@ public final class ExpressionBuilder {
 
     /**
      * Returns the expression for the exchanges inbound message body converted
+     * to the given type and invoking methods on the converted body defined in 
a simple OGNL notation
+     */
+    public static Expression bodyOgnlExpression(final String name, final 
String ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String text = simpleExpression(name).evaluate(exchange, 
String.class);
+                Class<?> type;
+                try {
+                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
+                } catch (ClassNotFoundException e) {
+                    throw ObjectHelper.wrapCamelExecutionException(exchange, 
e);
+                }
+                Object body = exchange.getIn().getBody(type);
+                if (body != null) {
+                    // ognl is able to evaluate method name if it contains 
nested functions
+                    // so we should not eager evaluate ognl as a string
+                    MethodCallExpression call = new 
MethodCallExpression(exchange, ognl);
+                    // set the instance to use
+                    call.setInstance(body);
+                    return call.evaluate(exchange);
+                } else {
+                    return null;
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "bodyOgnlAs[" + name + "](" + ognl + ")";
+            }
+        };
+    }
+
+    /**
+     * Returns the expression for the exchanges inbound message body converted
      * to the given type
      */
     public static Expression mandatoryBodyExpression(final String name) {
@@ -1022,6 +1056,41 @@ public final class ExpressionBuilder {
     }
 
     /**
+     * Returns the expression for the exchanges inbound message body converted
+     * to the given type and invoking methods on the converted body defined in 
a simple OGNL notation
+     */
+    public static Expression mandatoryBodyOgnlExpression(final String name, 
final String ognl) {
+        return new ExpressionAdapter() {
+            public Object evaluate(Exchange exchange) {
+                String text = simpleExpression(name).evaluate(exchange, 
String.class);
+                Class<?> type;
+                try {
+                    type = 
exchange.getContext().getClassResolver().resolveMandatoryClass(text);
+                } catch (ClassNotFoundException e) {
+                    throw ObjectHelper.wrapCamelExecutionException(exchange, 
e);
+                }
+                Object body;
+                try {
+                    body = exchange.getIn().getMandatoryBody(type);
+                } catch (InvalidPayloadException e) {
+                    throw ObjectHelper.wrapCamelExecutionException(exchange, 
e);
+                }
+                // ognl is able to evaluate method name if it contains nested 
functions
+                // so we should not eager evaluate ognl as a string
+                MethodCallExpression call = new MethodCallExpression(exchange, 
ognl);
+                // set the instance to use
+                call.setInstance(body);
+                return call.evaluate(exchange);
+            }
+
+            @Override
+            public String toString() {
+                return "mandatoryBodyAs[" + name + "](" + ognl + ")";
+            }
+        };
+    }
+
+    /**
      * Returns the expression for the current thread name
      */
     public static Expression threadNameExpression() {

http://git-wip-us.apache.org/repos/asf/camel/blob/eb85d3d3/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
 
b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 49cc299..efa92d2 100644
--- 
a/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ 
b/camel-core/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -229,24 +229,40 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         String remainder = ifStartsWithReturnRemainder("bodyAs", function);
         if (remainder != null) {
             String type = ObjectHelper.between(remainder, "(", ")");
-            remainder = ObjectHelper.after(remainder, ")");
-            if (type == null || ObjectHelper.isNotEmpty(remainder)) {
+            if (type == null) {
                 throw new SimpleParserException("Valid syntax: ${bodyAs(type)} 
was: " + function, token.getIndex());
             }
-            
             type = StringHelper.removeQuotes(type);
-            return ExpressionBuilder.bodyExpression(type);
+            remainder = ObjectHelper.after(remainder, ")");
+            if (ObjectHelper.isNotEmpty(remainder)) {
+                boolean invalid = 
OgnlHelper.isInvalidValidOgnlExpression(remainder);
+                if (invalid) {
+                    throw new SimpleParserException("Valid syntax: 
${bodyAs(type).OGNL} was: " + function, token.getIndex());
+                }
+                return ExpressionBuilder.bodyOgnlExpression(type, remainder);
+            } else {
+                return ExpressionBuilder.bodyExpression(type);
+            }
+
         }
         // mandatoryBodyAs
         remainder = ifStartsWithReturnRemainder("mandatoryBodyAs", function);
         if (remainder != null) {
             String type = ObjectHelper.between(remainder, "(", ")");
-            remainder = ObjectHelper.after(remainder, ")");
-            if (type == null || ObjectHelper.isNotEmpty(remainder)) {
+            if (type == null) {
                 throw new SimpleParserException("Valid syntax: 
${mandatoryBodyAs(type)} was: " + function, token.getIndex());
             }
             type = StringHelper.removeQuotes(type);
-            return ExpressionBuilder.mandatoryBodyExpression(type);
+            remainder = ObjectHelper.after(remainder, ")");
+            if (ObjectHelper.isNotEmpty(remainder)) {
+                boolean invalid = 
OgnlHelper.isInvalidValidOgnlExpression(remainder);
+                if (invalid) {
+                    throw new SimpleParserException("Valid syntax: 
${mandatoryBodyAs(type).OGNL} was: " + function, token.getIndex());
+                }
+                return ExpressionBuilder.mandatoryBodyOgnlExpression(type, 
remainder);
+            } else {
+                return ExpressionBuilder.mandatoryBodyExpression(type);
+            }
         }
 
         // body OGNL

http://git-wip-us.apache.org/repos/asf/camel/blob/eb85d3d3/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java 
b/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
index ada8265..22a89c1 100644
--- a/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
+++ b/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
@@ -264,6 +264,46 @@ public class SimpleTest extends LanguageTestSupport {
         assertPredicate("${body.toUpperCase()} == 'HELLO WORLD'", true);
     }
     
+    public void testOGNLBodyAsExpression() throws Exception {
+        byte[] body = "hello world".getBytes();
+        exchange.getIn().setBody(body);
+
+        // there is no upper case method on byte array, but we can convert to 
String as below
+        try {
+            assertPredicate("${body.toUpperCase()} == 'HELLO WORLD'", true);
+            fail("Should throw exception");
+        } catch (RuntimeBeanExpressionException e) {
+            MethodNotFoundException cause = 
assertIsInstanceOf(MethodNotFoundException.class, e.getCause());
+            assertEquals("toUpperCase()", cause.getMethodName());
+        }
+
+        assertPredicate("${bodyAs(String)} == 'hello world'", true);
+        assertPredicate("${bodyAs(String).toUpperCase()} == 'HELLO WORLD'", 
true);
+
+        // and body on exchange should not be changed
+        assertSame(body, exchange.getIn().getBody());
+    }
+
+    public void testOGNLMandatoryBodyAsExpression() throws Exception {
+        byte[] body = "hello world".getBytes();
+        exchange.getIn().setBody(body);
+
+        // there is no upper case method on byte array, but we can convert to 
String as below
+        try {
+            assertPredicate("${body.toUpperCase()} == 'HELLO WORLD'", true);
+            fail("Should throw exception");
+        } catch (RuntimeBeanExpressionException e) {
+            MethodNotFoundException cause = 
assertIsInstanceOf(MethodNotFoundException.class, e.getCause());
+            assertEquals("toUpperCase()", cause.getMethodName());
+        }
+
+        assertPredicate("${mandatoryBodyAs(String)} == 'hello world'", true);
+        assertPredicate("${mandatoryBodyAs(String).toUpperCase()} == 'HELLO 
WORLD'", true);
+
+        // and body on exchange should not be changed
+        assertSame(body, exchange.getIn().getBody());
+    }
+
     public void testOGNLCallReplace() throws Exception {
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("cool", "Camel rocks");
@@ -527,14 +567,6 @@ public class SimpleTest extends LanguageTestSupport {
         } catch (CamelExecutionException e) {
             assertIsInstanceOf(ClassNotFoundException.class, e.getCause());
         }
-        
-        exchange.getIn().setBody("hello");
-        try {
-            assertExpression("${bodyAs(String).test}", "hello.test");
-            fail("should have thrown an exception");
-        } catch (SimpleIllegalSyntaxException e) {
-            assertTrue("Get a wrong message", 
e.getMessage().indexOf("bodyAs(String).test") > 0);
-        }
     }
 
     public void testMandatoryBodyAs() throws Exception {
@@ -560,13 +592,6 @@ public class SimpleTest extends LanguageTestSupport {
         } catch (CamelExecutionException e) {
             assertIsInstanceOf(ClassNotFoundException.class, e.getCause());
         }
-        
-        try {
-            assertExpression("${mandatoryBodyAs(String).test}", "hello.test");
-            fail("should have thrown an exception");
-        } catch (SimpleIllegalSyntaxException e) {
-            assertTrue("Get a wrong message", 
e.getMessage().indexOf("mandatoryBodyAs(String).test") > 0);
-        }
     }
 
     public void testHeaderEmptyBody() throws Exception {

Reply via email to