Camel JBang

A JBang-based Camel app for easily running Camel routes.

Installation

First you must install JBang which is used for launching Camel. See instructions on JBang how to download and install.

After JBang is installed you can verify JBang is working by executing the following command from a command shell:

jbang version

Which should output the version of JBang.

To make it easier to use Camel JBang then install the following:

jbang app install camel@apache/camel

This will install Apache Camel as the camel command within JBang, meaning that you can run Camel from the command line by just executing camel (see more next).

Using Camel JBang

The Camel JBang supports multiple commands. Running the command below, will print all of them:

camel --help
The first time you run this command, it may cause dependencies to be cached, therefore taking a few extra seconds to run.

All the commands support the --help and will display the appropriate help if that flag is provided.

Creating and running Camel routes

You can create a new basic routes with the init command.

For example to create an XML route you do:

camel init cheese.xml

Which creates the file cheese.xml with a sample route.

To run the file, you simply do:

camel run cheese.xml
You can create and run any of the supported DSLs in Camel such as YAML, XML, Java, Groovy.

To create a new .java route, you simply do:

camel init foo.java

Running Routes from multiple files

You can run more than 1 file, for example to run two YAML files you can do:

camel run one.yaml two.yaml

You can also mix different DSLs such as yaml and Java:

camel run one.yaml hello.java

You can also use wildcards (i.e. *) to match multiple files, such as running all the yaml files:

camel run *.yaml

Or you can run all files starting with foo*

camel run foo*

And to run everything

camel run *
The run goal can also detect files that are properties.

Dev mode with live reload

You can enable dev mode that comes with live reload of the route(s) when the source file is updated (saved), using the --dev options as shown:

camel run foo.yaml --dev

Then while the Camel application is running, you can update the YAML route and update when saving.

This works for all DLS even java, so you can do:

camel run hello.java --dev
The live reload is meant for development purposes, and if you encounter problems with reloading such as JVM class loading issues, then you may need to restart the application.

Developer Console

You can enable the developer console, which presents a variety of information to the developer.

camel run hello.java --console

The console is then accessible from a web browser at: http://localhost:8080/q/dev (by default). The link is also shown in the log when Camel is starting up.

The console can give you insights into your running Camel application, such as reporting the top routes that takes the longest time to process messages. You can then drill down to pin-point, exactly which individual EIPs in these routes are the slowest.

The developer console can also output the data in JSon format, which for example can be used by 3rd-party tooling to scrape the information.

For example to output the top routes via curl, you can execute:

curl -s -H "Accept: application/json"  http://0.0.0.0:8080/q/dev/top/

And if you have jq installed which can format and output the JSon data in colour, then do:

curl -s -H "Accept: application/json"  http://0.0.0.0:8080/q/dev/top/ | jq

Using profiles

Camel JBang have the concept of profiles. A profile is essentially a name (id) that refers to which configuration to automatic load with Camel JBang. The default profile is named application which is a (smart default) to let Camel JBang automatic load application.properties (if present).

This means that creating profiles matching to a properties file with the same name.

For example having a profile named local, means that Camel JBang will load local.properties instead of application.properties.

To use a profile, you specify as command line option --profile such as:

camel run hello.java --profile=local

You can only specify one profile name, i.e. --profile=local,two is not valid.

In the properties files you can configure all the configurations from Camel Main.

For example to turn off Stream Caching and enable log masking you can specify:

camel.main.streamCaching=false
camel.main.logMask=true

And you can also configure Camel components such as camel-kafka to declare the URL to the brokers:

camel.component.kafka.brokers=broker1:9092,broker2:9092,broker3:9092
Keys starting with camel.jbang are reserved keys that are used by Camel JBang internally, and as well allow for pre-configuring arguments for Camel JBang commands.

Downloading JARs over the internet

By default, Camel JBang will automatically resolve dependencies needed to run Camel, which is done by JBang and Camel respectively. Camel itself detects at runtime if a component has a need for JARs that are not currently available on the classpath, and can then automatic download the JARs (incl transitive).

Camel will download these JARs in the following order:

  1. from local disk in ~/.m2/repository

  2. from internet in Maven Central

  3. from internet in custom 3rd-party Maven repositories

If you do not want Camel JBang to download over the internet, you can turn this off with --download, as shown below:

camel run foo.java --download=false

Adding custom JARs

Camel JBang will automatically detect dependencies for Camel components, languages, data formats, etc. that from its own release. This means you often do not have to specify which JARs to use.

