You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2023/03/27 13:43:38 UTC

[camel-quarkus] branch camel-main updated (d2b277f1ae -> 15d49c6403)

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

jamesnetherton pushed a change to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


    from d2b277f1ae Upgrade Camel to 4.0.0-M3
     new 01f3cdecac Add support of expressions referring an external resource
     new 15d49c6403 Ref #1746: Groovy language native support

The 2 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:
 docs/modules/ROOT/examples/languages/groovy.yml    |   6 +-
 .../ROOT/pages/reference/extensions/groovy.adoc    |  22 ++-
 .../groovy/deployment/GroovyProcessor.java         |  47 ------
 extensions-jvm/pom.xml                             |   1 -
 .../language/deployment/ExpressionBuildItem.java   |  26 ++-
 .../deployment/LanguageSupportProcessor.java       |  10 +-
 .../language/deployment/ScriptBuildItem.java       |   8 +-
 .../language/deployment/dm/DryModeLanguage.java    |  17 +-
 .../deployment/dm/DryModeLanguageResolver.java     |   4 +-
 .../deployment/dm/DryModeScriptingLanguage.java    |   7 +-
 .../language/deployment/dm/ExpressionHolder.java   |  12 +-
 .../language/deployment/dm/ScriptHolder.java       |   8 +-
 .../groovy/deployment/pom.xml                      |   8 +
 .../GroovyExpressionSourceBuildItem.java}          |  31 ++--
 .../groovy/deployment/GroovyProcessor.java         | 176 +++++++++++++++++++++
 {extensions-jvm => extensions}/groovy/pom.xml      |   2 +-
 .../groovy/runtime/pom.xml                         |   9 ++
 .../groovy/runtime/src/main/doc/limitations.adoc   |   3 +
 .../groovy/runtime/GroovyExpressionRecorder.java}  |  25 +--
 .../groovy/runtime/GroovyStaticScript.java         |  63 ++++++++
 .../main/resources/META-INF/quarkus-extension.yaml |   0
 extensions/pom.xml                                 |   1 +
 integration-tests-jvm/groovy/pom.xml               | 100 ------------
 integration-tests-jvm/pom.xml                      |   1 -
 integration-tests/{ognl => groovy}/pom.xml         |  25 +--
 .../quarkus/component/groovy/it/GroovyBean.java}   |   4 +-
 .../component/groovy/it/GroovyResource.java        |  24 +++
 .../quarkus/component/groovy/it/GroovyRoutes.java  |  18 +++
 .../groovy/src/main/resources/bean.txt             |   4 +
 .../quarkus/component/groovy/it/GroovyIT.java      |   4 +-
 .../quarkus/component/groovy/it/GroovyTest.java    |  43 ++++-
 integration-tests/pom.xml                          |   3 +-
 tooling/scripts/test-categories.yaml               |   1 +
 33 files changed, 491 insertions(+), 222 deletions(-)
 delete mode 100644 extensions-jvm/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java
 rename {extensions-jvm => extensions}/groovy/deployment/pom.xml (87%)
 copy extensions/{csimple/deployment/src/main/java/org/apache/camel/quarkus/component/csimple/deployment/CSimpleExpressionSourceBuildItem.java => groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyExpressionSourceBuildItem.java} (64%)
 create mode 100644 extensions/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java
 rename {extensions-jvm => extensions}/groovy/pom.xml (96%)
 rename {extensions-jvm => extensions}/groovy/runtime/pom.xml (90%)
 create mode 100644 extensions/groovy/runtime/src/main/doc/limitations.adoc
 copy extensions/{csimple/runtime/src/main/java/org/apache/camel/quarkus/component/csimple/CSimpleLanguageRecorder.java => groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyExpressionRecorder.java} (57%)
 create mode 100644 extensions/groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyStaticScript.java
 rename {extensions-jvm => extensions}/groovy/runtime/src/main/resources/META-INF/quarkus-extension.yaml (100%)
 delete mode 100644 integration-tests-jvm/groovy/pom.xml
 copy integration-tests/{ognl => groovy}/pom.xml (91%)
 copy integration-tests/{joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorBean.java => groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyBean.java} (93%)
 rename {integration-tests-jvm => integration-tests}/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java (73%)
 rename {integration-tests-jvm => integration-tests}/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java (63%)
 create mode 100644 integration-tests/groovy/src/main/resources/bean.txt
 copy integration-test-groups/foundation/browse/src/test/java/org/apache/camel/quarkus/component/browse/it/BrowseIT.java => integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyIT.java (90%)
 rename {integration-tests-jvm => integration-tests}/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java (55%)


[camel-quarkus] 02/02: Ref #1746: Groovy language native support

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

jamesnetherton pushed a commit to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 15d49c6403798bca8cd696fd33f82d9839255a40
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Wed Mar 22 16:58:08 2023 +0100

    Ref #1746: Groovy language native support
