Setting up a restlet with Camel in JBoss Fuse

If you have already successfully gone through the steps of the previous tutorial, this is going to be quite fast and straightforward. All you need to know is that in Camel you can set up a restlet to listen to a specific URL/port with the “restlet” prefix.

Let’s assume that we want to listen for REST request and turn the body of the request into a message to be queued on one of our (already existent) ActiveMQ. As in the previous example, we can accomplish the task without even write a line of Java code.

We can add the following elements to our blueprint.xml file:

    <route>
        <from uri="restlet:http://localhost:8282/demo-endpoint?restletMethod=POST"></from>
        <camel:setBody>
            <simple>test=true</simple>
        </camel:setBody>
        <log message="The request body is: ${body}"></log>
        <to uri="activemq:sink-queue" pattern="InOnly"></to>
        <to uri="mock:result"></to>
    </route>

Here I’m specifying the restletMethod parameter, which tells Camel to only respond to GET HTTP request (i.e. any other HTTP verb will result in the request to be discarded). The setBody element is used for making thigs simpler: it sets the body of the exchange to the child value, as you might expect. Now we can “clean-install” the project as usual and switch to the Karaf console. Update the package with a osgi:update command (here, 251 is the ID of my bundle, you will probably have a different one. You can find out what ID your bundle has by executing a “list” command):

JBossFuse:karaf@root> osgi:update 251

After this, execute “list” and take a look at the output. In correspondence with the updated bundle you should see something like this:

[ 251] [Active     ] [GracePeriod ] [       ] [   60] A Camel Blueprint Route (1.0.0)

This is because the bundle has a missing dependency: the camel-restlet Feature. The bundle has been successfully installed, but it cannot be started until the missing dependency is satisfied. The missing feature is not installed by default in Fuse. Luckily, you can easily get it by typing the following command:

JBossFuse:karaf@root> features:install camel-restlet

To learn more about Features, refer to the official documentation.

Restart your bundle. The restlet is now ready. You can try and call it with whatever method you prefer. For simplicity, i present you the command used to perform a test with curl:

curl --data "test=true" http://localhost:8282/demo-endpoint

 

Simple Camel route in JBoss Fuse

For this tutorial and the following ones, I am going to use a Fuse instance on a Lubuntu Linux box. My IDE is Eclipse Luna and the build system is Apache Maven v. 3.5.2. Eclipse is actually running on Java 8 but it does not matter since I’m going to run all the builds from a terminal.

Let’s see how we can implement and deploy a simple Camel route in JBoss Fuse. We start by defining our requirements that, in this case, are going to be very trivial: we want to read messages from a queue, process them and the write them back to another queue. The processing step is going to be simple too: we will just log the message body.

First of all, we need two queues. Start Fuse and reach the console (see the previous post). In the menu bar, click on “ActiveMQ”. Then click on “+Create” on the submenu, select “queue” in the radio buttons group, type the appropriate name in the text box (I’m choosing “source-queue”) and finally click the “Create Queue” button (see pictures below). Repeat the process and create a “sink-queue” queue, it will be our destination queue. Later, we will be going to need to queue a message in the source queue through the web panel. In order to be able to do that, we have to set the username and password. In the web console, go to the drop down menu in the top right corner (where your username appears). Select “preferences”. Go to the “ActiveMQ” tab and insert your administrative username and password. The settings are automatically saved. Now that we have the infrastructure ready, let’s switch to the development side.

activemq-menu

create-queue

If you are going to develop projects for Fuse, Maven is the way to go. The default way you install new components in Fuse, is by telling it to get the artifacts from a Maven repository. For this tutorial I assume that you are quite familiar and comfortable with Maven and that you have a working installation of Maven on your system.

We can create the initial skeleton of the project starting from a Maven archetype. Open a Terminal and type:

mvn archetype:generate