However, if you need to add 3rd-party custom JARs then you can specify these with --deps as CLI argument in Maven GAV syntax (groupId:artifactId:version), such as:

camel run foo.java --deps=com.foo:acme:1.0

In case you need to explicit add a Camel dependency you can use a shorthand syntax (starting with camel: or camel-) such as:

camel run foo.java --deps=camel-saxon

You can specify multiple dependencies separated by comma:

camel run foo.java --deps=camel-saxon,com.foo:acme:1.0

Using 3rd-party Maven repositories

Camel JBang will download from local repository first, and then online from Maven Central. To be able to download from 3rd-party Maven repositories then you need to specify this as CLI argument, ]or in application.properties

camel run foo.java --repos=https://packages.atlassian.com/maven-external
Multiple repositories can be separated by comma

The configuration for the 3rd-party Maven repositories can also be configured in application.properties with the key camel.jbang.repos as shown:

camel.jbang.repos=https://packages.atlassian.com/maven-external

And when running Camel then application.properties is automatically loaded:

camel run foo.java

However, you can also explicit specify the properties file to use:

camel run foo.java application.properties

And even better if you specify this as a profile:

camel run foo.java --profile=application

Where the profile id is the name of the properties file.

Running routes hosted on GitHub

You can run a route that is hosted on GitHub using Camels github resource loader.

For example to run one of the Camel K examples you can do:

camel run github:apache:camel-k:examples/languages/routes.yaml

You can also use the https URL for GitHub. For example, you can browse the examples from a web-browser and then copy the URL from the browser window and run the example with Camel JBang:

camel run https://github.com/apache/camel-k/blob/main/examples/languages/routes.yaml

You can also use wildcards (i.e. *) to match multiple files, such as running all the groovy files:

camel run https://github.com/apache/camel-k/tree/main/examples/languages/*.groovy

Or you can run all files starting with rou*

camel run https://github.com/apache/camel-k/tree/main/examples/languages/rou*

Running routes from GitHub gists

Using gists from GitHub is a quick way to share small Camel routes that you can easily run.

For example to run a gist you simply do:

camel run https://gist.github.com/davsclaus/477ddff5cdeb1ae03619aa544ce47e92

A gist can contain one or more files, and Camel JBang will gather all relevant files, so a gist can contain multiple routes, properties files, Java beans, etc.

Downloading routes hosted on GitHub

We have made it easy for Camel JBang to download existing examples from GitHub to local disk, which allows for modifying the example and to run locally.

All you need to do is to copy the https link from the web browser. For example, you can download the dependency injection example by:

camel init https://github.com/apache/camel-kamelets-examples/tree/main/jbang/dependency-injection

Then the files (not sub folders) are downloaded to the current directory. The example can then be run locally with:

camel run *

You can also run in dev mode, to hot-deploy on source code changes.

camel run * --dev

You can also download a single file, such as one of the Camel K examples:

camel init https://github.com/apache/camel-k/blob/main/examples/languages/simple.groovy

This is a groovy route, which you can run with (or use *):

camel run simple.groovy

Downloading routes form GitHub gists

You can also download files from gists easily as shown:

camel init https://gist.github.com/davsclaus/477ddff5cdeb1ae03619aa544ce47e92

This will then download the files to local disk, which you can run afterwards:

camel run *

Using a specific Camel version

You can specify which Camel version to run as shown:

jbang run -Dcamel.jbang.version=3.17.0 camel@apache/camel [command]

And you can also try bleeding edge development by using SNAPSHOT such as:

jbang run -Dcamel.jbang.version=3.19.0-SNAPSHOT camel@apache/camel [command]

Running Camel K integrations or bindings

Camel also supports running Camel K integrations and binding files, which are in CRD format (Kubernetes Custom Resource Definitions).

For example a kamelet binding file named joke.yaml:

#!/usr/bin/env jbang camel@apache/camel run
apiVersion: camel.apache.org/v1alpha1
kind: KameletBinding
metadata:
  name: joke
spec:
  source:
    ref:
      kind: Kamelet
      apiVersion: camel.apache.org/v1
      name: chuck-norris-source
    properties:
      period: 2000
  sink:
    ref:
      kind: Kamelet
      apiVersion: camel.apache.org/v1
      name: log-sink
    properties:
      show-headers: false

Can be run with camel:

camel run joke.yaml

Run from clipboard

You can also run Camel routes directly from the OS clipboard. This allows to copy some code, and then quickly run this.

The syntax is