---
 docs/modules/ROOT/examples/languages/groovy.yml    |   6 +-
 .../ROOT/pages/reference/extensions/groovy.adoc    |  22 ++-
 .../groovy/deployment/GroovyProcessor.java         |  47 ------
 extensions-jvm/pom.xml                             |   1 -
 .../groovy/deployment/pom.xml                      |   8 +
 .../GroovyExpressionSourceBuildItem.java           |  57 +++++++
 .../groovy/deployment/GroovyProcessor.java         | 176 +++++++++++++++++++++
 {extensions-jvm => extensions}/groovy/pom.xml      |   2 +-
 .../groovy/runtime/pom.xml                         |   9 ++
 .../groovy/runtime/src/main/doc/limitations.adoc   |   3 +
 .../groovy/runtime/GroovyExpressionRecorder.java   |  43 +++++
 .../groovy/runtime/GroovyStaticScript.java         |  63 ++++++++
 .../main/resources/META-INF/quarkus-extension.yaml |   0
 extensions/pom.xml                                 |   1 +
 integration-tests-jvm/pom.xml                      |   1 -
 .../groovy/pom.xml                                 |  68 +++++++-
 .../quarkus/component/groovy/it/GroovyBean.java    |  16 +-
 .../component/groovy/it/GroovyResource.java        |  24 +++
 .../quarkus/component/groovy/it/GroovyRoutes.java  |  18 +++
 .../groovy/src/main/resources/bean.txt             |   4 +
 .../quarkus/component/groovy/it/GroovyIT.java      |  21 +--
 .../quarkus/component/groovy/it/GroovyTest.java    |  43 ++++-
 integration-tests/pom.xml                          |   3 +-
 tooling/scripts/test-categories.yaml               |   1 +
 24 files changed, 551 insertions(+), 86 deletions(-)

diff --git a/docs/modules/ROOT/examples/languages/groovy.yml b/docs/modules/ROOT/examples/languages/groovy.yml
index 6a2a19afa1..5f8155df7b 100644
--- a/docs/modules/ROOT/examples/languages/groovy.yml
+++ b/docs/modules/ROOT/examples/languages/groovy.yml
@@ -2,11 +2,11 @@
 # This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
 cqArtifactId: camel-quarkus-groovy
 cqArtifactIdBase: groovy
-cqNativeSupported: false
-cqStatus: Preview
+cqNativeSupported: true
+cqStatus: Stable
 cqDeprecated: false
 cqJvmSince: 1.0.0
-cqNativeSince: n/a
+cqNativeSince: 3.0.0
 cqCamelPartName: groovy
 cqCamelPartTitle: Groovy
 cqCamelPartDescription: Evaluates a Groovy script.
diff --git a/docs/modules/ROOT/pages/reference/extensions/groovy.adoc b/docs/modules/ROOT/pages/reference/extensions/groovy.adoc
index 45a56e1a12..e0c5ad48ed 100644
--- a/docs/modules/ROOT/pages/reference/extensions/groovy.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/groovy.adoc
@@ -5,17 +5,17 @@
 :page-aliases: extensions/groovy.adoc
 :linkattrs:
 :cq-artifact-id: camel-quarkus-groovy
-:cq-native-supported: false
-:cq-status: Preview
-:cq-status-deprecation: Preview
+:cq-native-supported: true
+:cq-status: Stable
+:cq-status-deprecation: Stable
 :cq-description: Evaluate a Groovy script
 :cq-deprecated: false
 :cq-jvm-since: 1.0.0
-:cq-native-since: n/a
+:cq-native-since: 3.0.0
 
 ifeval::[{doc-show-badges} == true]
 [.badges]
-[.badge-key]##JVM since##[.badge-supported]##1.0.0## [.badge-key]##Native##[.badge-unsupported]##unsupported##
+[.badge-key]##JVM since##[.badge-supported]##1.0.0## [.badge-key]##Native since##[.badge-supported]##3.0.0##
 endif::[]
 
 Evaluate a Groovy script
@@ -30,6 +30,10 @@ Please refer to the above link for usage and configuration details.
 [id="extensions-groovy-maven-coordinates"]
 == Maven coordinates
 
+https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-groovy[Create a new project with this extension on {link-quarkus-code-generator}, window="_blank"]
+
+Or add the coordinates to your existing project:
+
 [source,xml]
 ----
 <dependency>
@@ -40,3 +44,11 @@ Please refer to the above link for usage and configuration details.
 ifeval::[{doc-show-user-guide-link} == true]
 Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
 endif::[]
+
+[id="extensions-groovy-camel-quarkus-limitations"]
+== Camel Quarkus limitations
+
+Due to some limitations in GraalVM that prevent to execute even basic scripts in native mode, the compilation of the
+Groovy expressions is made with the static compilation enabled which means that the types used in your expression must
+be known at compile time. Please refer to the https://docs.groovy-lang.org/latest/html/documentation/core-semantics.html#static-type-checking[Groovy documentation for more details].
+
diff --git a/extensions-jvm/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java b/extensions-jvm/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java
deleted file mode 100644
index 3b8716ad29..0000000000
--- a/extensions-jvm/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.quarkus.component.groovy.deployment;
-
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.ExecutionTime;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.pkg.steps.NativeBuild;
-import org.apache.camel.quarkus.core.JvmOnlyRecorder;
-import org.jboss.logging.Logger;
-
-class GroovyProcessor {
-    private static final Logger LOG = Logger.getLogger(GroovyProcessor.class);
-
-    private static final String FEATURE = "camel-groovy";
-
-    @BuildStep
-    FeatureBuildItem feature() {
-        return new FeatureBuildItem(FEATURE);
-    }
-
-    /**
-     * Remove this once this extension starts supporting the native mode.
-     */
-    @BuildStep(onlyIf = NativeBuild.class)
-    @Record(value = ExecutionTime.RUNTIME_INIT)
-    void warnJvmInNative(JvmOnlyRecorder recorder) {
-        JvmOnlyRecorder.warnJvmInNative(LOG, FEATURE); // warn at build time
-        recorder.warnJvmInNative(FEATURE); // warn at runtime
-    }
-
-}
diff --git a/extensions-jvm/pom.xml b/extensions-jvm/pom.xml
index 383deda2b3..2c619170dd 100644
--- a/extensions-jvm/pom.xml
+++ b/extensions-jvm/pom.xml
@@ -65,7 +65,6 @@
         <module>flink</module>
         <module>google-functions</module>
         <module>google-secret-manager</module>
