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 2021/05/10 06:34:41 UTC

[camel] branch CAMEL-16593 updated (145ff7f -> 171065e)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch CAMEL-16593
in repository https://gitbox.apache.org/repos/asf/camel.git.


    from 145ff7f  Regen
     new c7ba8d5  CAMEL-16596: ScriptingLanguage SPI.
     new 0b56a56  CAMEL-16596: ScriptingLanguage SPI.
     new 1fd896d  CAMEL-16596: ScriptingLanguage SPI.
     new f79c258  CAMEL-16596: ScriptingLanguage SPI.
     new 608bad0  CAMEL-16596: ScriptingLanguage SPI.
     new 171065e  CAMEL-16596: ScriptingLanguage SPI.

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  10 +-
 .../groovy/GroovyScriptingLanguageTest.java        |  57 ++++++
 .../groovy/GroovySetHeaderConcurrentIssueTest.java |   2 +
 .../apache/camel/language/joor/JoorLanguage.java   |  32 +++-
 .../org/apache/camel/language/joor/JoorMethod.java |   3 +
 .../camel/language/joor/JoorScriptingCompiler.java | 213 +++++++++++++++++++++
 ...tionException.java => JoorScriptingMethod.java} |  26 +--
 .../language/joor/JoorScriptingLanguageTest.java   |  48 +++++
 components/camel-kamelet/pom.xml                   |   5 +
 .../KameletLocalBeanGroovyExternalTest.java        |  76 ++++++++
 .../kamelet/KameletLocalBeanJoorExternalTest.java  |  76 ++++++++
 .../src/test/resources/mybar.groovy}               |  18 +-
 .../camel-kamelet/src/test/resources/mybar.joor    |   4 +
 .../java/org/apache/camel/impl/DefaultModel.java   |  86 +++++----
 14 files changed, 586 insertions(+), 70 deletions(-)
 create mode 100644 components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyScriptingLanguageTest.java
 create mode 100644 components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java
 rename components/camel-joor/src/main/java/org/apache/camel/language/joor/{JoorExpressionEvaluationException.java => JoorScriptingMethod.java} (52%)
 create mode 100644 components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java
 create mode 100644 components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanGroovyExternalTest.java
 create mode 100644 components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanJoorExternalTest.java
 copy components/{camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java => camel-kamelet/src/test/resources/mybar.groovy} (69%)
 create mode 100644 components/camel-kamelet/src/test/resources/mybar.joor

[camel] 06/06: CAMEL-16596: ScriptingLanguage SPI.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-16593
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 171065eff9aca263ea75d3c0758f3afe1d6ff87f
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon May 10 08:32:53 2021 +0200

    CAMEL-16596: ScriptingLanguage SPI.
---
 .../org/apache/camel/language/joor/JoorLanguage.java     | 11 +++++++++++
 .../camel/language/joor/JoorScriptingLanguageTest.java   |  9 +++++----
 components/camel-kamelet/src/test/resources/mybar.joor   | 16 ----------------
 3 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
index 040b1f6..696e4a4 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
@@ -86,6 +86,7 @@ public class JoorLanguage extends LanguageSupport implements ScriptingLanguage,
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public <T> T evaluate(String script, Map<String, Object> bindings, Class<T> resultType) {
         Object out;
         JoorScriptingMethod target = scriptingCompiler.compile(getCamelContext(), script, bindings, resultType, singleQuotes);
@@ -203,6 +204,16 @@ public class JoorLanguage extends LanguageSupport implements ScriptingLanguage,
         } else {
             compiler.getImports().addAll(imports);
         }