choose the archetype named camel-archetype-blueprint (in my case is the number 449) and complete the process. Here is a dump of my terminal:

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 510: 449
Choose org.apache.camel.archetypes:camel-archetype-blueprint version:
1: 2.8.0
[...]
42: 2.14.1
Choose a number: 42: 42
Downloading: https://repo.maven.apache.org/maven2/org/apache/camel/archetypes/camel-archetype-blueprint/2.14.1/camel-archetype-blueprint-2.14.1.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/camel/archetypes/camel-archetype-blueprint/2.14.1/camel-archetype-blueprint-2.14.1.jar (17 KB at 14.1 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/camel/archetypes/camel-archetype-blueprint/2.14.1/camel-archetype-blueprint-2.14.1.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/camel/archetypes/camel-archetype-blueprint/2.14.1/camel-archetype-blueprint-2.14.1.pom (3 KB at 10.9 KB/sec)
Define value for property 'groupId': : org.merka
Define value for property 'artifactId': : fuse-demo-blueprint
Define value for property 'version':  1.0-SNAPSHOT: : 1.0
Define value for property 'package':  org.merka: : org.merka.demo
[INFO] Using property: camel-version = 2.14.1
[INFO] Using property: log4j-version = 1.2.17
[INFO] Using property: maven-bundle-plugin-version = 2.3.7
[INFO] Using property: maven-compiler-plugin-version = 2.5.1
[INFO] Using property: maven-resources-plugin-version = 2.6
[INFO] Using property: slf4j-version = 1.7.7
Confirm properties configuration:
groupId: org.merka
artifactId: fuse-demo-blueprint
version: 1.0
package: org.merka.demo
camel-version: 2.14.1
log4j-version: 1.2.17
maven-bundle-plugin-version: 2.3.7
maven-compiler-plugin-version: 2.5.1
maven-resources-plugin-version: 2.6
slf4j-version: 1.7.7
Y: : Y
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: camel-archetype-blueprint:2.14.1
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: org.merka
[INFO] Parameter: artifactId, Value: fuse-demo-blueprint
[INFO] Parameter: version, Value: 1.0
[INFO] Parameter: package, Value: org.merka.demo
[INFO] Parameter: packageInPathFormat, Value: org/merka/demo
[INFO] Parameter: maven-bundle-plugin-version, Value: 2.3.7
[INFO] Parameter: maven-resources-plugin-version, Value: 2.6
[INFO] Parameter: groupId, Value: org.merka
[INFO] Parameter: maven-compiler-plugin-version, Value: 2.5.1
[INFO] Parameter: slf4j-version, Value: 1.7.7
[INFO] Parameter: version, Value: 1.0
[INFO] Parameter: log4j-version, Value: 1.2.17
[INFO] Parameter: camel-version, Value: 2.14.1
[INFO] Parameter: package, Value: org.merka.demo
[INFO] Parameter: artifactId, Value: fuse-demo-blueprint
[INFO] project created from Archetype in dir: /home/merka/workspace/fuse-demo-blueprint
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 05:20 min
[INFO] Finished at: 2014-12-23T20:29:24+01:00
[INFO] Final Memory: 13M/60M
[INFO] ------------------------------------------------------------------------

Now we can import the project in our IDE of choice and open it. Just to be sure that everything is OK, run a first build with the command mvn -DskipTests=true clean package from the shell and wait for the required dependencies to be downloaded.

The archetype project comes with a couple of “hello world” files that you can completely ignore at this point: they only serves as an example. It’s actually better if you delete all the hello-world-related stuff, unit test included.  Open the blueprint.xml file in the folder OSGI-INF/blueprint and comment out the existing route. You should also delete the “helloBean” definition. The file should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:camel="http://camel.apache.org/schema/blueprint"
       xsi:schemaLocation="
       http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
       http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">

  <camelContext id="blueprintContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<!--     <route id="timerToLog"> -->
<!--       <from uri="timer:foo?period=5000"/> -->
<!--       <setBody> -->
<!--           <method ref="helloBean" method="hello"/> -->
<!--       </setBody> -->
<!--       <log message="The message contains ${body}"/> -->
<!--       <to uri="mock:result"/> -->
<!--     </route> -->
  </camelContext>

</blueprint>

Before the camelContext element, add the following bean definition: it provides Camel with the credentials to access the ActiveMQ Broker:

	<!-- connect to the local ActiveMQ broker -->
	<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
		<property name="brokerURL" value="tcp://localhost:61616" />
		<property name="userName" value="merka" />
		<property name="password" value="merka" />
	</bean>

Then, add the following snippet inside the camelContext element. It defines a route that satisfies our requirements:

    <route id="queue2queue">
        <from uri="activemq:source-queue"></from>
        <log message="the message body is: ${body}" loggingLevel="INFO"></log>
        <to uri="activemq:sink-queue"></to>
    </route>

It is quite readable. The from element defines a consumer endpoint: it will read messages from the queue named source-queue (that we have just created), as soon as they are available. The message body is logged, thanks to the log element, and then it is written to sink-queue.

Build the project with Maven (mvn clean install). This puts the artifact in the local Maven repository, thus making it available to Fuse. To install the artifact in Fuse, go to the Karaf prompt and type

osgi:install mvn:org.merka/fuse-demo-blueprint/1.0

With this command you tell Karaf to search for the artifact with the given groupId/artifactId/version. If found, it answers with the id of the installed osgi bundle:

JBossFuse:karaf@root> osgi:install mvn:org.merka/fuse-demo-blueprint/1.0
Bundle ID: 251

You can see all the installed components typing list. Start the bundle with the commnand start <bundle-id>. Check the log for possible errors with log:display or log:tail. If no errors are found, go to the web console and manually send a message into the source-queue queue. The message is immediately consumed from the queue, the message body appears in the log and a brand new message is sent to sink-queue.

 send-msg