-        <module>groovy</module>
         <module>guava-eventbus</module>
         <module>hashicorp-vault</module>
         <module>hdfs</module>
diff --git a/extensions-jvm/groovy/deployment/pom.xml b/extensions/groovy/deployment/pom.xml
similarity index 87%
rename from extensions-jvm/groovy/deployment/pom.xml
rename to extensions/groovy/deployment/pom.xml
index e321de40a9..0beefa5e60 100644
--- a/extensions-jvm/groovy/deployment/pom.xml
+++ b/extensions/groovy/deployment/pom.xml
@@ -38,6 +38,14 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-groovy</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-groovy-dsl-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-support-language-deployment</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/extensions/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyExpressionSourceBuildItem.java b/extensions/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyExpressionSourceBuildItem.java
new file mode 100644
index 0000000000..104e478083
--- /dev/null
+++ b/extensions/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyExpressionSourceBuildItem.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.quarkus.component.groovy.deployment;
+
+import io.quarkus.builder.item.MultiBuildItem;
+
+/**
+ * A {@link MultiBuildItem} bearing info about a Groovy language expression that needs to get compiled.
+ */
+public final class GroovyExpressionSourceBuildItem extends MultiBuildItem {
+
+    private final String sourceCode;
+    private final String originalCode;
+    private final String className;
+
+    public GroovyExpressionSourceBuildItem(String className, String originalCode, String sourceCode) {
+        this.className = className;
+        this.originalCode = originalCode;
+        this.sourceCode = sourceCode;
+    }
+
+    /**
+     * @return the expression source code to compile
+     */
+    public String getSourceCode() {
+        return sourceCode;
+    }
+
+    /**
+     * @return the original content of the extracted expression.
+     */
+    public String getOriginalCode() {
+        return originalCode;
+    }
+
+    /**
+     * @return a fully qualified class name that the compiler may use as a base for the name of the class into which it
+     *         compiles the source code returned by {@link #getSourceCode()}
+     */
+    public String getClassName() {
+        return className;
+    }
+}
diff --git a/extensions/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java b/extensions/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java
new file mode 100644
index 0000000000..03fcd47769
--- /dev/null
+++ b/extensions/groovy/deployment/src/main/java/org/apache/camel/quarkus/component/groovy/deployment/GroovyProcessor.java
@@ -0,0 +1,176 @@
+/*
+ * 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.quarkus.component.groovy.deployment;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
+import io.quarkus.deployment.pkg.steps.NativeBuild;
+import io.quarkus.deployment.recording.RecorderContext;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathCollection;
+import io.quarkus.runtime.RuntimeValue;
+import org.apache.camel.language.groovy.GroovyLanguage;
+import org.apache.camel.quarkus.component.groovy.runtime.GroovyExpressionRecorder;
+import org.apache.camel.quarkus.component.groovy.runtime.GroovyStaticScript;
+import org.apache.camel.quarkus.core.deployment.spi.CamelBeanBuildItem;
+import org.apache.camel.quarkus.support.language.deployment.ExpressionBuildItem;
+import org.apache.camel.quarkus.support.language.deployment.ExpressionExtractionResultBuildItem;
+import org.apache.camel.quarkus.support.language.deployment.ScriptBuildItem;
+import org.apache.camel.quarkus.support.language.runtime.ExpressionUID;
+import org.apache.camel.quarkus.support.language.runtime.ScriptUID;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.tools.GroovyClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class GroovyProcessor {
+    private static final Logger LOG = LoggerFactory.getLogger(GroovyProcessor.class);
+
+    private static final String PACKAGE_NAME = "org.apache.camel.quarkus.component.groovy.generated";
+    private static final String SCRIPT_FORMAT = """
+            package %s
+            @groovy.transform.CompileStatic
+            class %s extends %s {
+              Object run() {
+                %s
+              }
+            }
+            """;
+    private static final String FEATURE = "camel-groovy";
+
+    @BuildStep
+    FeatureBuildItem feature() {
+        return new FeatureBuildItem(FEATURE);
+    }
+
+    @BuildStep(onlyIf = NativeBuild.class)
+    void collectExpressions(ExpressionExtractionResultBuildItem result,
+            List<ExpressionBuildItem> expressions,
+            List<ScriptBuildItem> scripts,
+            BuildProducer<GroovyExpressionSourceBuildItem> producer) {
+        if (result.isSuccess()) {
+            List<ExpressionBuildItem> groovyExpressions = expressions.stream()
+                    .filter(exp -> "groovy".equals(exp.getLanguage()))
+                    .toList();
+            List<ScriptBuildItem> groovyScripts = scripts.stream()
+                    .filter(exp -> "groovy".equals(exp.getLanguage()))
+                    .toList();
+            if (groovyExpressions.isEmpty() && groovyScripts.isEmpty()) {
+                return;
+            }
+            for (ExpressionBuildItem expression : groovyExpressions) {
+                String original = expression.getExpression();
+                ExpressionUID id = new ExpressionUID(original);
+                String name = String.format("%s.%s", PACKAGE_NAME, id);
+                String content = toScriptClass(id.asJavaIdentifier(), expression.getLoadedExpression());
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Extracting expression:\n\n{}\n", content);
+                }
+                producer.produce(new GroovyExpressionSourceBuildItem(name, original, content));
+            }
+            for (ScriptBuildItem script : groovyScripts) {
+                String original = script.getContent();
+                ScriptUID id = new ScriptUID(original, script.getBindings());
+                String name = String.format("%s.%s", PACKAGE_NAME, id);
+                String content = toScriptClass(id.asJavaIdentifier(), script.getLoadedContent());
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Extracting script:\n\n{}\n", content);
+                }
+                producer.produce(new GroovyExpressionSourceBuildItem(name, original, content));
+            }
+        }
+    }
+
+    @BuildStep(onlyIf = NativeBuild.class)
+    void compileScriptsAOT(CurateOutcomeBuildItem curateOutcomeBuildItem,
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            List<GroovyExpressionSourceBuildItem> sources,
+            BuildProducer<GeneratedClassBuildItem> generatedClass) {
+        if (sources.isEmpty()) {
+            return;
+        }
+        CompilationUnit unit = new CompilationUnit();
+        Set<String> classNames = new HashSet<>();
+        for (GroovyExpressionSourceBuildItem source : sources) {
+            String name = source.getClassName();
+            String content = source.getSourceCode();
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Compiling script:\n\n{}\n", content);
+            }
+            unit.addSource(name, content);
+            classNames.add(name);
+        }
+        CompilerConfiguration cc = new CompilerConfiguration();
+        cc.setClasspathList(
+                curateOutcomeBuildItem.getApplicationModel().getDependencies().stream()
+                        .map(ResolvedDependency::getResolvedPaths)
+                        .flatMap(PathCollection::stream)
+                        .map(Objects::toString)
+                        .toList());
+        unit.configure(cc);
+        unit.compile(Phases.CLASS_GENERATION);
+        for (GroovyClass clazz : unit.getClasses()) {
+            String className = clazz.getName();
+            generatedClass.produce(new GeneratedClassBuildItem(true, className, clazz.getBytes()));
+            if (classNames.contains(className)) {
+                reflectiveClass.produce(ReflectiveClassBuildItem.builder(className).methods().fields().build());
+            }
+        }
+    }
+
+    @Record(ExecutionTime.STATIC_INIT)
+    @BuildStep(onlyIf = NativeBuild.class)
+    CamelBeanBuildItem configureLanguage(
+            RecorderContext recorderContext,
+            GroovyExpressionRecorder recorder,
+            ExpressionExtractionResultBuildItem result,
+            List<GroovyExpressionSourceBuildItem> sources) {
+        if (result.isSuccess() && !sources.isEmpty()) {
+            RuntimeValue<GroovyLanguage.Builder> builder = recorder.languageBuilder();
+            for (GroovyExpressionSourceBuildItem source : sources) {
+                recorder.addScript(builder, source.getOriginalCode(), recorderContext.classProxy(source.getClassName()));
+            }
+            final RuntimeValue<GroovyLanguage> language = recorder.languageNewInstance(builder);
+            return new CamelBeanBuildItem("groovy", GroovyLanguage.class.getName(), language);
+        }
+        return null;
+    }
+
+    /**
+     * Convert a Groovy expression into a Script class to be able to compile it.
+     *
+     * @param  name          the name of the Groovy expression
+     * @param  contentScript the content of the Groovy script
+     * @return               the content of the corresponding Script class.
+     */
+    private static String toScriptClass(String name, String contentScript) {
+        return String.format(SCRIPT_FORMAT, PACKAGE_NAME, name, GroovyStaticScript.class.getName(), contentScript);
+    }
+}
diff --git a/extensions-jvm/groovy/pom.xml b/extensions/groovy/pom.xml
similarity index 96%
rename from extensions-jvm/groovy/pom.xml
rename to extensions/groovy/pom.xml
index a5eee7f5d6..dac9f90a14 100644
--- a/extensions-jvm/groovy/pom.xml
+++ b/extensions/groovy/pom.xml
@@ -21,7 +21,7 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.camel.quarkus</groupId>
-        <artifactId>camel-quarkus-extensions-jvm</artifactId>
+        <artifactId>camel-quarkus-extensions</artifactId>
         <version>3.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