camel run clipboard.<extension>

Where <extension> is what kind of file the content of the clipboard is, such as java, xml, or yaml etc.

For example. you can copy this to your clipboard and then run it afterwards:

<route>
  <from uri="timer:foo"/>
  <log message="Hello World"/>
</route>
camel run clipboard.xml

Scripting from terminal using pipes

You can also execute a Camel JBang file as a script that can be used for terminal scripting with pipes and filters.

Every time the script is executed a JVM is started with Camel. This is not very fast or low on memory usage, so use Camel JBang terminal scripting where using Camel makes sense. For example to use the many Camel components or Kamelets to more easily send or receive data from disparate IT systems.

This requires to add the following line in top of the file, for example as in the upper.yaml file below:

///usr/bin/env jbang --quiet camel@apache/camel pipe "$0" "$@" ; exit $?

# Will upper-case the input
- from:
    uri: "stream:in"
    steps:
      - setBody:
          simple: "${body.toUpperCase()}"
      - to: "stream:out"

To be able to execute this as a script, you need to set execute file permission:

chmod +x upper.yaml

Then you can then execute this as a script:

echo "Hello\nWorld" | ./upper.yaml

Which should output:

HELLO
WORLD

Logging can be turned on using --logging=true which then logs to .camel-jbang/camel-pipe.log file. The name of the logging file cannot be configured.

echo "Hello\nWorld" | ./upper.yaml --logging=true

Using stream:in with line vs raw mode

When using stream:in to read data from System in then the Stream component works in two modes:

  • line mode (default) - reads input as single lines (separated by line breaks). Message body is a String.

  • raw mode - reads the entire stream until end of stream. Message body is a byte[].

The default mode is due to historically how the stream component was created. Therefore, you may want to set stream:in?readLine=false to use raw mode.

Running local Kamelets

You can also use Camel JBang to try local Kamelets, without the need to publish them on GitHub or package them in a jar.

camel run --local-kamelet-dir=/path/to/local/kamelets earthquake.yaml

Using platform-http component

When a route is started from platform-http then Camel JBang will automatically include a VertX HTTP server running on port 8080. For example the following route in a file named server.yaml:

- from:
    uri: "platform-http:/hello"
    steps:
      - set-body:
          constant: "Hello World"

Can be run with

camel run server.yaml

And you can call the HTTP service with:

$ curl http://localhost:8080/hello
Hello World%

Using Java beans and processors

There is basic support for including regular Java source files together with Camel routes, and let Camel JBang runtime compile the Java source. This means you can include smaller utility classes, POJOs, Camel Processors and whatnot that the application needs.

The Java source files cannot use package names. This may change in the future.

Dependency Injection in Java classes

When running Camel applications with camel-jbang, then the runtime is camel-main based. This means there is no Spring Boot, or Quarkus available. However, we have added support for using annotation based dependency injection in Java classes.

Using Camel dependency injection

You can use the following Camel annotations (they work on all runtimes):

  • @org.apache.camel.BindToRegistry on class level to create an instance of the class and register in the Registry.

  • @org.apache.camel.BeanInject to dependency inject a bean on a class field.

  • @org.apache.camel.PropertyInject to inject a property placeholder. Such as a property defined in application.properties.

  • @org.apache.camel.BindToRegistry on a method to create a bean by invoking the method.

  • @org.apache.camel.Converter on class level to auto-register the type converters from the class.

Using Spring Boot dependency injection

You can use the following Spring Boot annotations:

  • @org.springframework.stereotype.Component or @org.springframework.stereotype.Service on class level to create an instance of the class and register in the Registry.

  • @org.springframework.beans.factory.annotation.Autowired to dependency inject a bean on a class field. @org.springframework.beans.factory.annotation.Qualifier can be used to specify the bean id.

  • @org.springframework.beans.factory.annotation.Value to inject a property placeholder. Such as a property defined in application.properties.

  • @org.springframework.context.annotation.Bean on a method to create a bean by invoking the method.

Using Quarkus injection

You can use the following Quarkus annotations:

  • @javax.enterprise.context.ApplicationScoped or @javax.inject.Singleton on class level to create an instance of the class and register in the Registry. @javax.inject.Named can be used to specify the bean id.

  • @javax.inject.Inject to dependency inject a bean on a class field. @javax.inject.Named can be used to specify the bean id.

  • @org.eclipse.microprofile.config.inject.ConfigProperty to inject a property placeholder. Such as a property defined in application.properties.

  • @javax.enterprise.inject.Produces on a method to create a bean by invoking the method. @javax.inject.Named can be used to specify the bean id.

