Fix build time processing of Kamelets with bean definitions
Fixes #6581
diff --git a/extensions/kamelet/deployment/src/main/java/org/apache/camel/quarkus/component/kamelet/deployment/KameletProcessor.java b/extensions/kamelet/deployment/src/main/java/org/apache/camel/quarkus/component/kamelet/deployment/KameletProcessor.java
index 1bd217b..8588bdb 100644
--- a/extensions/kamelet/deployment/src/main/java/org/apache/camel/quarkus/component/kamelet/deployment/KameletProcessor.java
+++ b/extensions/kamelet/deployment/src/main/java/org/apache/camel/quarkus/component/kamelet/deployment/KameletProcessor.java
@@ -20,14 +20,17 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
import java.util.Optional;
+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.nativeimage.ReflectiveClassBuildItem;
import org.apache.camel.CamelContext;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.Ordered;
@@ -89,6 +92,7 @@
@BuildStep
CamelContextCustomizerBuildItem configureTemplates(
List<KameletResourceBuildItem> resources,
+ BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
KameletRecorder recorder) throws Exception {
List<RouteTemplateDefinition> definitions = new ArrayList<>();
@@ -97,9 +101,13 @@
ExtendedCamelContext ecc = context.getCamelContextExtension();
for (KameletResourceBuildItem item : resources) {
- LOGGER.debugf("Loading kamelet from: %s)", item.getResource());
+ Resource resource = item.getResource();
+ if (!resource.exists()) {
+ throw new IllegalStateException("Unable to load kamelet from: " + resource.getLocation());
+ }
- Collection<RoutesBuilder> rbs = PluginHelper.getRoutesLoader(ecc).findRoutesBuilders(item.getResource());
+ LOGGER.debugf("Loading kamelet from: %s", resource);
+ Collection<RoutesBuilder> rbs = PluginHelper.getRoutesLoader(ecc).findRoutesBuilders(resource);
for (RoutesBuilder rb : rbs) {
RouteBuilder routeBuilder = (RouteBuilder) rb;
routeBuilder.configure();
@@ -135,6 +143,24 @@
if (definition.getRoute() != null && definition.getRoute().getOutputs() != null) {
definition.getRoute().getOutputs().forEach(o -> o.setCamelContext(null));
}
+
+ if (definition.getTemplateBeans() != null) {
+ Set<String> beanClassNames = new HashSet<>();
+ definition.getTemplateBeans().forEach(bean -> {
+ bean.setResource(resource);
+
+ String beanType = bean.getType();
+ if (beanType != null && beanType.startsWith("#class:")) {
+ String className = beanType.substring("#class:".length());
+ beanClassNames.add(className);
+ }
+ });
+
+ reflectiveClass.produce(ReflectiveClassBuildItem.builder(beanClassNames.toArray(new String[0]))
+ .fields()
+ .methods()
+ .build());
+ }
});
return new CamelContextCustomizerBuildItem(
diff --git a/extensions/kamelet/runtime/src/main/java/org/apache/camel/quarkus/component/kamelet/KameletRecorder.java b/extensions/kamelet/runtime/src/main/java/org/apache/camel/quarkus/component/kamelet/KameletRecorder.java
index b431298..2763ca5 100644
--- a/extensions/kamelet/runtime/src/main/java/org/apache/camel/quarkus/component/kamelet/KameletRecorder.java
+++ b/extensions/kamelet/runtime/src/main/java/org/apache/camel/quarkus/component/kamelet/KameletRecorder.java
@@ -63,6 +63,13 @@
if (definition.getRoute() != null && definition.getRoute().getOutputs() != null) {
definition.getRoute().getOutputs().forEach(o -> o.setCamelContext(context));
}
+
+ if (definition.getTemplateBeans() != null) {
+ definition.getTemplateBeans()
+ .stream()
+ .filter(bean -> bean.getResource() instanceof EmptyKameletResource)
+ .forEach(bean -> bean.setResource(resourceLoader.resolveResource(location)));
+ }
}
context.getCamelContextExtension().getContextPlugin(Model.class).addRouteTemplateDefinitions(definitions);
} catch (Exception e) {
diff --git a/integration-tests/kamelet/pom.xml b/integration-tests/kamelet/pom.xml
index 1f3d77f..ad46dee 100644
--- a/integration-tests/kamelet/pom.xml
+++ b/integration-tests/kamelet/pom.xml
@@ -52,6 +52,10 @@
<artifactId>camel-quarkus-xml-io-dsl</artifactId>
</dependency>
<dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-seda</artifactId>
+ </dependency>
+ <dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
@@ -169,6 +173,19 @@
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-seda-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-timer-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
diff --git a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletBean.java b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletBean.java
new file mode 100644
index 0000000..475c1a3
--- /dev/null
+++ b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletBean.java
@@ -0,0 +1,29 @@
+/*
+ * 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.kamelet.it;
+
+public class KameletBean {
+ private final String greeting;
+
+ public KameletBean(String greeting) {
+ this.greeting = greeting;
+ }
+
+ public String getGreeting() {
+ return greeting;
+ }
+}
diff --git a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java
index 37a73e5..f9bb2f9 100644
--- a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java
+++ b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletResource.java
@@ -103,4 +103,10 @@
return fluentProducerTemplate.to("direct:kamelet-location-at-runtime").withBody(name).request(String.class);
}
+ @Path("/greeting")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String greeting() {
+ return consumerTemplate.receiveBody("seda:greeting", 10000, String.class);
+ }
}
diff --git a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java
index e8b812e..afb8520 100644
--- a/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java
+++ b/integration-tests/kamelet/src/main/java/org/apache/camel/quarkus/component/kamelet/it/KameletRoutes.java
@@ -64,6 +64,9 @@
from("direct:kamelet-location-at-runtime")
.kamelet("upper?location=classpath:kamelets-runtime/upper-kamelet.xml");
+
+ from("kamelet:greeting")
+ .to("seda:greeting");
}
@RegisterForReflection
diff --git a/integration-tests/kamelet/src/main/resources/application.properties b/integration-tests/kamelet/src/main/resources/application.properties
index cff0cd1..0b6ffc8 100644
--- a/integration-tests/kamelet/src/main/resources/application.properties
+++ b/integration-tests/kamelet/src/main/resources/application.properties
@@ -16,7 +16,7 @@
## ---------------------------------------------------------------------------
camel.kamelet.setBodyFromProperties.bodyValueFromProperty=Camel Quarkus Kamelet Property
-quarkus.camel.kamelet.identifiers = injector,logger
+quarkus.camel.kamelet.identifiers = injector,logger,greeting
# this is needed to actually test that kamelet are preloaded at build time:
camel.component.kamelet.location = file:/invalid
diff --git a/integration-tests/kamelet/src/main/resources/kamelets/greeting.kamelet.yaml b/integration-tests/kamelet/src/main/resources/kamelets/greeting.kamelet.yaml
new file mode 100644
index 0000000..aff771f
--- /dev/null
+++ b/integration-tests/kamelet/src/main/resources/kamelets/greeting.kamelet.yaml
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: greeting
+ labels:
+ camel.apache.org/kamelet.type: "source"
+ camel.apache.org/kamelet.name: "greeting"
+ camel.apache.org/kamelet.version: "v1"
+ camel.apache.org/kamelet.revision: "1"
+spec:
+ definition:
+ title: "Greeting"
+ description: "Print a greeting"
+ dependencies:
+ - "camel:timer"
+ template:
+ beans:
+ - name: greetingBean
+ type: "#class:org.apache.camel.quarkus.component.kamelet.it.KameletBean"
+ constructors:
+ 0: "Hello World"
+ from:
+ uri: timer:greet?repeatCount=1&delay=-1
+ steps:
+ - to: "bean:{{greetingBean}}?method=getGreeting"
diff --git a/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java b/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java
index 5aafba9..e95c0ef 100644
--- a/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java
+++ b/integration-tests/kamelet/src/test/java/org/apache/camel/quarkus/component/kamelet/it/KameletTest.java
@@ -93,7 +93,8 @@
public void testDiscovered() {
Response resp = RestAssured.given()
.contentType(ContentType.JSON)
- .when().get("/kamelet/list");
+ .when()
+ .get("/kamelet/list");
resp.then().statusCode(200);
ArrayList<String> jsonAsArrayList = resp.body()
@@ -102,6 +103,7 @@
assertTrue(jsonAsArrayList.contains("injector"));
assertTrue(jsonAsArrayList.contains("logger"));
assertTrue(jsonAsArrayList.contains("custom-log"));
+ assertTrue(jsonAsArrayList.contains("greeting"));
}
@Test
@@ -112,4 +114,12 @@
.statusCode(200)
.body(is("HELLO"));
}
+
+ @Test
+ public void testKameletWithBean() {
+ RestAssured.get("/kamelet/greeting")
+ .then()
+ .statusCode(200)
+ .body(is("Hello World"));
+ }
}