diff --git a/extensions-jvm/groovy/runtime/pom.xml b/extensions/groovy/runtime/pom.xml
similarity index 90%
rename from extensions-jvm/groovy/runtime/pom.xml
rename to extensions/groovy/runtime/pom.xml
index 8990247530..b1f0e4483e 100644
--- a/extensions-jvm/groovy/runtime/pom.xml
+++ b/extensions/groovy/runtime/pom.xml
@@ -32,6 +32,7 @@
 
     <properties>
         <camel.quarkus.jvmSince>1.0.0</camel.quarkus.jvmSince>
+        <camel.quarkus.nativeSince>3.0.0</camel.quarkus.nativeSince>
     </properties>
 
     <dependencies>
@@ -39,10 +40,18 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-support-language</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-groovy</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-groovy-dsl</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/extensions/groovy/runtime/src/main/doc/limitations.adoc b/extensions/groovy/runtime/src/main/doc/limitations.adoc
new file mode 100644
index 0000000000..5aa4300809
--- /dev/null
+++ b/extensions/groovy/runtime/src/main/doc/limitations.adoc
@@ -0,0 +1,3 @@
+Due to some limitations in GraalVM that prevent to execute even basic scripts in native mode, the compilation of the
+Groovy expressions is made with the static compilation enabled which means that the types used in your expression must
+be known at compile time. Please refer to the https://docs.groovy-lang.org/latest/html/documentation/core-semantics.html#static-type-checking[Groovy documentation for more details].
diff --git a/extensions/groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyExpressionRecorder.java b/extensions/groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyExpressionRecorder.java
new file mode 100644
index 0000000000..e1d9a922a9
--- /dev/null
+++ b/extensions/groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyExpressionRecorder.java
@@ -0,0 +1,43 @@
+/*
+ * 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.quarkus.component.groovy.runtime;
+
+import groovy.lang.Script;
+import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.Recorder;
+import org.apache.camel.language.groovy.GroovyLanguage;
+
+@Recorder
+public class GroovyExpressionRecorder {
+
+    public RuntimeValue<GroovyLanguage.Builder> languageBuilder() {
+        return new RuntimeValue<>(new GroovyLanguage.Builder());
+    }
+
+    @SuppressWarnings("unchecked")
+    public void addScript(RuntimeValue<GroovyLanguage.Builder> builder, String content, Class<?> clazz) {
+        try {
+            builder.getValue().addScript(content, (Class<Script>) clazz);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public RuntimeValue<GroovyLanguage> languageNewInstance(RuntimeValue<GroovyLanguage.Builder> builder) {
+        return new RuntimeValue<>(builder.getValue().build());
+    }
+}
diff --git a/extensions/groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyStaticScript.java b/extensions/groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyStaticScript.java
new file mode 100644
index 0000000000..f2d86e6577
--- /dev/null
+++ b/extensions/groovy/runtime/src/main/java/org/apache/camel/quarkus/component/groovy/runtime/GroovyStaticScript.java
@@ -0,0 +1,63 @@
+/*
+ * 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.quarkus.component.groovy.runtime;
+
+import java.util.Map;
+
+import groovy.lang.Binding;
+import groovy.lang.Script;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.RouteTemplateContext;
+
+/**
+ * A type of {@link Script} that is specific to Camel with fixed fields to be able to compile the script using
+ * static compilation.
+ */
+public abstract class GroovyStaticScript extends Script {
+
+    protected Map<String, Object> headers;
+    protected Object body;
+    protected Message in;
+    protected Message request;
+    protected Exchange exchange;
+    protected Message out;
+    protected Message response;
+    protected CamelContext camelContext;
+    protected RouteTemplateContext rtc;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void setBinding(Binding binding) {
+        super.setBinding(binding);
+        this.headers = (Map<String, Object>) getPropertyValue("headers");
+        this.body = getPropertyValue("body");
+        this.in = (Message) getPropertyValue("in");
+        this.out = (Message) getPropertyValue("out");
+        this.request = (Message) getPropertyValue("request");
+        this.response = (Message) getPropertyValue("response");
+        this.exchange = (Exchange) getPropertyValue("exchange");
+        this.camelContext = (CamelContext) getPropertyValue("camelContext");
+        this.rtc = (RouteTemplateContext) getPropertyValue("rtc");
+    }
+
+    private Object getPropertyValue(String name) {
+        Binding binding = getBinding();
+        return binding.hasVariable(name) ? binding.getProperty(name) : null;
+    }
+}
diff --git a/extensions-jvm/groovy/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/groovy/runtime/src/main/resources/META-INF/quarkus-extension.yaml
similarity index 100%
rename from extensions-jvm/groovy/runtime/src/main/resources/META-INF/quarkus-extension.yaml
rename to extensions/groovy/runtime/src/main/resources/META-INF/quarkus-extension.yaml
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 180d62022b..e1331a0fb8 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -117,6 +117,7 @@
         <module>google-storage</module>
         <module>graphql</module>
         <module>grok</module>
