Skip to content

Commit

Permalink
Fix build time processing of Kamelets with bean definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesnetherton committed Oct 3, 2024
1 parent 321dfd6 commit dffd69a
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -89,6 +92,7 @@ void loadResources(
@BuildStep
CamelContextCustomizerBuildItem configureTemplates(
List<KameletResourceBuildItem> resources,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
KameletRecorder recorder) throws Exception {

List<RouteTemplateDefinition> definitions = new ArrayList<>();
Expand All @@ -97,9 +101,13 @@ CamelContextCustomizerBuildItem configureTemplates(
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();
Expand Down Expand Up @@ -135,6 +143,24 @@ CamelContextCustomizerBuildItem configureTemplates(
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ public void configure(CamelContext context) {
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() != null)
.filter(bean -> bean.getResource() instanceof EmptyKameletResource)
.forEach(bean -> bean.setResource(resourceLoader.resolveResource(location)));
}
}
context.getCamelContextExtension().getContextPlugin(Model.class).addRouteTemplateDefinitions(definitions);
} catch (Exception e) {
Expand Down
17 changes: 17 additions & 0 deletions integration-tests/kamelet/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
<groupId>org.apache.camel.quarkus</groupId>
<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>
Expand Down Expand Up @@ -167,6 +171,19 @@
</exclusion>
</exclusions>
</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>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,10 @@ public String kameletLocationAtRuntime(@PathParam("name") String name) {
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public void configure() throws Exception {

from("direct:kamelet-location-at-runtime")
.kamelet("upper?location=classpath:kamelets-runtime/upper-kamelet.xml");

from("kamelet:greeting")
.to("seda:greeting");
}

@RegisterForReflection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ public void testInvoke() {
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()
Expand All @@ -102,6 +103,7 @@ public void testDiscovered() {
assertTrue(jsonAsArrayList.contains("injector"));
assertTrue(jsonAsArrayList.contains("logger"));
assertTrue(jsonAsArrayList.contains("custom-log"));
assertTrue(jsonAsArrayList.contains("greeting"));
}

@Test
Expand All @@ -112,4 +114,12 @@ public void testKameletLocationAtRuntime() {
.statusCode(200)
.body(is("HELLO"));
}

@Test
public void testKameletWithBean() {
RestAssured.get("/kamelet/greeting")
.then()
.statusCode(200)
.body(is("Hello World"));
}
}

0 comments on commit dffd69a

Please sign in to comment.