This is an automated email from the ASF dual-hosted git repository. ppalaga pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel-website.git
The following commit(s) were added to refs/heads/master by this push: new 047264f Blog post: Command line utility with Camel Quarkus 047264f is described below commit 047264fa3804481f2f7315d3f19e5b86da937b35 Author: Peter Palaga <ppal...@redhat.com> AuthorDate: Wed Jul 15 12:35:13 2020 +0200 Blog post: Command line utility with Camel Quarkus --- .../index.md | 226 +++++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/content/blog/2020/07/command-line-utility-with-camel-quarkus/index.md b/content/blog/2020/07/command-line-utility-with-camel-quarkus/index.md new file mode 100644 index 0000000..02ee73e --- /dev/null +++ b/content/blog/2020/07/command-line-utility-with-camel-quarkus/index.md @@ -0,0 +1,226 @@ +--- +title: "Command line utility with Camel Quarkus" +date: 2020-07-15 +authors: ["ppalaga"] +categories: ["Howtos", "Camel Quarkus"] +preview: How to write a command line utility with Camel Quarkus +--- + +[Camel](https://camel.apache.org/) and [Camel Quarkus](https://camel.apache.org/camel-quarkus/latest/index.html) are +typically used to create integration applications that run as long living processes, a.k.a. daemons or services. +In this blog post, we are going to explain a slightly different use case: using Camel Quarkus in programs that exit by +themselves after performing some desired tasks. + +## Where can this be useful? + +The enterprise is full of scheduled batch processing. Say, some system exports some sort of reports daily at 4 a.m. +Those need to be transformed (e.g. XML -> Excel) and transferred somewhere else (e.g. via mail, FTP or similar). + +Camel is a perfect match for doing the transformation and the transfer. However, having a service running 24/7 for +doing something useful just once a day would probably be an overkill. Combining a +[Cron job](https://en.wikipedia.org/wiki/Cron) (or a similar scheduling technology) with a command line utility may suit +much better in situations like this. + +## So how can I write a command line tool with Camel Quarkus? + +There are just two things where it would differ from a stock Camel Quarkus application: + +1. Adding `camel-quarkus-main` dependency +2. Setting an exit condition in `application.properties` + +The rest of the application - most notably the [Route](https://camel.apache.org/manual/latest/routes.html) that +performs the actual data transformation and transfer - will look the same like with a traditional Camel service. + + +## A minimal Hello World! + +Let's go through a minimal example that just prints `Hello World!` to the console and exits. + +The route definition could look like the following: + +```java +import org.apache.camel.builder.RouteBuilder; + +@ApplicationScoped +public class CamelRoute extends RouteBuilder { + + @Override + public void configure() { + from("timer:hello?delay=-1&repeatCount=1") + .setBody().constant("Hello World!") + .to("log:hello"); + } +} +``` + +Note that we use the [timer](https://camel.apache.org/components/latest/timer-component.html) component to trigger the +route execution. The URI parameter `delay=-1` causes the timer to be triggered with no initial delay and +`repeatCount=1` ensures that the route is executed just once. + +However, doing just the above would not make our application exit by itself. +[camel-main](https://camel.apache.org/components/latest/others/main.html) and its `camel.main.durationMax*` +family of configuration options offers a way to solve that. E.g. we can set the following in +`application.properties` + +```properties +camel.main.durationMaxMessages = 1 +``` + +to make the application exit after the route has processed a single message. + +For the configuration to get effective, we need to add the respective dependency to the application. In case of Maven, +it is + +```xml +<dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-main</artifactId> +</dependency> +``` + +Of course, we also need to add the dependencies for `timer` and `log` components: + +```xml +<dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-log</artifactId> +</dependency> +<dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-timer</artifactId> +</dependency> +``` + +When invoking the application on the command line, you should see something like the following: + +```shell +]$ java -jar target/*-runner.jar +2020-07-15 11:32:13,577 INFO [org.apa.cam.qua.cor.CamelBootstrapRecorder] (main) bootstrap runtime: org.apache.camel.quarkus.main.CamelMainRuntime +2020-07-15 11:32:13,623 INFO [org.apa.cam.mai.BaseMainSupport] (main) Auto-configuration summary: +2020-07-15 11:32:13,623 INFO [org.apa.cam.mai.BaseMainSupport] (main) camel.main.durationMaxMessages=1 +2020-07-15 11:32:13,700 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel 3.4.0 (camel-1) is starting +2020-07-15 11:32:13,701 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html +2020-07-15 11:32:13,709 INFO [org.apa.cam.imp.eng.InternalRouteStartupManager] (main) Route: route1 started and consuming from: timer://hello +2020-07-15 11:32:13,714 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Total 1 routes, of which 1 are started +2020-07-15 11:32:13,715 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel 3.4.0 (camel-1) started in 0.014 seconds +2020-07-15 11:32:13,718 INFO [org.apa.cam.mai.MainSupport] (camel-main) Waiting until: 1 messages has been processed +2020-07-15 11:32:13,719 INFO [io.quarkus] (main) camel-quarkus-integration-test-main-command-mode 1.1.0-SNAPSHOT on JVM (powered by Quarkus 1.6.0.Final) started in 0.592s. +2020-07-15 11:32:13,720 INFO [io.quarkus] (main) Profile prod activated. +2020-07-15 11:32:13,721 INFO [io.quarkus] (main) Installed features: [camel-core, camel-log, camel-main, camel-policy, camel-support-common, camel-timer, cdi] +2020-07-15 11:32:13,725 INFO [hello] (Camel (camel-1) thread #0 - timer://hello) Exchange[ExchangePattern: InOnly, BodyType: String, Body: Hello World!] +2020-07-15 11:32:13,729 INFO [org.apa.cam.mai.MainLifecycleStrategy] (Camel (camel-1) thread #0 - timer://hello) Duration max messages triggering shutdown of the JVM. +2020-07-15 11:32:13,730 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) is shutting down +2020-07-15 11:32:13,740 INFO [org.apa.cam.mai.MainLifecycleStrategy] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) CamelContext: camel-1 has been shutdown, triggering shutdown of the JVM. +2020-07-15 11:32:13,741 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) uptime 0.041 seconds +2020-07-15 11:32:13,741 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) is shutdown in 0.011 seconds +2020-07-15 11:32:13,745 INFO [io.quarkus] (main) camel-quarkus-integration-test-main-command-mode stopped in 0.005s +``` + + +## Command line parameters + +That was really trivial. How about greeting a person whose name is passed via a command line parameter? We can use +[Quarkus MicroProfile Config](https://quarkus.io/guides/config) for that: + +```java +import javax.enterprise.context.ApplicationScoped; +import org.apache.camel.builder.RouteBuilder; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +@ApplicationScoped +public class CamelRoute extends RouteBuilder { + + @ConfigProperty(name = "greeted.subject", defaultValue = "World") + String greetedSubject; + + @Override + public void configure() { + from("timer:hello?delay=-1") + .setBody().constant("Hello " + greetedSubject + "!") + .to("log:hello"); + } +} +``` + +For the `@ConfigProperty` annotation to work, the `CamelRoute` class needs to be annotated with +`@ApplicationScoped`. + +Having the above in place, we can call the application with the `-Dgreeted.subject=Joe` parameter at the command +line and voilĂ + +```shell +$ $ java -Dgreeted.subject=Joe -jar target/*-runner.jar +2020-07-15 11:42:18,770 INFO [org.apa.cam.qua.cor.CamelBootstrapRecorder] (main) bootstrap runtime: org.apache.camel.quarkus.main.CamelMainRuntime +2020-07-15 11:42:18,816 INFO [org.apa.cam.mai.BaseMainSupport] (main) Auto-configuration summary: +2020-07-15 11:42:18,816 INFO [org.apa.cam.mai.BaseMainSupport] (main) camel.main.durationMaxMessages=1 +2020-07-15 11:42:18,892 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel 3.4.0 (camel-1) is starting +2020-07-15 11:42:18,893 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html +2020-07-15 11:42:18,902 INFO [org.apa.cam.imp.eng.InternalRouteStartupManager] (main) Route: route1 started and consuming from: timer://hello +2020-07-15 11:42:18,907 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Total 1 routes, of which 1 are started +2020-07-15 11:42:18,908 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel 3.4.0 (camel-1) started in 0.015 seconds +2020-07-15 11:42:18,911 INFO [org.apa.cam.mai.MainSupport] (camel-main) Waiting until: 1 messages has been processed +2020-07-15 11:42:18,914 INFO [io.quarkus] (main) camel-quarkus-integration-test-main-command-mode 1.1.0-SNAPSHOT on JVM (powered by Quarkus 1.6.0.Final) started in 0.569s. +2020-07-15 11:42:18,915 INFO [io.quarkus] (main) Profile prod activated. +2020-07-15 11:42:18,915 INFO [io.quarkus] (main) Installed features: [camel-core, camel-log, camel-main, camel-policy, camel-support-common, camel-timer, cdi] +2020-07-15 11:42:18,919 INFO [hello] (Camel (camel-1) thread #0 - timer://hello) Exchange[ExchangePattern: InOnly, BodyType: String, Body: Hello Joe!] +2020-07-15 11:42:18,921 INFO [org.apa.cam.mai.MainLifecycleStrategy] (Camel (camel-1) thread #0 - timer://hello) Duration max messages triggering shutdown of the JVM. +2020-07-15 11:42:18,922 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) is shutting down +2020-07-15 11:42:18,931 INFO [org.apa.cam.mai.MainLifecycleStrategy] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) CamelContext: camel-1 has been shutdown, triggering shutdown of the JVM. +2020-07-15 11:42:18,933 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) uptime 0.040 seconds +2020-07-15 11:42:18,933 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) is shutdown in 0.011 seconds +2020-07-15 11:42:18,937 INFO [io.quarkus] (main) camel-quarkus-integration-test-main-command-mode stopped in 0.005s +``` + +## Compiling the command line utility to a native executable + +[As usual with Camel Quarkus](https://camel.apache.org/camel-quarkus/latest/user-guide/first-steps.html#_native_mode), +the application can be compiled to native executable by activating the `native` profile. +GraalVM with `native-image` command installed and `GRAALVM_HOME` environment variable set is required for that, +see [Building a native executable](https://quarkus.io/guides/building-native-image) section of the Quarkus +documentation. + +```shell +$ export GRAALVM_HOME=... +$ mvn clean package -Pnative +... +$ ls -lh target +... +-rwxr-xr-x. 1 ppalaga ppalaga 33M Jul 15 11:48 command-mode-runner +... +``` + +The basic command line application compiled into a Linux native executable has about 33 Megabytes. + +Running it is easy: + +```shell +$ target/*runner -Dgreeted.subject=Joe +2020-07-15 12:19:22,810 INFO [org.apa.cam.qua.cor.CamelBootstrapRecorder] (main) bootstrap runtime: org.apache.camel.quarkus.main.CamelMainRuntime +2020-07-15 12:19:22,811 INFO [org.apa.cam.mai.BaseMainSupport] (main) Auto-configuration summary: +2020-07-15 12:19:22,811 INFO [org.apa.cam.mai.BaseMainSupport] (main) camel.main.durationMaxMessages=1 +2020-07-15 12:19:22,812 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel 3.4.0 (camel-1) is starting +2020-07-15 12:19:22,812 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html +2020-07-15 12:19:22,812 INFO [org.apa.cam.imp.eng.InternalRouteStartupManager] (main) Route: route1 started and consuming from: timer://hello +2020-07-15 12:19:22,812 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Total 1 routes, of which 1 are started +2020-07-15 12:19:22,812 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel 3.4.0 (camel-1) started in 0.000 seconds +2020-07-15 12:19:22,812 INFO [io.quarkus] (main) camel-quarkus-integration-test-main-command-mode 1.1.0-SNAPSHOT native (powered by Quarkus 1.6.0.Final) started in 0.007s. +2020-07-15 12:19:22,813 INFO [io.quarkus] (main) Profile prod activated. +2020-07-15 12:19:22,812 INFO [hello] (Camel (camel-1) thread #0 - timer://hello) Exchange[ExchangePattern: InOnly, BodyType: String, Body: Hello Joe!] +2020-07-15 12:19:22,813 INFO [io.quarkus] (main) Installed features: [camel-core, camel-log, camel-main, camel-policy, camel-support-common, camel-timer, cdi] +2020-07-15 12:19:22,813 INFO [org.apa.cam.mai.MainSupport] (camel-main) Waiting until: 1 messages has been processed +2020-07-15 12:19:22,813 INFO [org.apa.cam.mai.MainLifecycleStrategy] (Camel (camel-1) thread #0 - timer://hello) Duration max messages triggering shutdown of the JVM. +2020-07-15 12:19:22,813 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) is shutting down +2020-07-15 12:19:22,813 INFO [org.apa.cam.mai.MainLifecycleStrategy] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) CamelContext: camel-1 has been shutdown, triggering shutdown of the JVM. +2020-07-15 12:19:22,813 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) uptime 0.001 seconds +2020-07-15 12:19:22,813 INFO [org.apa.cam.imp.eng.AbstractCamelContext] (Camel (camel-1) thread #1 - CamelMainShutdownCamelContext) Apache Camel 3.4.0 (camel-1) is shutdown in 0.000 seconds +2020-07-15 12:19:22,813 INFO [io.quarkus] (main) camel-quarkus-integration-test-main-command-mode stopped in 0.000s +``` + +## Show me the code! + +The sources of the application used in this blog post are based on the `main-command-mode` integration test in +the Camel Quarkus source tree: https://github.com/apache/camel-quarkus/tree/master/integration-tests/main-command-mode + +Bonus: The integration test module shows a way how to test command line applications. + +Have a lot of fun!