+        <module>groovy</module>
         <module>groovy-dsl</module>
         <module>grpc</module>
         <module>gson</module>
diff --git a/integration-tests-jvm/pom.xml b/integration-tests-jvm/pom.xml
index b011c16c03..a948f45be2 100644
--- a/integration-tests-jvm/pom.xml
+++ b/integration-tests-jvm/pom.xml
@@ -64,7 +64,6 @@
         <module>flink</module>
         <module>google-functions</module>
         <module>google-secret-manager</module>
-        <module>groovy</module>
         <module>guava-eventbus</module>
         <module>hashicorp-vault</module>
         <module>hdfs</module>
diff --git a/integration-tests-jvm/groovy/pom.xml b/integration-tests/groovy/pom.xml
similarity index 60%
rename from integration-tests-jvm/groovy/pom.xml
rename to integration-tests/groovy/pom.xml
index a17bd3bf5f..0acaec5782 100644
--- a/integration-tests-jvm/groovy/pom.xml
+++ b/integration-tests/groovy/pom.xml
@@ -39,6 +39,14 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-direct</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-kamelet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-bean</artifactId>
+        </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-resteasy</artifactId>
@@ -54,6 +62,12 @@
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
             <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.groovy</groupId>
+                    <artifactId>groovy</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
     </dependencies>
 
@@ -67,6 +81,19 @@
             </activation>
             <dependencies>
                 <!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-bean-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
                 <dependency>
                     <groupId>org.apache.camel.quarkus</groupId>
                     <artifactId>camel-quarkus-direct-deployment</artifactId>
@@ -93,8 +120,47 @@
                         </exclusion>
                     </exclusions>
                 </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-kamelet-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
             </dependencies>
         </profile>
+        <profile>
+            <id>native</id>
+            <activation>
+                <property>
+                    <name>native</name>
+                </property>
+            </activation>
+            <properties>
+                <quarkus.package.type>native</quarkus.package.type>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
-
 </project>
diff --git a/integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyBean.java
similarity index 72%
copy from integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java
copy to integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyBean.java
index 59c03d1ec0..e0108b0fbd 100644
--- a/integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java
+++ b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyBean.java
@@ -16,16 +16,18 @@
  */
 package org.apache.camel.quarkus.component.groovy.it;
 
-import org.apache.camel.builder.RouteBuilder;
+import io.quarkus.runtime.annotations.RegisterForReflection;
 
