diff --git a/023-quarkus-kamelet/README.md b/023-quarkus-kamelet/README.md new file mode 100644 index 00000000..36497079 --- /dev/null +++ b/023-quarkus-kamelet/README.md @@ -0,0 +1,24 @@ +# Quarkus - Kamelet + +Quarkus-kamelet provide you support to interacting with Camel routes templates. +The aim of this module is to cover the following Kamelet scenarios: +* Camel producers, those scenarios where your service produces events and are consumed by a camel route +* Camel consumers, those scenarios where your service consumes a camel route +* Chain routes multiples routes +* Load application properties as routes bodies +* Validate Kamelet resources as ocp/k8s kamelet yamls(routes-temapltes, routes-bindings...) + +Project folder structure + +* `/resources/kamelets` contains kamelets resources as templates or KameletBindings. Also, there are groovy scripts +in order to instantiate these templates by your self (as an example). + +* `io.quarkus.qe.kamelet.KameletRoutes` contains templates that could be invoked (tested) directly by code. So is not +need it to be deployed into ocp or some other platform. + +### Recommended Readings +[Kamelet introduction](https://camel.apache.org/camel-k/latest/kamelets/kamelets-user.html) + +[Kamelets developer guide](https://camel.apache.org/camel-k/latest/kamelets/kamelets-dev.html) + +[Camel-Quarkus first steps](https://camel.apache.org/camel-quarkus/latest/user-guide/first-steps.html) diff --git a/023-quarkus-kamelet/pom.xml b/023-quarkus-kamelet/pom.xml new file mode 100644 index 00000000..3412ec69 --- /dev/null +++ b/023-quarkus-kamelet/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + io.quarkus.qe + beefy-scenarios + 1.0.0-SNAPSHOT + + 023-quarkus-kamelet + + + org.apache.camel.quarkus + camel-quarkus-kamelet + + + org.apache.camel.quarkus + camel-quarkus-timer + + + org.apache.camel.quarkus + camel-quarkus-direct + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jsonb + + + diff --git a/023-quarkus-kamelet/src/main/java/io/quarkus/qe/kamelet/KameletResource.java b/023-quarkus-kamelet/src/main/java/io/quarkus/qe/kamelet/KameletResource.java new file mode 100644 index 00000000..5c2e3699 --- /dev/null +++ b/023-quarkus-kamelet/src/main/java/io/quarkus/qe/kamelet/KameletResource.java @@ -0,0 +1,51 @@ +package io.quarkus.qe.kamelet; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.apache.camel.ConsumerTemplate; +import org.apache.camel.FluentProducerTemplate; + +@Path("/kamelet") +public class KameletResource { + + @Inject + FluentProducerTemplate fluentProducerTemplate; + + @Inject + ConsumerTemplate consumerTemplate; + + @Path("/produce") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + public String produceToKamelet(String message) { + return fluentProducerTemplate.toF("kamelet:setBody/test?bodyValue=%s", message).request(String.class); + } + + @Path("/timer") + @GET + @Produces(MediaType.TEXT_PLAIN) + public Integer consumeFromKamelet() { + return consumerTemplate.receiveBody("kamelet:tick", 10000, Integer.class); + } + + @Path("/property") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String bodyFromApplicationProperty() { + return fluentProducerTemplate.to("kamelet:setBodyFromProperties").request(String.class); + } + + @Path("/chain") + @POST + @Produces(MediaType.TEXT_PLAIN) + public String kameletChain(String message) { + return fluentProducerTemplate.to("direct:chain").withBody(message).request(String.class); + } +} diff --git a/023-quarkus-kamelet/src/main/java/io/quarkus/qe/kamelet/KameletRoutes.java b/023-quarkus-kamelet/src/main/java/io/quarkus/qe/kamelet/KameletRoutes.java new file mode 100644 index 00000000..b43fed06 --- /dev/null +++ b/023-quarkus-kamelet/src/main/java/io/quarkus/qe/kamelet/KameletRoutes.java @@ -0,0 +1,35 @@ +package io.quarkus.qe.kamelet; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; + +public class KameletRoutes extends RouteBuilder { + + @Override + public void configure() throws Exception { + routeTemplate("setBody") + .templateParameter("bodyValue") + .from("kamelet:source") + .setBody().constant("Hello {{bodyValue}}"); + + routeTemplate("tick") + .from("timer:{{routeId}}?repeatCount=1&delay=-1") + .setBody().exchangeProperty(Exchange.TIMER_COUNTER) + .to("kamelet:sink"); + + routeTemplate("setBodyFromProperties") + .templateParameter("bodyValueFromProperty") + .from("kamelet:source") + .setBody().constant("Hello {{bodyValueFromProperty}}"); + + routeTemplate("echo") + .templateParameter("prefix") + .templateParameter("suffix") + .from("kamelet:source") + .setBody().simple("{{prefix}} ${body} {{suffix}}"); + + from("direct:chain") + .to("kamelet:echo/1?prefix=Camel Quarkus&suffix=Chained") + .to("kamelet:echo/2?prefix=Hello&suffix=Route"); + } +} diff --git a/023-quarkus-kamelet/src/main/resources/application.properties b/023-quarkus-kamelet/src/main/resources/application.properties new file mode 100644 index 00000000..ff0fe0d8 --- /dev/null +++ b/023-quarkus-kamelet/src/main/resources/application.properties @@ -0,0 +1,4 @@ +# kamelet.names, must match with kamelets prefix name, ex: {prefix}.kamelet.yaml +quarkus.camel.kamelet.names = logger, fresh-beer + +camel.kamelet.setBodyFromProperties.bodyValueFromProperty=World from property diff --git a/023-quarkus-kamelet/src/main/resources/kamelets/fresh-beer-integration-example.groovy b/023-quarkus-kamelet/src/main/resources/kamelets/fresh-beer-integration-example.groovy new file mode 100644 index 00000000..cfd332e6 --- /dev/null +++ b/023-quarkus-kamelet/src/main/resources/kamelets/fresh-beer-integration-example.groovy @@ -0,0 +1,3 @@ +package kamelets + +from('kamelet:beer-source').log('${body}') diff --git a/023-quarkus-kamelet/src/main/resources/kamelets/fresh-beer.Kamelet.yaml b/023-quarkus-kamelet/src/main/resources/kamelets/fresh-beer.Kamelet.yaml new file mode 100644 index 00000000..1a1e90e3 --- /dev/null +++ b/023-quarkus-kamelet/src/main/resources/kamelets/fresh-beer.Kamelet.yaml @@ -0,0 +1,27 @@ +apiVersion: camel.apache.org/v1alpha1 +kind: Kamelet +metadata: + name: beer-source + labels: + camel.apache.org/kamelet.type: "source" +spec: + definition: + title: "Beer Source" + description: "Retrieve a random beer from catalog" + properties: + period: + title: Period + description: The interval between two events + type: integer + default: 1000 + types: + out: + mediaType: application/json + flow: + from: + uri: timer:tick + parameters: + period: "#property:period" + steps: + - to: "https://random-data-api.com/api/beer/random_beer" + - to: "kamelet:sink" \ No newline at end of file diff --git a/023-quarkus-kamelet/src/main/resources/kamelets/logger.kamelet.yaml b/023-quarkus-kamelet/src/main/resources/kamelets/logger.kamelet.yaml new file mode 100644 index 00000000..bc06b7c6 --- /dev/null +++ b/023-quarkus-kamelet/src/main/resources/kamelets/logger.kamelet.yaml @@ -0,0 +1,39 @@ +apiVersion: camel.apache.org/v1alpha1 +kind: Kamelet +metadata: + labels: + camel.apache.org/kamelet.type: "sink" + camel.apache.org/kamelet.name: "log" + camel.apache.org/kamelet.version: "v1alpha1" +spec: + definition: + title: "Logger" + description: "Logger" + properties: + loggerName: + title: Name of the logging category + description: Name of the logging category + type: string + default: "logger" + showAll: + title: Show All + description: Show All + type: boolean + default: false + multiLine: + title: Multi Line + description: Multi Line + type: boolean + default: false + dependencies: + - "camel:log" + flow: + from: + uri: "kamelet:source" + steps: + - to: + uri: "log" + properties: + loggerName: "{{loggerName}}" + showAll: "{{showAll}}" + multiline: "{{multiLine}}" diff --git a/023-quarkus-kamelet/src/test/java/io/quarkus/qe/kamelet/KameletIT.java b/023-quarkus-kamelet/src/test/java/io/quarkus/qe/kamelet/KameletIT.java new file mode 100644 index 00000000..7e090a1d --- /dev/null +++ b/023-quarkus-kamelet/src/test/java/io/quarkus/qe/kamelet/KameletIT.java @@ -0,0 +1,8 @@ +package io.quarkus.qe.kamelet; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +class KameletIT extends KameletTest { + +} diff --git a/023-quarkus-kamelet/src/test/java/io/quarkus/qe/kamelet/KameletTest.java b/023-quarkus-kamelet/src/test/java/io/quarkus/qe/kamelet/KameletTest.java new file mode 100644 index 00000000..3b944125 --- /dev/null +++ b/023-quarkus-kamelet/src/test/java/io/quarkus/qe/kamelet/KameletTest.java @@ -0,0 +1,52 @@ +package io.quarkus.qe.kamelet; + +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; + +@QuarkusTest +class KameletTest { + @Test + public void testKameletProducerHelloWorld() { + String message = "World"; + + RestAssured.given() + .contentType(ContentType.TEXT) + .body(message) + .post("/kamelet/produce") + .then() + .statusCode(200) + .body(is("Hello " + message)); + } + + @Test + public void testKameletTimerConsumer() { + RestAssured.get("/kamelet/timer") + .then() + .statusCode(200) + .body(is("1")); + } + + @Test + public void testKameletWithProperties() { + RestAssured.get("/kamelet/property") + .then() + .statusCode(200) + .body(is("Hello World from property")); + } + + @Test + public void testKameletChain() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Kamelet") + .post("/kamelet/chain") + .then() + .statusCode(200) + .body(is("Hello Camel Quarkus Kamelet Chained Route")); + } +} diff --git a/pom.xml b/pom.xml index 99f8356c..b61a9d4a 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ 020-quarkus-http-non-application-endpoints 021-quarkus-panache-multiple-pus 022-quarkus-properties-config-all + 023-quarkus-kamelet 101-javaee-like-getting-started 201-large-static-content 300-quarkus-vertx-webClient @@ -49,6 +50,7 @@ 1.3.2.Final 6.0.0 0.0.2 + 1.8.1 2.15.0 1.6.0 3.1.2 @@ -105,6 +107,21 @@ quarkiverse-apicurio-registry-client ${version.quarkiverse.apicurio.registry.client} + + org.apache.camel.quarkus + camel-quarkus-kamelet + ${version.quarkus.camel} + + + org.apache.camel.quarkus + camel-quarkus-timer + ${version.quarkus.camel} + + + org.apache.camel.quarkus + camel-quarkus-direct + ${version.quarkus.camel} +