Custom (un)Marshalling with the Camel Rest DSL

Sometimes you want to use a custom marshaller to marshal or unmarshal your messages. In our case we needed to parse all date fields to a specific format when marshalling our output message. We noticed that we could set a custom jsonDataFormat or a custom xmlDataFormat. These options allow you to specify your own DataFormat class, in essence your customized marshaller.

We needed to send out XML or JSON, depending on the clients request (http header: Accept). Because you implement the same interface I will show only the JSON DataFormat. The dataFormat options expects a class that implements the “org.apache.camel.spi.DataFormat” interface. The interface defines two methods, marshal and unmarshal. When you only use the DataFormat for outgoing messages implementing the marshal method is sufficient.

public class JsonDataFormat implements DataFormat {

    private final ObjectMapper jacksonMapper;

    public JsonDataFormat() {
        jacksonMapper = new ObjectMapper();
    }

    @Override
    public void marshal(Exchange exchange, Object obj, OutputStream stream) throws Exception {

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss");
        jacksonMapper.setDateFormat(dateFormat);

        if (view != null) {
            ObjectWriter w = jacksonMapper.writerWithView(view);
            w.writeValue(stream, obj);
        } else {
            stream.write(jacksonMapper.writeValueAsBytes(obj));
        }
    }

    @Override
    public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
        return null;
    }

Now you cannot simply add the class as a bean and refer to it. You need to add it as a DataFormat to the camel context. This can be done by adding the following file to your META-INF directory: in the classpath: services.org.apache.camel.dataformat add a file which contains the following line:

class=nl.janssen.dataformats.JsonDataFormat

The last thing you need to do is tell your restConfiguration that you want to use your dataFormat. When setting the dataFormat you have to use the file name you specified in the above mentioned classpath. In my case JsonFormat.

restConfiguration()
      .component("jetty")
      .host("0.0.0.0")
      .port("8080")
      .bindingMode(RestBindingMode.auto)
      .xmlDataFormat("XmlFormat")
      .jsonDataFormat("JsonFormat");

If you want a custom xmlDataFormat you simply have to implement the DataFormat interface again but now with an XML (un)marshalling implementation.

Alternative class in Weld

In a Camel project with Weld I faced an issue while trying to unit test a route that called a remote system (Elasticsearch). This was done with the help of a custom bean. The bean handles the connection and the actual calls to the system. I did not want to call the actual system during my Unit Test, so I created a stub. However, to create the context and start the route I used CamelCdiRunner. This meant that the original client bean was being loaded. So I had to replace the actual bean with my stub. Luckily Weld supports the use of alternative beans. In essence you can replace a bean with an alternative, in my case a stub.

The first thing you need to do is to make sure that your class is based on a interface. This enables Weld to successfully replace your bean with a alternative. Inject the bean based on the interface and not on the class itself.

@Inject
@Named("elasticsearchCamelClient")
ElasticsearchCamelClientInterface client;

Next create your mock and make sure that it implements the interface of the bean you want to replace. Add the Alternative annotation.

@Alternative
@Named("elasticsearchCamelClient")
public class MockElasticsearchCamelClient implements ElasticsearchCamelClientInterface {

  public MockElasticsearchCamelClient() {
  }

  Stub code.....

Most of the documentation I found shows you how to use an alternative bean using the beans.xml file. However it is not possible to simply add a beans.xml file to the test resources. You can only specify one for your project. You could replace it dynamically with your build tool. This however is, imho, not a nice solution. Luckily you can also specify an alternative class in your test class. By adding the “@Beans” annotation. This allows you to specify one or more alternative beans.

@RunWith(CamelCdiRunner.class)
@Beans(
  alternatives = {MockElasticsearchCamelClient.class}
)
public class RouteTest { ...

The alternatives indicates that you want to run the CamelCdiRunner with the stub. When you now start the Unit Test you will see that both beans are being loaded but that the mock is used to run your tests.

Happy testing!

Contract first Rest API

As an integration consultant I have an extensive background in web services. To be specific SOAP enabled web services. The way I used to create a service was by first defining the contract, the WSDL and the XSD files. Based on those files I could generate a service without the need for me to manually type any code.

However lately I started working with Rest services, both JSON and XML. I have written a post (Rest just got easy) on how to create a service using the rest DSL from camel. However in some situations you might want to use a JAX-RS implementation, for example using CXFRS. This means you have to first create the interface definition using POJO’s. You could do this the manual way, like me in my first couple of implementations. Or you could generate the code based on an interface design (Hooray for the lazy!). In this blog post I will show you how to generate your rest interface implementation using swagger documentation (Swagger in a nutshell).

Using a maven plugin you can easily generate the required code based on a yaml styled swagger specification file. The plugin can be found through this dependency:

<dependency>
   <groupId>io.swagger</groupId>
   <artifactId>swagger-codegen-maven-plugin</artifactId>
   <version>2.1.6</version>
</dependency>

Because I am using CXFRS I added the dependency for that as well to my pom file:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-cxf</artifactId>
</dependency>

After you have added the dependencies to the pom file you can configure the plugin.

<plugin>
   <groupId>io.swagger</groupId>
   <artifactId>swagger-codegen-maven-plugin</artifactId>
   <version>2.2.0-SNAPSHOT</version>
   <executions>
      <execution>
        <goals>
          <goal>generate</goal>
        </goals>
        <configuration>
		<!-- specify the swagger yaml -->
		<inputSpec>src/main/resources/yaml/swagger.yaml</inputSpec>
		<!-- target to generate -->
		<language>jaxrs-cxf</language>
		<apiPackage>nl.rubix.api</apiPackage>
		<modelPackage>nl.rubix.api.model</modelPackage>
		<configOptions>
		<sourceFolder>src/main/java</sourceFolder>
		</configOptions>
		</configuration>
     </execution>
   </executions>
</plugin>

The plugin has several configuration options.