-public class GroovyRoutes extends RouteBuilder {
+@RegisterForReflection
+public class GroovyBean {
 
-    @Override
-    public void configure() {
+    private String bar;
 
-        from("direct:scriptGroovy")
-                .script()
-                .groovy("exchange.getMessage().setBody('Hello ' + exchange.getMessage().getBody(String.class) + ' from Groovy!')");
+    public void setBar(String bar) {
+        this.bar = bar;
+    }
 
+    public String where(String name) {
+        return "Hi " + name + " we are going to " + bar;
     }
 }
diff --git a/integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java
similarity index 73%
rename from integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java
rename to integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java
index a953e27812..2732e8ccc1 100644
--- a/integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java
+++ b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java
@@ -40,6 +40,30 @@ public class GroovyResource {
     @Inject
     ProducerTemplate producerTemplate;
 
+    @POST
+    @Path("/hello")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String hello(String message) {
+        return producerTemplate.requestBody("direct:groovyHello", message, String.class);
+    }
+
+    @POST
+    @Path("/hi")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String hi(String message) {
+        return producerTemplate.requestBody("direct:groovyHi", message, String.class);
+    }
+
+    @POST
+    @Path("/predicate")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String predicate(String message) {
+        return producerTemplate.requestBody("direct:predicate", Integer.valueOf(message), String.class);
+    }
+
     @Path("/route/{route}")
     @POST
     @Consumes(MediaType.TEXT_PLAIN)
diff --git a/integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java
similarity index 63%
rename from integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java
rename to integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java
index 59c03d1ec0..4fd526812b 100644
--- a/integration-tests-jvm/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java
+++ b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java
@@ -23,6 +23,24 @@ public class GroovyRoutes extends RouteBuilder {
     @Override
     public void configure() {
 
+        routeTemplate("whereTo")
+                .templateParameter("bar")
+                .templateBean("myBar", "groovy", "resource:classpath:bean.txt")
+                .from("kamelet:source")
+                .to("bean:{{myBar}}");
+
+        from("direct:groovyHi")
+                .kamelet("whereTo?bar=Shamrock");
+
+        from("direct:groovyHello")
+                .transform().groovy("\"Hello \" + body + \" from Groovy!\"");
+        from("direct:predicate")
+                .choice()
+                .when().groovy("((int) body) / 2 > 10")
+                .setBody().constant("High").endChoice()
+                .otherwise()
+                .setBody().constant("Low").endChoice();
+
         from("direct:scriptGroovy")
                 .script()
                 .groovy("exchange.getMessage().setBody('Hello ' + exchange.getMessage().getBody(String.class) + ' from Groovy!')");
diff --git a/integration-tests/groovy/src/main/resources/bean.txt b/integration-tests/groovy/src/main/resources/bean.txt
new file mode 100644
index 0000000000..eb19a8a2d9
--- /dev/null
+++ b/integration-tests/groovy/src/main/resources/bean.txt
@@ -0,0 +1,4 @@
+def bean = new org.apache.camel.quarkus.component.groovy.it.GroovyBean()
+// rtc is RouteTemplateContext
+bean.setBar(rtc.getProperty('bar', String.class))
+return bean
diff --git a/integration-tests-jvm/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java b/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyIT.java
similarity index 61%
copy from integration-tests-jvm/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java
copy to integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyIT.java
index 258c35f43c..68c7733865 100644
--- a/integration-tests-jvm/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java
+++ b/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyIT.java
@@ -16,24 +16,9 @@
  */
 package org.apache.camel.quarkus.component.groovy.it;
 
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import io.restassured.http.ContentType;
-import org.hamcrest.Matchers;
-import org.junit.jupiter.api.Test;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
 
-@QuarkusTest
-class GroovyTest {
-
-    @Test
-    public void script() {
-        RestAssured.given()
-                .contentType(ContentType.TEXT)
-                .body("world")
-                .post("/groovy/route/scriptGroovy")
-                .then()
-                .statusCode(200)
-                .body(Matchers.is("Hello world from Groovy!"));
-    }
+@QuarkusIntegrationTest
+class GroovyIT extends GroovyTest {
 
 }
diff --git a/integration-tests-jvm/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java b/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java
similarity index 55%
rename from integration-tests-jvm/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java
rename to integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java
index 258c35f43c..1a4dc1a3a1 100644
--- a/integration-tests-jvm/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java
+++ b/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java
@@ -19,6 +19,7 @@ package org.apache.camel.quarkus.component.groovy.it;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matchers;
 import org.junit.jupiter.api.Test;
 
@@ -26,7 +27,47 @@ import org.junit.jupiter.api.Test;
 class GroovyTest {
 
     @Test
-    public void script() {
+    void groovyHello() {
+        RestAssured.given()
+                .body("Will Smith")
+                .post("/groovy/hello")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Hello Will Smith from Groovy!"));
+    }
+
+    @Test
+    void groovyHi() {
+        RestAssured.given()
+                .body("Jack")
+                .post("/groovy/hi")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Hi Jack we are going to Shamrock"));
+    }
+
+    @Test
+    void groovyHigh() {
+        RestAssured.given()
+                .body("45")
+                .post("/groovy/predicate")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("High"));
+    }
+
+    @Test
+    void groovyLow() {
+        RestAssured.given()
+                .body("13")
+                .post("/groovy/predicate")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Low"));
+    }
+
+    @Test
+    void script() {
         RestAssured.given()
                 .contentType(ContentType.TEXT)
                 .body("world")
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 3c642e87ff..504fa2ef29 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -105,13 +105,14 @@
         <module>google-storage</module>
         <module>graphql</module>
         <module>grok</module>
+        <module>groovy</module>
         <module>groovy-dsl</module>
         <module>grpc</module>
         <!--<module>hazelcast</module> https://github.com/apache/camel-quarkus/issues/4498 -->
         <module>headersmap</module>
         <module>hl7</module>
         <module>http</module>
-	<module>infinispan</module>
+        <module>infinispan</module>
         <module>infinispan-common</module>
         <module>infinispan-quarkus-client</module>
         <module>influxdb</module>
diff --git a/tooling/scripts/test-categories.yaml b/tooling/scripts/test-categories.yaml
index 3cdeaff620..07ba7c1c30 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -142,6 +142,7 @@ group-10:
   - consul
   - digitalocean
   - fop
+  - groovy
   - joor
   - kotlin
   - mail


[camel-quarkus] 01/02: Add support of expressions referring an external resource

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

jamesnetherton pushed a commit to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 01f3cdecacb72633ca19a251b4a880482fa84ede
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Thu Mar 23 19:39:57 2023 +0100

    Add support of expressions referring an external resource
---
 .../language/deployment/ExpressionBuildItem.java   | 26 +++++++++++++++++++++-
 .../deployment/LanguageSupportProcessor.java       | 10 ++++++---
 .../language/deployment/ScriptBuildItem.java       |  8 ++++++-
 .../language/deployment/dm/DryModeLanguage.java    | 17 ++++++++------
 .../deployment/dm/DryModeLanguageResolver.java     |  4 ++--
 .../deployment/dm/DryModeScriptingLanguage.java    |  7 +++---
 .../language/deployment/dm/ExpressionHolder.java   | 12 +++++++---
 .../language/deployment/dm/ScriptHolder.java       |  8 ++++++-
 8 files changed, 71 insertions(+), 21 deletions(-)

diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
index bbb5242308..b3dc72b3fa 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
@@ -26,28 +26,52 @@ public final class ExpressionBuildItem extends MultiBuildItem {
 
     final String language;
     final String expression;
+    final String loadedExpression;
     final boolean predicate;
     final Object[] properties;
 
-    public ExpressionBuildItem(String language, String expression, Object[] properties, boolean predicate) {
+    public ExpressionBuildItem(String language, String expression, String loadedExpression, Object[] properties,
+            boolean predicate) {
         this.language = language;
         this.expression = expression;
+        this.loadedExpression = loadedExpression;
         this.properties = properties;
         this.predicate = predicate;
     }
 
+    /**
+     * @return the name of the language in which the expression is written.
+     */
     public String getLanguage() {
         return language;
     }
 
+    /**
+     * @return the original content of the extracted expression.
+     */
     public String getExpression() {
         return expression;
     }
 
+    /**
+     * @return the content of the expression after being loaded in case the given expression is referring to an external
+     *         resource by using the syntax
+     *         <tt>resource:scheme:uri<tt>.
+     */
+    public String getLoadedExpression() {
+        return loadedExpression;
+    }
+
+    /**
+     * @return {@code true} if the expression is a predicate, {@code false} otherwise.
+     */
     public boolean isPredicate() {
         return predicate;
     }
 
+    /**
+     * @return the properties provided to evaluate the expression.
+     */
     public Object[] getProperties() {
         return properties;
     }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java
index 3a5f88eaf0..7f95d71d40 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java
@@ -64,13 +64,17 @@ class LanguageSupportProcessor {
                 for (DryModeLanguage language : main.getLanguages()) {
                     final String name = language.getName();
                     for (ExpressionHolder holder : language.getPredicates()) {
-                        expressions.produce(new ExpressionBuildItem(name, holder.getContent(), holder.getProperties(), true));
+                        expressions.produce(new ExpressionBuildItem(name, holder.getContent(), holder.getLoadedContent(),
+                                holder.getProperties(), true));
                     }
                     for (ExpressionHolder holder : language.getExpressions()) {
-                        expressions.produce(new ExpressionBuildItem(name, holder.getContent(), holder.getProperties(), false));
+                        expressions.produce(new ExpressionBuildItem(name, holder.getContent(), holder.getLoadedContent(),
+                                holder.getProperties(), false));
                     }
                     for (ScriptHolder script : language.getScripts()) {
-                        scripts.produce(new ScriptBuildItem(name, script.getContent(), script.getBindings()));
+                        scripts.produce(
+                                new ScriptBuildItem(name, script.getContent(), script.getLoadedContent(),
+                                        script.getBindings()));
                     }
                 }
                 return new ExpressionExtractionResultBuildItem(true);
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ScriptBuildItem.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ScriptBuildItem.java
index da3c862560..0e3119e0a2 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ScriptBuildItem.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ScriptBuildItem.java
@@ -28,11 +28,13 @@ public final class ScriptBuildItem extends MultiBuildItem {
 
     final String language;
     final String content;
+    final String loadedContent;
     final Map<String, Object> bindings;
 
-    public ScriptBuildItem(String language, String content, Map<String, Object> bindings) {
+    public ScriptBuildItem(String language, String content, String loadedContent, Map<String, Object> bindings) {
         this.language = language;
         this.content = content;
+        this.loadedContent = loadedContent;
         this.bindings = bindings;
     }
 
@@ -44,6 +46,10 @@ public final class ScriptBuildItem extends MultiBuildItem {
         return content;
     }
 
+    public String getLoadedContent() {
+        return loadedContent;
+    }
+
     public Map<String, Object> getBindings() {
         return bindings;
     }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java
index e74a699cc2..f8e0e38e72 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java
@@ -24,21 +24,22 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.Predicate;
-import org.apache.camel.spi.Language;
+import org.apache.camel.support.LanguageSupport;
 
 /**
  * {@code DryModeLanguage} is a mock language meant to collect all the expressions and predicates that are registered
  * for a specific language.
  */
-public class DryModeLanguage implements Language {
+public class DryModeLanguage extends LanguageSupport {
 
     private final String name;
     private final Predicate defaultPredicate = new DryModePredicate();
     private final Expression defaultExpression = new DryModeExpression();
     private final Map<Boolean, Set<ExpressionHolder>> expressions = new ConcurrentHashMap<>();
 
-    public DryModeLanguage(String name) {
+    DryModeLanguage(CamelContext camelContext, String name) {
         this.name = name;
+        this.setCamelContext(camelContext);
     }
 
     public String getName() {
@@ -59,27 +60,29 @@ public class DryModeLanguage implements Language {
 
     @Override
     public Predicate createPredicate(String expression) {
-        expressions.computeIfAbsent(Boolean.TRUE, mode -> ConcurrentHashMap.newKeySet()).add(new ExpressionHolder(expression));
+        expressions.computeIfAbsent(Boolean.TRUE, mode -> ConcurrentHashMap.newKeySet())
+                .add(new ExpressionHolder(expression, loadResource(expression)));
         return defaultPredicate;
     }
 
     @Override
     public Expression createExpression(String expression) {
-        expressions.computeIfAbsent(Boolean.FALSE, mode -> ConcurrentHashMap.newKeySet()).add(new ExpressionHolder(expression));
+        expressions.computeIfAbsent(Boolean.FALSE, mode -> ConcurrentHashMap.newKeySet())
+                .add(new ExpressionHolder(expression, loadResource(expression)));
         return defaultExpression;
     }
 
     @Override
     public Predicate createPredicate(String expression, Object[] properties) {
         expressions.computeIfAbsent(Boolean.TRUE, mode -> ConcurrentHashMap.newKeySet())
-                .add(new ExpressionHolder(expression, properties));
+                .add(new ExpressionHolder(expression, loadResource(expression), properties));
         return defaultPredicate;
     }
 
     @Override
     public Expression createExpression(String expression, Object[] properties) {
         expressions.computeIfAbsent(Boolean.FALSE, mode -> ConcurrentHashMap.newKeySet())
-                .add(new ExpressionHolder(expression, properties));
+                .add(new ExpressionHolder(expression, loadResource(expression), properties));
         return defaultExpression;
     }
 
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
index 1d2e1bfccb..b2443fd91c 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
@@ -38,9 +38,9 @@ class DryModeLanguageResolver extends DefaultLanguageResolver {
     public Language resolveLanguage(String name, CamelContext context) throws NoSuchLanguageException {
         final Language language = super.resolveLanguage(name, context);
         if (language instanceof ScriptingLanguage) {
-            return languages.computeIfAbsent(name, DryModeScriptingLanguage::new);
+            return languages.computeIfAbsent(name, n -> new DryModeScriptingLanguage(context, n));
         }
-        return languages.computeIfAbsent(name, DryModeLanguage::new);
+        return languages.computeIfAbsent(name, n -> new DryModeLanguage(context, n));
     }
 
     Collection<DryModeLanguage> getLanguages() {
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeScriptingLanguage.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeScriptingLanguage.java
index 5f9f938b2a..4c8bfd3b6e 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeScriptingLanguage.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeScriptingLanguage.java
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.camel.CamelContext;
 import org.apache.camel.spi.ScriptingLanguage;
 
 /**
@@ -30,8 +31,8 @@ class DryModeScriptingLanguage extends DryModeLanguage implements ScriptingLangu
 
     private final Set<ScriptHolder> scripts = ConcurrentHashMap.newKeySet();
 
-    public DryModeScriptingLanguage(String name) {
-        super(name);
+    DryModeScriptingLanguage(CamelContext camelContext, String name) {
+        super(camelContext, name);
     }
 
     @Override
@@ -42,7 +43,7 @@ class DryModeScriptingLanguage extends DryModeLanguage implements ScriptingLangu
     @SuppressWarnings("unchecked")
     @Override
     public <T> T evaluate(String script, Map<String, Object> bindings, Class<T> resultType) {
-        scripts.add(new ScriptHolder(script, bindings));
+        scripts.add(new ScriptHolder(script, loadResource(script), bindings));
         // A non-null value must be returned and the returned type is not really important for the dry mode
         return (T) new Object();
     }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ExpressionHolder.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ExpressionHolder.java
index 45c80139eb..7f0b8374a1 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ExpressionHolder.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ExpressionHolder.java
@@ -25,15 +25,17 @@ import java.util.Objects;
 public final class ExpressionHolder {
 
     private final String content;
+    private final String loadedContent;
 
     private final Object[] properties;
 
-    public ExpressionHolder(String content) {
-        this(content, null);
+    public ExpressionHolder(String content, String loadedContent) {
+        this(content, loadedContent, null);
     }
 
-    public ExpressionHolder(String content, Object[] properties) {
+    public ExpressionHolder(String content, String loadedContent, Object[] properties) {
         this.content = content;
+        this.loadedContent = loadedContent;
         this.properties = properties;
     }
 
@@ -41,6 +43,10 @@ public final class ExpressionHolder {
         return content;
     }
 
+    public String getLoadedContent() {
+        return loadedContent;
+    }
+
     public Object[] getProperties() {
         return properties;
     }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ScriptHolder.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ScriptHolder.java
index fb99746d1a..43233d045d 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ScriptHolder.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ScriptHolder.java
@@ -25,11 +25,13 @@ import java.util.Objects;
 public final class ScriptHolder {
 
     private final String content;
+    private final String loadedContent;
 
     private final Map<String, Object> bindings;
 
-    public ScriptHolder(String content, Map<String, Object> bindings) {
+    public ScriptHolder(String content, String loadedContent, Map<String, Object> bindings) {
         this.content = content;
+        this.loadedContent = loadedContent;
         this.bindings = bindings;
     }
 
@@ -37,6 +39,10 @@ public final class ScriptHolder {
         return content;
     }
 
+    public String getLoadedContent() {
+        return loadedContent;
+    }
+
     public Map<String, Object> getBindings() {
         return bindings;
     }