+        if (scriptingCompiler.getAliases() == null) {
+            scriptingCompiler.setAliases(aliases);
+        } else {
+            scriptingCompiler.getAliases().putAll(aliases);
+        }
+        if (scriptingCompiler.getImports() == null) {
+            scriptingCompiler.setImports(imports);
+        } else {
+            scriptingCompiler.getImports().addAll(imports);
+        }
     }
 
     private static int getJavaMajorVersion() {
diff --git a/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java b/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java
index 97f00f0..9eb3d4e 100644
--- a/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java
+++ b/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java
@@ -16,15 +16,15 @@
  */
 package org.apache.camel.language.joor;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 import org.apache.camel.spi.Language;
 import org.apache.camel.spi.ScriptingLanguage;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 public class JoorScriptingLanguageTest extends CamelTestSupport {
 
     @Test
@@ -41,7 +41,8 @@ public class JoorScriptingLanguageTest extends CamelTestSupport {
         user.setName("Scott");
         Map<String, Object> bindings = new LinkedHashMap<>();
         bindings.put("user", user);
-        String out = slan.evaluate("'Hello ' + user.getName() + ' you are ' + user.getAge() + ' years old'", bindings, String.class);
+        String out = slan.evaluate("'Hello ' + user.getName() + ' you are ' + user.getAge() + ' years old'", bindings,
+                String.class);
         Assertions.assertEquals("Hello Scott you are 33 years old", out);
     }
 }
diff --git a/components/camel-kamelet/src/test/resources/mybar.joor b/components/camel-kamelet/src/test/resources/mybar.joor
index f9c0bc9..be7a484 100644
--- a/components/camel-kamelet/src/test/resources/mybar.joor
+++ b/components/camel-kamelet/src/test/resources/mybar.joor
@@ -1,19 +1,3 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 var bean = new org.apache.camel.component.kamelet.MyInjectBar();
 // context is RouteTemplateContext
 bean.setBar(context.getProperty('bar', String.class));

[camel] 02/06: CAMEL-16596: ScriptingLanguage SPI.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-16593
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 0b56a56192ea78773fc8f273b4c5edda8c3e2823
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon May 10 07:20:06 2021 +0200

    CAMEL-16596: ScriptingLanguage SPI.
---
 .../org/apache/camel/catalog/schemas/camel-spring.xsd          | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index c68b6e3..92f9ba1 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -10297,7 +10297,15 @@ Whether tracing is enabled on this route.
   </xs:complexType>
 
   <xs:complexType name="routeTemplateBeanDefinition">
-    <xs:sequence/>
+    <xs:sequence>
+      <xs:element minOccurs="0" name="beanFactory" type="tns:routeTemplateBeanFactoryDefinition">
+        <xs:annotation>
+          <xs:documentation xml:lang="en"><![CDATA[
+Bean factory that uses a scripting language to create the local bean.
+          ]]></xs:documentation>
+        </xs:annotation>
+      </xs:element>
+    </xs:sequence>
     <xs:attribute name="name" type="xs:string" use="required">
       <xs:annotation>
         <xs:documentation xml:lang="en"><![CDATA[

[camel] 01/06: CAMEL-16596: ScriptingLanguage SPI.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-16593
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c7ba8d59fcf12a33321af00dd9c410245f4315c7
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon May 10 06:57:30 2021 +0200

    CAMEL-16596: ScriptingLanguage SPI.
---
 .../groovy/GroovyScriptingLanguageTest.java        | 57 ++++++++++++++++++++++
 .../groovy/GroovySetHeaderConcurrentIssueTest.java |  2 +
 2 files changed, 59 insertions(+)

diff --git a/components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyScriptingLanguageTest.java b/components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyScriptingLanguageTest.java
new file mode 100644
index 0000000..8e3475a6
--- /dev/null
+++ b/components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyScriptingLanguageTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.groovy;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.ScriptingLanguage;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class GroovyScriptingLanguageTest extends CamelTestSupport {
+
+    @Test
+    public void testScripting() throws Exception {
+        Language lan = context.resolveLanguage("groovy");
+        Assertions.assertTrue(lan instanceof ScriptingLanguage);
+        ScriptingLanguage slan = (ScriptingLanguage) lan;
+
+        int num = slan.evaluate("2 * 3", null, int.class);
+        Assertions.assertEquals(6, num);
+
+        Map<String, Object> bindings = new HashMap<>();
+        bindings.put("context", context());
+        String id = slan.evaluate("context.name", bindings, String.class);
+        Assertions.assertEquals(context.getName(), id);
+    }
+
+    @Test
+    public void testExternalScripting() throws Exception {
+        Language lan = context.resolveLanguage("groovy");
+        Assertions.assertTrue(lan instanceof ScriptingLanguage);
+        ScriptingLanguage slan = (ScriptingLanguage) lan;
+
+        Map<String, Object> bindings = new HashMap<>();
+        bindings.put("body", 3);
+        String text = slan.evaluate("resource:classpath:mygroovy.groovy", bindings, String.class);
+        Assertions.assertEquals("The result is 6", text);
+    }
+
+}
diff --git a/components/camel-groovy/src/test/java/org/apache/camel/processor/groovy/GroovySetHeaderConcurrentIssueTest.java b/components/camel-groovy/src/test/java/org/apache/camel/processor/groovy/GroovySetHeaderConcurrentIssueTest.java
index 78ce9de..0f2e8dc 100644
--- a/components/camel-groovy/src/test/java/org/apache/camel/processor/groovy/GroovySetHeaderConcurrentIssueTest.java
+++ b/components/camel-groovy/src/test/java/org/apache/camel/processor/groovy/GroovySetHeaderConcurrentIssueTest.java
@@ -21,8 +21,10 @@ import java.util.concurrent.Executors;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
+@Disabled
 public class GroovySetHeaderConcurrentIssueTest extends CamelTestSupport {
 
     private ExecutorService executor;

[camel] 04/06: CAMEL-16596: ScriptingLanguage SPI.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-16593
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f79c25816ad2ed9db21e031712056ff3c62d24de
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon May 10 08:24:47 2021 +0200

    CAMEL-16596: ScriptingLanguage SPI.
---
 .../apache/camel/language/joor/JoorLanguage.java   |  26 ++-
 .../org/apache/camel/language/joor/JoorMethod.java |   3 +
 .../camel/language/joor/JoorScriptingCompiler.java | 214 +++++++++++++++++++++
 ...tionException.java => JoorScriptingMethod.java} |  26 +--
 .../language/joor/JoorScriptingLanguageTest.java   |  47 +++++
 components/camel-kamelet/pom.xml                   |   5 +
 .../kamelet/KameletLocalBeanJoorExternalTest.java  |  76 ++++++++
 .../src/test/resources/mybar.joor}                 |  18 +-
 8 files changed, 379 insertions(+), 36 deletions(-)

diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
index 9d5b883..b3788d6 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
@@ -23,7 +23,9 @@ import java.util.TreeSet;
 
 import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.StaticService;
+import org.apache.camel.spi.ScriptingLanguage;
 import org.apache.camel.spi.annotations.Language;
 import org.apache.camel.support.ExpressionToPredicateAdapter;
 import org.apache.camel.support.LanguageSupport;
@@ -34,12 +36,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Language("joor")
-public class JoorLanguage extends LanguageSupport implements StaticService {
+public class JoorLanguage extends LanguageSupport implements ScriptingLanguage, StaticService {
 
     private static final Logger LOG = LoggerFactory.getLogger(JoorLanguage.class);
 
     private static Boolean java8;
     private final JoorCompiler compiler = new JoorCompiler();
+    private final JoorScriptingCompiler scriptingCompiler = new JoorScriptingCompiler();
     private final Set<String> imports = new TreeSet<>();
     private final Map<String, String> aliases = new HashMap<>();
 
@@ -83,6 +86,27 @@ public class JoorLanguage extends LanguageSupport implements StaticService {
     }
 
     @Override
+    public <T> T evaluate(String script, Map<String, Object> bindings, Class<T> resultType) {
+        Object out;
+        JoorScriptingMethod target = scriptingCompiler.compile(getCamelContext(), script, bindings, resultType, singleQuotes);
+        try {
+            if (bindings != null && !bindings.isEmpty()) {
+                Object[] args = bindings.values().toArray(new Object[0]);
+                out = target.evaluate(args);
+            } else {
+                out = target.evaluate();
+            }
+        } catch (Exception e) {
+            throw RuntimeCamelException.wrapRuntimeException(e);
+        }
+        if (out != null && resultType != null) {
+            return getCamelContext().getTypeConverter().convertTo(resultType, out);
+        } else {
+            return (T) out;
+        }
+    }
+
+    @Override
     public Predicate createPredicate(String expression) {
         return ExpressionToPredicateAdapter.toPredicate(createExpression(expression));
     }
diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java
index ade1503..a1a8c03 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java
@@ -22,6 +22,9 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 
+/**
+ * Interface for the compiled joor method when evaluating as Camel {@link org.apache.camel.Expression}.
+ */
 public interface JoorMethod {
 
     Object evaluate(CamelContext context, Exchange exchange, Message message, Object body, Optional<?> optionalBody)
diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java
new file mode 100644
index 0000000..6527dd7
--- /dev/null
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.joor;
+
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.StaticService;
+import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.ScriptHelper;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StopWatch;
+import org.joor.Reflect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JoorScriptingCompiler extends ServiceSupport implements StaticService {
+
+    private static final Pattern BEAN_INJECTION_PATTERN = Pattern.compile("(#bean:)([A-Za-z0-9-_]*)");
+
+    private static final Logger LOG = LoggerFactory.getLogger(JoorCompiler.class);
+    private static final AtomicInteger UUID = new AtomicInteger();
+    private Set<String> imports = new TreeSet<>();
+    private Map<String, String> aliases;
+    private int counter;
+    private long taken;
+
+    public Set<String> getImports() {
+        return imports;
+    }
+
+    public void setImports(Set<String> imports) {
+        this.imports = imports;
+    }
+
+    public Map<String, String> getAliases() {
+        return aliases;
+    }
+
+    public void setAliases(Map<String, String> aliases) {
+        this.aliases = aliases;
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+        if (counter > 0) {
+            LOG.info("jOOR scripting language compiled {} scripts in {} millis", counter, taken);
+        }
+    }
+
+    public JoorScriptingMethod compile(
+            CamelContext camelContext, String script, Map<String, Object> bindings, Class<?> resultType, boolean singleQuotes) {
+        StopWatch watch = new StopWatch();
+
+        JoorScriptingMethod answer;
+        String className = nextFQN();
+        String code = evalCode(camelContext, className, script, bindings, resultType, singleQuotes);
+        try {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Compiling code:\n\n{}\n", code);
+            }
+            Reflect ref = Reflect.compile(className, code);
+            Class<?> clazz = ref.type();
+            answer = (JoorScriptingMethod) clazz.getConstructor(CamelContext.class).newInstance(camelContext);
+        } catch (Exception e) {
+            throw new JoorCompilationException(className, code, e);
+        }
+
+        counter++;
+        taken += watch.taken();
+        return answer;
+    }
+
+    @SuppressWarnings("unchecked")
+    public String evalCode(
+            CamelContext camelContext, String fqn, String script, Map<String, Object> bindings, Class<?> resultType,
+            boolean singleQuotes) {
+        String qn = fqn.substring(0, fqn.lastIndexOf('.'));
+        String name = fqn.substring(fqn.lastIndexOf('.') + 1);
+
+        // reload script
+        script = ScriptHelper.resolveOptionalExternalScript(camelContext, script);
+
+        // trim text
+        script = script.trim();
+
+        Set<String> scriptImports = new LinkedHashSet<>();
+        Map<String, Class> scriptBeans = new HashMap<>();
+        script = evalDependencyInjection(camelContext, scriptImports, scriptBeans, script);
+
+        //  wrap text into a class method we can call
+        StringBuilder sb = new StringBuilder();
+        sb.append("package ").append(qn).append(";\n");
+        sb.append("\n");
+        sb.append("import java.util.*;\n");
+        sb.append("import java.util.concurrent.*;\n");
+        sb.append("import java.util.stream.*;\n");
+        sb.append("\n");
+        sb.append("import org.apache.camel.*;\n");
+        sb.append("import org.apache.camel.util.*;\n");
+        sb.append("import static org.apache.camel.language.joor.JoorHelper.*;\n");
+        sb.append("\n");
+        // custom imports
+        for (String i : imports) {
+            sb.append(i);
+            if (!i.endsWith(";")) {
+                sb.append(";");
+            }
+            sb.append("\n");
+        }
+        for (String i : scriptImports) {
+            sb.append("import ");
+            sb.append(i);
+            sb.append(";\n");
+        }
+        sb.append("\n");
+        sb.append("public class ").append(name).append(" implements org.apache.camel.language.joor.JoorScriptingMethod {\n");
+        sb.append("\n");
+        // local beans variables
+        for (Map.Entry<String, Class> entry : scriptBeans.entrySet()) {
+            sb.append("    private ").append(entry.getValue().getSimpleName()).append(" ").append(entry.getKey()).append(";\n");
+        }
+        sb.append("\n");
+
+        // constructor to lookup beans
+        sb.append("    public ").append(name).append("(CamelContext context) throws Exception {\n");
+        for (Map.Entry<String, Class> entry : scriptBeans.entrySet()) {
+            sb.append("        ").append(entry.getKey()).append(" = ").append("context.getRegistry().lookupByNameAndType(\"")
+                    .append(entry.getKey()).append("\", ").append(entry.getValue().getSimpleName()).append(".class);\n");
+        }
+        sb.append("    }\n");
+        sb.append("\n");
+
+        sb.append("    @Override\n");
+        sb.append(
+                "    public Object evaluate(Object... args) throws Exception {\n");
+        sb.append("        ");
+
+        // bindings as local variables
+        if (bindings != null) {
+            int i = 0;
+            for (Map.Entry<String, Object> bind : bindings.entrySet()) {
+                String vn = bind.getKey();
+                String cn = ObjectHelper.className(bind.getValue());
+                String b = String.format("        var %s = (%s) args[%s];\n", vn, cn, i++);
+                sb.append(b);
+            }
+            sb.append("\n");
+        }
+        if (!script.contains("return ")) {
+            sb.append("return ");
+        }
+
+        if (singleQuotes) {
+            // single quotes instead of double quotes, as its very annoying for string in strings
+            String quoted = script.replace('\'', '"');
+            sb.append(quoted);
+        } else {
+            sb.append(script);
+        }
+        if (!script.endsWith("}") && !script.endsWith(";")) {
+            sb.append(";");
+        }
+        sb.append("\n");
+        sb.append("    }\n");
+        sb.append("}\n");
+        sb.append("\n");
+
+        return sb.toString();
+    }
+
+    private String evalDependencyInjection(
+            CamelContext camelContext, Set<String> scriptImports, Map<String, Class> scriptBeans, String script) {
+        Matcher matcher = BEAN_INJECTION_PATTERN.matcher(script);
+        while (matcher.find()) {
+            String id = matcher.group(2);
+            Object bean = CamelContextHelper.mandatoryLookup(camelContext, id);
+            Class<?> type = bean.getClass();
+            scriptImports.add(type.getName());
+            scriptBeans.put(id, type);
+            script = matcher.replaceFirst(id);
+            matcher = BEAN_INJECTION_PATTERN.matcher(script);
+        }
+        return script;
+    }
+
+    private static String nextFQN() {
+        return "org.apache.camel.language.joor.compiled.scripting.JoorScripting" + UUID.incrementAndGet();
+    }
+
+}
diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorExpressionEvaluationException.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingMethod.java
similarity index 52%
rename from components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorExpressionEvaluationException.java
rename to components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingMethod.java
index 806e550..2d2eec6 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorExpressionEvaluationException.java
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingMethod.java
@@ -16,27 +16,11 @@
  */
 package org.apache.camel.language.joor;
 
-import org.apache.camel.Exchange;
-import org.apache.camel.Expression;
-import org.apache.camel.ExpressionEvaluationException;
-
-public class JoorExpressionEvaluationException extends ExpressionEvaluationException {
-
-    private final String className;
-    private final String code;
-
-    public JoorExpressionEvaluationException(Expression expression, String className, String code, Exchange exchange,
-                                             Throwable cause) {
-        super(expression, "jOOR evaluation error for class: " + className + " with code:\n" + code, exchange, cause);
-        this.className = className;
-        this.code = code;
-    }
+/**
+ * Interface for the compiled joor scripting method when evaluating as scripting language.
+ */
+public interface JoorScriptingMethod {
 
-    public String getClassName() {
-        return className;
-    }
+    Object evaluate(Object... args) throws Exception;
 
-    public String getCode() {
-        return code;
-    }
 }
diff --git a/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java b/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java
new file mode 100644
index 0000000..97f00f0
--- /dev/null
+++ b/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorScriptingLanguageTest.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.joor;
+
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.ScriptingLanguage;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class JoorScriptingLanguageTest extends CamelTestSupport {
+
+    @Test
+    public void testScripting() throws Exception {
+        Language lan = context.resolveLanguage("joor");
+        Assertions.assertTrue(lan instanceof ScriptingLanguage);
+
+        ScriptingLanguage slan = (ScriptingLanguage) lan;
+        int num = slan.evaluate("2 * 3", null, int.class);
+        Assertions.assertEquals(6, num);
+
+        MyUser user = new MyUser();
+        user.setAge(33);
+        user.setName("Scott");
+        Map<String, Object> bindings = new LinkedHashMap<>();
+        bindings.put("user", user);
+        String out = slan.evaluate("'Hello ' + user.getName() + ' you are ' + user.getAge() + ' years old'", bindings, String.class);
+        Assertions.assertEquals("Hello Scott you are 33 years old", out);
+    }
+}
diff --git a/components/camel-kamelet/pom.xml b/components/camel-kamelet/pom.xml
index c443946..8cd7354 100644
--- a/components/camel-kamelet/pom.xml
+++ b/components/camel-kamelet/pom.xml
@@ -51,6 +51,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
+            <artifactId>camel-joor</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
             <artifactId>camel-timer</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanJoorExternalTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanJoorExternalTest.java
new file mode 100644
index 0000000..349587d
--- /dev/null
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanJoorExternalTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.kamelet;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.apache.http.annotation.Obsolete;
+import org.junit.jupiter.api.Test;
+
+public class KameletLocalBeanJoorExternalTest extends CamelTestSupport {
+
+    @Test
+    public void testOne() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are going to Moes");
+
+        template.sendBody("direct:moe", "John");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testTwo() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hi Jack we are going to Shamrock",
+                "Hi Mary we are going to Moes");
+
+        template.sendBody("direct:shamrock", "Jack");
+        template.sendBody("direct:moe", "Mary");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // **********************************************
+    //
+    // test set-up
+    //
+    // **********************************************
+
+    @Obsolete
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                routeTemplate("whereTo")
+                        .templateParameter("bar") // name of bar
+                        .templateBean("myBar", "joor", "resource:classpath:mybar.joor")
+                        .from("kamelet:source")
+                        // must use {{myBar}} to refer to the local bean
+                        .to("bean:{{myBar}}");
+
+                from("direct:shamrock")
+                        .kamelet("whereTo?bar=Shamrock")
+                        .to("mock:result");
+
+                from("direct:moe")
+                        .kamelet("whereTo?bar=Moes")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java b/components/camel-kamelet/src/test/resources/mybar.joor
similarity index 69%
copy from components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java
copy to components/camel-kamelet/src/test/resources/mybar.joor
index ade1503..f9c0bc9 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorMethod.java
+++ b/components/camel-kamelet/src/test/resources/mybar.joor
@@ -14,17 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.language.joor;
-
-import java.util.Optional;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
-
-public interface JoorMethod {
-
-    Object evaluate(CamelContext context, Exchange exchange, Message message, Object body, Optional<?> optionalBody)
-            throws Exception;
-
-}
+var bean = new org.apache.camel.component.kamelet.MyInjectBar();
+// context is RouteTemplateContext
+bean.setBar(context.getProperty('bar', String.class));
+return bean;

[camel] 03/06: CAMEL-16596: ScriptingLanguage SPI.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-16593
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 1fd896db695ab782ba210914809db93363ece2e5
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon May 10 07:35:29 2021 +0200

    CAMEL-16596: ScriptingLanguage SPI.
---
 .../KameletLocalBeanGroovyExternalTest.java        | 76 +++++++++++++++++++
 .../camel-kamelet/src/test/resources/mybar.groovy  | 22 ++++++
 .../java/org/apache/camel/impl/DefaultModel.java   | 86 +++++++++++++---------
 3 files changed, 149 insertions(+), 35 deletions(-)

diff --git a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanGroovyExternalTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanGroovyExternalTest.java
new file mode 100644
index 0000000..d5a159c
--- /dev/null
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletLocalBeanGroovyExternalTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.kamelet;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.apache.http.annotation.Obsolete;
+import org.junit.jupiter.api.Test;
+
+public class KameletLocalBeanGroovyExternalTest extends CamelTestSupport {
+
+    @Test
+    public void testOne() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hi John we are going to Moes");
+
+        template.sendBody("direct:moe", "John");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testTwo() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hi Jack we are going to Shamrock",
+                "Hi Mary we are going to Moes");
+
+        template.sendBody("direct:shamrock", "Jack");
+        template.sendBody("direct:moe", "Mary");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // **********************************************
+    //
+    // test set-up
+    //
+    // **********************************************
+
+    @Obsolete
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                routeTemplate("whereTo")
+                        .templateParameter("bar") // name of bar
+                        .templateBean("myBar", "groovy", "resource:classpath:mybar.groovy")
+                        .from("kamelet:source")
+                        // must use {{myBar}} to refer to the local bean
+                        .to("bean:{{myBar}}");
+
+                from("direct:shamrock")
+                        .kamelet("whereTo?bar=Shamrock")
+                        .to("mock:result");
+
+                from("direct:moe")
+                        .kamelet("whereTo?bar=Moes")
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-kamelet/src/test/resources/mybar.groovy b/components/camel-kamelet/src/test/resources/mybar.groovy
new file mode 100644
index 0000000..a62ab64
--- /dev/null
+++ b/components/camel-kamelet/src/test/resources/mybar.groovy
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import org.apache.camel.component.kamelet.MyInjectBar
+
+def bean = new MyInjectBar()
+// context is RouteTemplateContext
+bean.bar = context.getProperty('bar')
+return bean
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
index 1dabbe4..8266c1a 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -55,6 +55,7 @@ import org.apache.camel.model.validator.ValidatorDefinition;
 import org.apache.camel.spi.ExchangeFactory;
 import org.apache.camel.spi.Language;
 import org.apache.camel.spi.ModelReifierFactory;
+import org.apache.camel.spi.ScriptingLanguage;
 import org.apache.camel.support.ScriptHelper;
 import org.apache.camel.util.AntPathMatcher;
 
@@ -306,30 +307,59 @@ public class DefaultModel implements Model {
 
         // setup local beans
         if (target.getTemplateBeans() != null) {
-            for (RouteTemplateBeanDefinition b : target.getTemplateBeans()) {
-                if (b.getBeanType() != null) {
-                    // could be created via XML DSL where you cannot program in Java and can only specify the bean as fqn classname
-                    Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(b.getBeanType());
-                    routeTemplateContext.bind(b.getName(), clazz, () -> camelContext.getInjector().newInstance(clazz));
-                } else if (b.getBeanSupplier() != null) {
-                    // bean class is optional for supplier
-                    if (b.getBeanClass() != null) {
-                        routeTemplateContext.bind(b.getName(), b.getBeanClass(), b.getBeanSupplier());
-                    } else {
-                        routeTemplateContext.bind(b.getName(), b.getBeanSupplier());
-                    }
-                } else if (b.getBeanFactory() != null) {
-                    final Language language = camelContext.resolveLanguage(b.getBeanFactory().getLanguage());
-                    final String script = b.getBeanFactory().getScript();
+            addTemplateBeans(routeTemplateContext, target);
+        }
+
+        if (target.getConfigurer() != null) {
+            routeTemplateContext.setConfigurer(target.getConfigurer());
+        }
+
+        // assign ids to the routes and validate that the id's are all unique
+        String duplicate = RouteDefinitionHelper.validateUniqueIds(def, routeDefinitions);
+        if (duplicate != null) {
+            throw new FailedToCreateRouteFromTemplateException(
+                    routeId, routeTemplateId,
+                    "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
+        }
+        addRouteDefinition(def);
+        return def.getId();
+    }
 
-                    final Class<?> clazz = b.getBeanClass() != null ? b.getBeanClass() : Object.class;
+    private void addTemplateBeans(RouteTemplateContext routeTemplateContext, RouteTemplateDefinition target) throws Exception {
+        for (RouteTemplateBeanDefinition b : target.getTemplateBeans()) {
+            if (b.getBeanType() != null) {
+                // could be created via XML DSL where you cannot program in Java and can only specify the bean as fqn classname
+                Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(b.getBeanType());
+                routeTemplateContext.bind(b.getName(), clazz, () -> camelContext.getInjector().newInstance(clazz));
+            } else if (b.getBeanSupplier() != null) {
+                // bean class is optional for supplier
+                if (b.getBeanClass() != null) {
+                    routeTemplateContext.bind(b.getName(), b.getBeanClass(), b.getBeanSupplier());
+                } else {
+                    routeTemplateContext.bind(b.getName(), b.getBeanSupplier());
+                }
+            } else if (b.getBeanFactory() != null) {
+                final String script = b.getBeanFactory().getScript();
+                final Class<?> clazz = b.getBeanClass() != null ? b.getBeanClass() : Object.class;
+
+                final Language lan = camelContext.resolveLanguage(b.getBeanFactory().getLanguage());
+                final ScriptingLanguage slan = lan instanceof ScriptingLanguage ? (ScriptingLanguage) lan : null;
+                if (slan != null) {
+                    // scripting language should be evaluated with route template context as binding
+                    routeTemplateContext.bind(b.getName(), clazz, () -> {
+                        Map<String, Object> bindings = new HashMap<>();
+                        bindings.put("context", routeTemplateContext);
+                        return slan.evaluate(script, bindings, clazz);
+                    });
+                } else {
+                    // exchange based languages needs a dummy exchange to be evaluated
                     routeTemplateContext.bind(b.getName(), clazz, () -> {
                         ExchangeFactory ef = camelContext.adapt(ExtendedCamelContext.class).getExchangeFactory();
                         Exchange dummy = ef.create(false);
                         try {
                             String text = ScriptHelper.resolveOptionalExternalScript(camelContext, dummy, script);
                             if (text != null) {
-                                Expression exp = language.createExpression(text);
+                                Expression exp = lan.createExpression(text);
                                 return exp.evaluate(dummy, clazz);
                             } else {
                                 return null;
@@ -338,27 +368,13 @@ public class DefaultModel implements Model {
                             ef.release(dummy);
                         }
                     });
-                } else if (b.getBeanClass() != null) {
-                    // we only have the bean class so we use that to create a new bean via the injector
-                    routeTemplateContext.bind(b.getName(), b.getBeanClass(),
-                            () -> camelContext.getInjector().newInstance(b.getBeanClass()));
                 }
+            } else if (b.getBeanClass() != null) {
+                // we only have the bean class so we use that to create a new bean via the injector
+                routeTemplateContext.bind(b.getName(), b.getBeanClass(),
+                        () -> camelContext.getInjector().newInstance(b.getBeanClass()));
             }
         }
-
-        if (target.getConfigurer() != null) {
-            routeTemplateContext.setConfigurer(target.getConfigurer());
-        }
-
-        // assign ids to the routes and validate that the id's are all unique
-        String duplicate = RouteDefinitionHelper.validateUniqueIds(def, routeDefinitions);
-        if (duplicate != null) {
-            throw new FailedToCreateRouteFromTemplateException(
-                    routeId, routeTemplateId,
-                    "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
-        }
-        addRouteDefinition(def);
-        return def.getId();
     }
 
     @Override

[camel] 05/06: CAMEL-16596: ScriptingLanguage SPI.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-16593
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 608bad0210a6cebe265d987c3a2ccda35ea9cccd
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon May 10 08:27:44 2021 +0200

    CAMEL-16596: ScriptingLanguage SPI.
---
 .../src/main/java/org/apache/camel/language/joor/JoorLanguage.java | 7 +------
 .../java/org/apache/camel/language/joor/JoorScriptingCompiler.java | 5 ++---
 .../java/org/apache/camel/language/joor/JoorScriptingMethod.java   | 4 +++-
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
index b3788d6..040b1f6 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorLanguage.java
@@ -90,12 +90,7 @@ public class JoorLanguage extends LanguageSupport implements ScriptingLanguage,
         Object out;
         JoorScriptingMethod target = scriptingCompiler.compile(getCamelContext(), script, bindings, resultType, singleQuotes);
         try {
-            if (bindings != null && !bindings.isEmpty()) {
-                Object[] args = bindings.values().toArray(new Object[0]);
-                out = target.evaluate(args);
-            } else {
-                out = target.evaluate();
-            }
+            out = target.evaluate(bindings);
         } catch (Exception e) {
             throw RuntimeCamelException.wrapRuntimeException(e);
         }
diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java
index 6527dd7..e5c3106 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingCompiler.java
@@ -156,16 +156,15 @@ public class JoorScriptingCompiler extends ServiceSupport implements StaticServi
 
         sb.append("    @Override\n");
         sb.append(
-                "    public Object evaluate(Object... args) throws Exception {\n");
+                "    public Object evaluate(Map<String, Object> args) throws Exception {\n");
         sb.append("        ");
 
         // bindings as local variables
         if (bindings != null) {
-            int i = 0;
             for (Map.Entry<String, Object> bind : bindings.entrySet()) {
                 String vn = bind.getKey();
                 String cn = ObjectHelper.className(bind.getValue());
-                String b = String.format("        var %s = (%s) args[%s];\n", vn, cn, i++);
+                String b = String.format("        var %s = (%s) args.get(\"%s\");\n", vn, cn, vn);
                 sb.append(b);
             }
             sb.append("\n");
diff --git a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingMethod.java b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingMethod.java
index 2d2eec6..1132634 100644
--- a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingMethod.java
+++ b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorScriptingMethod.java
@@ -16,11 +16,13 @@
  */
 package org.apache.camel.language.joor;
 
+import java.util.Map;
+
 /**
  * Interface for the compiled joor scripting method when evaluating as scripting language.
  */
 public interface JoorScriptingMethod {
 
-    Object evaluate(Object... args) throws Exception;
+    Object evaluate(Map<String, Object> args) throws Exception;
 
 }