  • inputSpec – OpenAPI Spec file path
  • language – target generation language
  • output – target output path (default is ${project.build.directory}/generated-sources/swagger)
  • templateDirectory – directory with mustache templates
  • addCompileSourceRoot – add the output directory to the project as a source root (true by default)
  • modelPackage – the package to use for generated model objects/classes
  • apiPackage – the package to use for generated api objects/classes
  • invokerPackage – the package to use for the generated invoker objects
  • configOptions – a map of language-specific parameters (see below)
  • configHelp – dumps the configuration help for the specified library (generates no sources)

As you can see in my example I specified the language to be “jaxrs-cxf”. Meaning that the generated sources will be specific for jaxrs-cxf. The modelPackage will contain the actual objects. If specified the plugin will add the XML declarations to the model POJO’s. The apiPackage will contain the interface specifications.

Create the yaml file on the specified location. My yaml file looks like this:

---
swagger: '2.0'
info:
  version: 0.0.0
  title: Simple API
paths:
  /:
    get:
      responses:
        200:
          description: OK

Meaning, a very simple interface that listens to the root (“/”) of servic epath and will return a http 200 if everything went as planned.

Now that the configuration is done, you can generate the sources with “mvn compile”. You will see the generated sources in the packages you specified.

If everything went correct you can now specify your service. In my example I am using blueprint in combination with the java DSL.

The blueprint definition for the cxfrs component:

<cxf:rsServer id="api" address="http://localhost:9092/test"
               serviceClass="nl.rubix.api.contractfirst.rest.DefaultApi"
               loggingFeatureEnabled="false">
   <cxf:providers>
     <bean class="org.apache.cxf.jaxrs.provider.json.JSONProvider" />
   </cxf:providers>
</cxf:rsServer>

And the route configuration:

from("cxfrs:bean:api?bindingStyle=SimpleConsumer").log("you did it!");

My example project can be found here: Download sources

Basic authentication in Camel

I need to call a webservice that uses basic authentication. All the solutions and suggestions I could find via google where ether complicated or a lot of work. Until I looked at the CXF manual (http://camel.apache.org/cxf.html). As of version 2.12.3, you can do it by simply adding the username and password to your endpoint in your camel route.

.to("cxf:bean:myCxfEndpoint?username=<username>&password=<password>")

JBoss Fuse on a raspberry pi 3

I was looking for a small server to run my personal fuse installation on. After a quick search I found the raspberry Pi as a likely candidate. A cheap and energy efficient device. Although it runs on an ARM processor you can run a (ARM) JDK on it. Which allows you to run a Jboss server and thus a Fuse server.

First install an operating system on your Pi. I chose Raspbian (lite), because of its simplicity and the fact that is a Debian distro, which I like. You can get the latest here. Installing it is simple and the site provides a good installation guide.

After the installation you want to add an usb drive or an external HDD. The SD is required for the installation of your OS but it is not wise to install the rest of your software on the SD card. More information about this can be found here. Make sure that your drive is correctly formatted (for example ext4). Check the location of your drive and (auto) mount it via editing fstab.

sudo fdisk –l 
sudo vi /etc/fstab
/dev/sda1		/apps		ext4	user,exec	0	1

After rebooting your pi confirm that the mount has succeeded. When you run “mount -l” you should see the “/dev/sda1/” mounted on the “/apps” location. Change the access rights to the directory with “sudo chown pi:pi /apps”. Note that if you made a mistake you can no longer reach your pi with ssh. It will be started in “safe mode”. You have to access the pi directly and fix the problem.

Now you are all set up to install the JDK and Fuse. Because the raspberry pi has an ARM processer you cannot install the usual JDK. You have to install one for the ARM processor, you can find the installer here.

The installation is quite straightforward, after you have unzipped the JDK you have to set the java version. This can be done in the .profile file.

vi ~/.profile
export JAVA_HOME=&lt;locatie&gt;
export PATH=$PATH:$JAVA_HOME/bin

Conferm that java is working (java –version).

Install the fuse server (installation guide).

The last step is simple, start the fuse server. Mind that it will take a while before it is started, especially the first time.