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

nfilotto pushed a commit to branch 4384/add-support-of-groovy-extensions
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit e35a97f47574b4b8b45b5a2cf1ca398aa8410f5b
Author: Nicolas Filotto <nfilo...@talend.com>
AuthorDate: Wed Mar 8 10:28:33 2023 +0100

    Ref #4384: Groovy DSL - Add support of Groovy extensions
---
 .../pages/reference/extensions/groovy-dsl.adoc     |   6 -
 .../dsl/groovy/deployment/GroovyDslProcessor.java  |  64 +++++++++-
 .../runtime/src/main/doc/limitations.adoc          |   1 -
 integration-tests/groovy-dsl/pom.xml               |   5 -
 .../main/resources/routes/routes-with-eip.groovy   |  36 ++++++
 .../camel/quarkus/dsl/groovy/GroovyDslTest.java    | 142 ++++++++++++++-------
 6 files changed, 191 insertions(+), 63 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/extensions/groovy-dsl.adoc 
b/docs/modules/ROOT/pages/reference/extensions/groovy-dsl.adoc
index f9c62daa0d..1926f73527 100644
--- a/docs/modules/ROOT/pages/reference/extensions/groovy-dsl.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/groovy-dsl.adoc
@@ -43,9 +43,3 @@ Or add the coordinates to your existing project:
 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-dsl-camel-quarkus-limitations"]
-== Camel Quarkus limitations
-
-The Groovy extensions are not supported which means that the extensions 
defined in the Camel project are ignored, more details in 
https://github.com/apache/camel-quarkus/issues/4384[Groovy DSL - Add support of 
Groovy extensions issue #4384].
-
diff --git 
a/extensions/groovy-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/groovy/deployment/GroovyDslProcessor.java
 
b/extensions/groovy-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/groovy/deployment/GroovyDslProcessor.java
index 5f23bb77c0..c7f114f6a8 100644
--- 
a/extensions/groovy-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/groovy/deployment/GroovyDslProcessor.java
+++ 
b/extensions/groovy-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/groovy/deployment/GroovyDslProcessor.java
@@ -19,14 +19,19 @@ package org.apache.camel.quarkus.dsl.groovy.deployment;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 import io.quarkus.deployment.annotations.BuildProducer;
 import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
 import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
@@ -34,6 +39,10 @@ import 
io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
 import io.quarkus.deployment.pkg.steps.NativeBuild;
 import io.quarkus.maven.dependency.ResolvedDependency;
 import io.quarkus.paths.PathCollection;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Message;
 import org.apache.camel.quarkus.core.deployment.main.CamelMainHelper;
 import org.apache.camel.quarkus.dsl.groovy.runtime.Configurer;
 import 
