Enterprise grade Java.
You'll read about Conferences, Java User Groups, Java, Integration, Reactive, Microservices and other technologies.

Friday, July 10, 2015

Using Camel Routes In Java EE Components

15:00 Friday, July 10, 2015 Posted by Markus Eisele
, ,
I've been working with Camel since a while now and I really like it's simplicity. Using it on top of Java EE always was a little bit of a challenge and one of the recent talks I gave about how to do this and the different methods of bootstrapping Camel in Java EE actually proposes to use the WildFly-Camel Subsystem. In an ongoing series I am going to explore the different ways of doing this and provide a bunch of examples which are still missing from the talk. I'm happy to receive your feedback and requests in the comments or via @myfear on twitter.

Getting Started With Camel On WildFly 8.2 
The Wildfly-Camel Subsystem provides Apache Camel integration with the WildFly Application Server. It allows you to add Camel Routes as part of the WildFly configuration. Routes can be deployed as part of Java EE applications. Java EE components can access the Camel Core API and various Camel Component APIs. Your Enterprise Integration Solution can be architected as a combination of Java EE and Camel functionality.
Remark: Latest WildFly 9 is expected to be supported by the 3.x release of WildFly-Camel.

Getting Ready 
Download and unzip WildFly 8.2.0.Final to a folder of your choice. Download and unzip the wildfly-camel patch (2.3.0) to the wildfly folder.  Start WildFly with
bin/standalone[.bat|.sh] -c standalone-camel.xml
One of the fastest ways to get up and running is with Docker and the WildFly Camel image. This image comes bundled with WildFly 8.1 and the Camel subsystem already installed.
Defining And Using A Camel Context
The CamelContext represents a single Camel routing rulebase. You use the CamelContext in a similar way to the Spring ApplicationContext. It contains all the routes for your application. You can have as many CamelContexts as necessary, as long as they have different names. WildFly-Camel let's you define them as a) in the standalone-camel.xml and domain.xml as part of the subsystem definition itself and b) or deploy them in a supported deployment artifact which contains a -camel-context.xml suffixed file and c) it can be provided as together with it's routes via a RouteBilder and the CDI integration.
A defined CamelContext can be consumed in two different ways: a) @Injected via Camel-CDI or b) accessed from the JNDI tree.

The Example Context And Route
For the following examples I use a context with an associated route which is provided via CDI and a RouteBuilder. It is an application scoped bean which is automatically started with the application start. The @ContextName annotation gives a specific name to the CamelContext.
@ApplicationScoped
@Startup
@ContextName("cdi-context")
public class HelloRouteBuilder extends RouteBuilder {

    @Inject
    HelloBean helloBean;

    @Override
    public void configure() throws Exception {
        from("direct:start").transform(body().prepend(helloBean.sayHello()).append(" user."));
    }
}
The route itself isn't exactly challenging. It takes an empty message body from direct:start and prepends the output from a CDI bean-method "sayHello" and appends the string " user." to it. For reference, the complete code can be found on my GitHub account. So, all we need to find out next is, how to use this route in the various Java EE component specifications.

Using Camel From CDI
Camel supports CDI since version 2.10. Before and outside the subsystem, it needed to be bootstrapped. This is no longer necessary and you can just use a deployed or defined CamelContext in a @Named CDI bean by simply @Injecting it by name:
@Inject
    @ContextName("cdi-context")
    private CamelContext context;

Using Camel From JSF, JAX-RS and EJBs
With the knowledge about how to use a CamelContext in CDI, you would assume, that it is easy to just do the same from JSF and alike. This is not true. You actually can't inject it into either ManagedBeans or even CDI Beans which are bound to a JSF component. Plus it's not working in EJBs. I haven't looked into it detailed, but assume it has something to do with scopes. A reasonable workaround and in fact, a better application design is to put the complete Camel logic into a separate CDI bean and just inject this.
@Named
public class HelloCamel {

    @Inject
    @ContextName("cdi-context")
    private CamelContext context;

    private final static Logger LOGGER = Logger.getLogger(HelloCamel.class.getName());

    public String doSomeWorkFor(String name) {

        ProducerTemplate producer = context.createProducerTemplate();
        String result = producer.requestBody("direct:start", name, String.class);
        LOGGER.log(Level.INFO, result);
        return result;
    }
}
The ProducerTemplate interface allows you to send message exchanges to endpoints in a variety of different ways to make it easy to work with Camel Endpoint instances from Java code. In this particular case, it just starts the route and puts a String into the body which represents the name of the component I'm using it from.
The CDI Bean, which acts as a backing-bean for the component just uses it:
@Inject
    HelloCamel helloCamel;

    public String getName() {
        return helloCamel.doSomeWorkFor("JSF");
    }
The return String is "Hello JSF user." Which also is written to the WildFly server log. The same approach is the best for all the other Java EE components.

Using Camel From EJBs
If you're using EJBs as your man application component model, it is also very reasonable to just use the JNDI approach:
 CamelContext camelctx = 
                (CamelContext) inicxt.lookup("java:jboss/camel/context/cdi-context");

Hawtio - A Camel Console
Another hidden gem in the subsystem is the bundling of the Hawtio console. It is a modular web console for managing your Java stuff and has an Apache Camel plugin which visualizes your contexts and routes. Remember, that it is automatically configured for security and you need to add a management user before you're able to access it.


Further Reading & Help
Talk to the Developers on Freenode
WildFly-Camel Subystem Documentation
WildFly Camel On GitHub
Apache Camel Website