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 {