Debugging

Java debugging

You can debug both Camel JBang and your integration scripts by making use of the --debug flag provided by JBang:

camel --debug run /path/to/integration.java
[jbang] Building jar...
Listening for transport dt_socket at address: 4004

As you can see the default listening port is 4004 but can be configured as described in JBang Debugging.

This is a standard Java debug socket. You can then use the IDE of your choice. For instance, see the generic documentation for IntelliJ, VS Code and Eclipse Desktop. You will surely want to add Processor to be able to put breakpoints hit during route execution (as opposed to route definition creation).

Camel debugging

The Camel debugger is available by default (the camel-debug component is automatically added to the classpath). By default, it can be reached through JMX at the URL service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi/camel.

You can then use the Integrated Development Environment (IDE) of your choice. For instance IntelliJ, VS Code or Eclipse Desktop.

A specific how-to is available for VS Code, see this video or this /blog/2022/05/start-camel-quarkus-application-with-camel-textual-debug-in-vscode/[blogpost].

Open API

Camel JBang allows to quickly expose an Open API service using contract first approach, where you have an existing OpenAPI specification file.

Then Camel JBang is able to bridge each API endpoints from the OpenAPI specification to a Camel route with the naming convention direct:<operationId>.

This make it quick to implement a Camel route for a given operation.

See the open-api example for more details.

Creating Projects

You can export your Camel JBang application to a traditional Java based project such as Spring Boot or Quarkus.

You may want to do this after you have built a prototype using Camel JBang, and are in need of a traditional Java based project with more need for Java coding, or wanting to use the powerful runtimes of Spring Boot, Quarkus or vanilla Camel Main.

Exporting to Camel Spring Boot

The command export --runtime=spring-boot will export your current Camel JBang file(s) to a Maven based Spring Boot project with files organized in src/main/ folder structure.

For example to export to Spring Boot using the Maven groupId com.foo and the artifactId acme and with version 1.0-SNAPSHOT you simply execute:

camel export --runtime=spring-boot --gav=com.foo:acme:1.0-SNAPSHOT
This will export to the current directory, meaning that files are moved into the needed folder structure.

To export to another directly (copies the files) you execute:

camel export --runtime=spring-boot --gav=com.foo:acme:1.0-SNAPSHOT --dir=../myproject
See the possible options by running: camel export --help for more details.

Exporting to Camel Quarkus

The command export --runtime=quarkus will export your current Camel JBang file(s) to a Maven based Quarkus project with files organized in src/main/ folder structure.

For example to export to Quarkus using the Maven groupId com.foo and the artifactId acme and with version 1.0-SNAPSHOT you simply execute:

camel export --runtime=quarkus --gav=com.foo:acme:1.0-SNAPSHOT
This will export to the current directory, meaning that files are moved into the needed folder structure.

To export to another directly (copies the files) you execute:

camel export --runtime=quarkus --gav=com.foo:acme:1.0-SNAPSHOT --dir=../myproject
See the possible options by running: camel export --help for more details.

Exporting to Camel Main

The command export --runtime=camel-main will export your current Camel JBang file(s) to a Maven based vanilla Camel Main project with files organized in src/main/ folder structure.

For example to export to Camel Main using the Maven groupId com.foo and the artifactId acme and with version 1.0-SNAPSHOT you simply execute:

camel export --runtime=camel-main --gav=com.foo:acme:1.0-SNAPSHOT
This will export to the current directory, meaning that files are moved into the needed folder structure.

To export to another directly (copies the files) you execute:

camel export --runtime=camel-main --gav=com.foo:acme:1.0-SNAPSHOT --dir=../myproject
See the possible options by running: camel export --help for more details.

Exporting with JMX management included

Usually when exporting to Spring Boot, Quarkus or Camel Main, then JMX management is not included out of the box. To include JMX, you need to add camel:management in the --deps option, as shown below:

camel export --runtime=quarkus --gav=com.foo:acme:1.0-SNAPSHOT --deps=camel:management --dir=../myproject

Troubleshooting

When using JBang then JBang stores state in ~/.jbang directory. This is also the location where JBang stores downloaded JARs.

Camel JBang also downloads needed dependencies while running. However, these dependencies are downloaded to your local Maven repository ~/.m2.

So if you find problems with running Camel JBang using what is seems like an outdated JAR, then you can try to delete these directories, or parts of it.