org.apache.camel.quarkus.support.dsl.deployment.DslGeneratedClassBuildItem;
@@ -44,6 +53,9 @@ 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.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,6 +65,11 @@ import static 
org.apache.camel.quarkus.support.dsl.deployment.DslSupportProcesso
 public class GroovyDslProcessor {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(GroovyDslProcessor.class);
+    private static final List<Class<?>> CAMEL_REFLECTIVE_CLASSES = 
Arrays.asList(
+            Exchange.class,
+            Message.class,
+            ExchangePattern.class,
+            CamelContext.class);
     private static final String PACKAGE_NAME = 
"org.apache.camel.quarkus.dsl.groovy.generated";
     private static final String FILE_FORMAT = """
             package %s
@@ -117,12 +134,47 @@ public class GroovyDslProcessor {
         }
     }
 
-    // To put it back once the Groovy extensions will be supported 
(https://github.com/apache/camel-quarkus/issues/4384)
-    //    @BuildStep
-    //    void 
registerNativeImageResources(BuildProducer<ServiceProviderBuildItem> 
serviceProvider) {
-    //        serviceProvider
-    //                
.produce(ServiceProviderBuildItem.allProvidersFromClassPath("org.codehaus.groovy.runtime.ExtensionModule"));
-    //    }
+    @BuildStep(onlyIf = NativeBuild.class)
+    void registerReflectiveClasses(
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            CombinedIndexBuildItem combinedIndexBuildItem) {
+
+        IndexView view = combinedIndexBuildItem.getIndex();
+
+        for (Class<?> type : CAMEL_REFLECTIVE_CLASSES) {
+            DotName name = DotName.createSimple(type.getName());
+
+            if (type.isInterface()) {
+                for (ClassInfo info : view.getAllKnownImplementors(name)) {
+                    reflectiveClass.produce(new ReflectiveClassBuildItem(true, 
false, info.name().toString()));
+                }
+            } else {
+                for (ClassInfo info : view.getAllKnownSubclasses(name)) {
+                    reflectiveClass.produce(new ReflectiveClassBuildItem(true, 
false, info.name().toString()));
+                }
+            }
+
+            reflectiveClass.produce(new ReflectiveClassBuildItem(true, 
type.isEnum(), type));
+        }
+
+        Set<Class<?>> types = new HashSet<>();
+        // Register all the Camel return types of public methods of the camel 
reflective classes for reflection to
+        // be accessible in native mode from a Groovy resource
+        for (Class<?> c : CAMEL_REFLECTIVE_CLASSES) {
+            for (Method method : c.getMethods()) {
+                if (!method.getDeclaringClass().equals(Object.class)) {
+                    Class<?> returnType = method.getReturnType();
+                    if 
(returnType.getPackageName().startsWith("org.apache.camel.")
+                            && !CAMEL_REFLECTIVE_CLASSES.contains(returnType)) 
{
+                        types.add(returnType);
+                    }
+                }
+            }
+        }
+        // Allow access to methods by reflection to be accessible in native 
mode from a Groovy resource
+        reflectiveClass.produce(new ReflectiveClassBuildItem(false, true, 
false, types.toArray(new Class<?>[0])));
+
+    }
 
     /**
      * Convert a Groovy script into a Groovy class to be able to compile it.
diff --git a/extensions/groovy-dsl/runtime/src/main/doc/limitations.adoc 
b/extensions/groovy-dsl/runtime/src/main/doc/limitations.adoc
deleted file mode 100644
index a77743a491..0000000000
--- a/extensions/groovy-dsl/runtime/src/main/doc/limitations.adoc
+++ /dev/null
@@ -1 +0,0 @@
-The Groovy extensions are not supported which means that the extensions 
defined in the Camel project are ignored, more details in 
https://github.com/apache/camel-quarkus/issues/4384[Groovy DSL - Add support of 
Groovy extensions issue #4384].
diff --git a/integration-tests/groovy-dsl/pom.xml 
b/integration-tests/groovy-dsl/pom.xml
index 07f11a865a..2b35814bb7 100644
--- a/integration-tests/groovy-dsl/pom.xml
+++ b/integration-tests/groovy-dsl/pom.xml
@@ -66,11 +66,6 @@
             <artifactId>quarkus-junit5</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>io.rest-assured</groupId>
-            <artifactId>rest-assured</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
diff --git 
a/integration-tests/groovy-dsl/src/main/resources/routes/routes-with-eip.groovy 
b/integration-tests/groovy-dsl/src/main/resources/routes/routes-with-eip.groovy
new file mode 100644
index 0000000000..8d21881910
--- /dev/null
+++ 
b/integration-tests/groovy-dsl/src/main/resources/routes/routes-with-eip.groovy
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+from('direct:routes-with-eip-setBody')
+    .id('routes-with-eip-setBody')
+    .setBody { "true" }
+
+from('direct:routes-with-eip-body')
+    .id('routes-with-eip-body')
+    .transform().body { b -> "true"}
+
+from('direct:routes-with-eip-message')
+        .id('routes-with-eip-message')
+        .transform().message { m -> m.body = "true"}
+
+from('direct:routes-with-eip-exchange')
+        .id('routes-with-eip-exchange')
+        .transform().exchange { e -> e.in.body = "true"}
+
+from('direct:routes-with-eip-process')
+        .id('routes-with-eip-process')
+        .process {e -> e.in.body = "true" }
diff --git 
a/integration-tests/groovy-dsl/src/test/java/org/apache/camel/quarkus/dsl/groovy/GroovyDslTest.java
 
b/integration-tests/groovy-dsl/src/test/java/org/apache/camel/quarkus/dsl/groovy/GroovyDslTest.java
index fdc6a4faf4..b0a0b6ae6a 100644
--- 
a/integration-tests/groovy-dsl/src/test/java/org/apache/camel/quarkus/dsl/groovy/GroovyDslTest.java
+++ 
b/integration-tests/groovy-dsl/src/test/java/org/apache/camel/quarkus/dsl/groovy/GroovyDslTest.java
@@ -16,64 +16,116 @@
  */
 package org.apache.camel.quarkus.dsl.groovy;
 
+import java.net.URL;
+
+import io.quarkus.test.common.http.TestHTTPResource;
 import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
 import org.apache.camel.dsl.groovy.GroovyRoutesBuilderLoader;
-import org.hamcrest.CoreMatchers;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
 import org.junit.jupiter.api.Test;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 @QuarkusTest
 class GroovyDslTest {
 
+    @TestHTTPResource
+    URL url;
+
     @Test
-    void groovyHello() {
-        RestAssured.given()
-                .body("John Smith")
-                .post("/groovy-dsl/hello")
-                .then()
-                .statusCode(200)
-                .body(CoreMatchers.is("Hello John Smith from Groovy!"));
+    void groovyHello() throws Exception {
+        try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
+            // Given
+            HttpPost httpPost = new HttpPost(this.url.toExternalForm() + 
"/groovy-dsl/hello");
+            httpPost.setEntity(new StringEntity("John Smith", 
ContentType.TEXT_PLAIN));
+
+            // When
+            HttpResponse httpResponse = client.execute(httpPost);
+
+            // Then
+            
assertThat(httpResponse.getStatusLine().getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+            
assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("Hello 
John Smith from Groovy!");
+        }
     }
 
     @Test
-    void testMainInstanceWithJavaRoutes() {
-        RestAssured.given()
-                .get("/groovy-dsl/main/groovyRoutesBuilderLoader")
-                .then()
-                .statusCode(200)
-                
.body(CoreMatchers.is(GroovyRoutesBuilderLoader.class.getName()));
-
-        RestAssured.given()
-                .get("/groovy-dsl/main/routeBuilders")
-                .then()
-                .statusCode(200)
-                .body(CoreMatchers.is(""));
-
-        RestAssured.given()
-                .get("/groovy-dsl/main/routes")
-                .then()
-                .statusCode(200)
-                .body(CoreMatchers.is(
-                        
"my-groovy-route,routes-with-components-configuration,routes-with-dataformats-configuration,routes-with-endpoint-dsl,routes-with-error-handler,routes-with-languages-configuration,routes-with-rest,routes-with-rest-dsl-get,routes-with-rest-dsl-post,routes-with-rest-get,routes-with-rest-post"));
-        RestAssured.given()
-                .get("/groovy-dsl/main/successful/routes")
-                .then()
-                .statusCode(200)
-                .body(CoreMatchers.is("5"));
+    void testMainInstanceWithJavaRoutes() throws Exception {
+        try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
+            // Given
+            HttpUriRequest request = new HttpGet(this.url.toExternalForm() + 
"/groovy-dsl/main/groovyRoutesBuilderLoader");
+
+            // When
+            HttpResponse httpResponse = client.execute(request);
+
+            // Then
+            
assertThat(httpResponse.getStatusLine().getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+            
assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo(GroovyRoutesBuilderLoader.class.getName());
+
+            // Given
+            request = new HttpGet(this.url.toExternalForm() + 
"/groovy-dsl/main/routeBuilders");
+
+            // When
+            httpResponse = client.execute(request);
+
+            // Then
+            
assertThat(httpResponse.getStatusLine().getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+            
assertThat(EntityUtils.toString(httpResponse.getEntity())).isEmpty();
+
+            // Given
+            request = new HttpGet(this.url.toExternalForm() + 
"/groovy-dsl/main/routes");
+
+            // When
+            httpResponse = client.execute(request);
+
+            // Then
+            
assertThat(httpResponse.getStatusLine().getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+            
assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo(
+                    
"my-groovy-route,routes-with-components-configuration,routes-with-dataformats-configuration,routes-with-eip-body,routes-with-eip-exchange,routes-with-eip-message,routes-with-eip-process,routes-with-eip-setBody,routes-with-endpoint-dsl,routes-with-error-handler,routes-with-languages-configuration,routes-with-rest,routes-with-rest-dsl-get,routes-with-rest-dsl-post,routes-with-rest-get,routes-with-rest-post");
+
+            // Given
+            request = new HttpGet(this.url.toExternalForm() + 
"/groovy-dsl/main/successful/routes");
+
+            // When
+            httpResponse = client.execute(request);
+
+            // Then
+            
assertThat(httpResponse.getStatusLine().getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+            
assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("10");
+        }
     }
 
     @Test
-    void testRestEndpoints() {
-        RestAssured.given()
-                .get("/root/my/path/get")
-                .then()
-                .statusCode(200)
-                .body(CoreMatchers.is("Hello World"));
-        RestAssured.given()
-                .body("Will")
-                .post("/root/post")
-                .then()
-                .statusCode(200)
-                .body(CoreMatchers.is("Hello Will"));
+    void testRestEndpoints() throws Exception {
+        try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
+            // Given
+            final HttpGet httpGet = new HttpGet(this.url.toExternalForm() + 
"/root/my/path/get");
+
+            // When
+            HttpResponse httpResponse = client.execute(httpGet);
+
+            // Then
+            
assertThat(httpResponse.getStatusLine().getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+            
assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("Hello 
World");
+
+            // Given
+            HttpPost httpPost = new HttpPost(this.url.toExternalForm() + 
"/root/post");
+            httpPost.setEntity(new StringEntity("Will", 
ContentType.TEXT_PLAIN));
+
+            // When
+            httpResponse = client.execute(httpPost);
+
+            // Then
+            
assertThat(httpResponse.getStatusLine().getStatusCode()).isEqualTo(HttpStatus.SC_OK);
+            
assertThat(EntityUtils.toString(httpResponse.getEntity())).isEqualTo("Hello 
Will");
+        }
     }
 }

Reply via email to