2013-01-04

Camel 2.11 - Camel web applications without Spring

So today we are in the year of 2013.

And as I write this we have just added a new component to the upcoming Apache Camel 2.11, that allow to run web applications with Camel without having to rely on Spring Framework to boostrap Camel. Or any other 3rd party frameworks for that matter.

A bit ashamed to say that in the year 2013 we are a bit late to the party to offer this out of the box in Apache Camel.

In modern web containers supporting Servlet 3.0 spec. you can programmatically bootstrap your code using the new @WebListener annotation. But even so there is still work to be done, as you would need to setup and configure Camel, and as well ensure resources is unregistered and stopped when stopping the web application.

I have not found a neat way of using @WebListener and allowing external configuration of your framework such as Apache Camel. I dont really want to hardcode my configuration, or have to invent my own way of loading external configuration and configure my application. Anyone know of a solution to this problem?

Anyway we also wanted a solution that works for old school Servlet 2.x based container. There is a ton of them out there running. And even so the old school configuration with a web.xml file works just as good in the newer Servlet 3.0 containers. So we wanted an out of the box solution that fit both worlds.

Example to showcase

We have a number of examples at Apache Camel, and one is a simple web application that is ready to be deployed as a .war file in Apache Tomcat, or any other web container.

This example is using the Spring Framework to boostrap a Spring XML file, where we have Camel embedded. So what we did was to redo this example without the need for Spring.

The two examples is documented at the Apache Camel site at:


CamelServletContextListener

In Camel 2.11 we have a new component named camel-servletlistener, which offers a new CamelServletContextListener class which you configure in the web.xml file. This will then boostrap a CamelContext, and use the context init parameters as its configuration.

This context listener has a lot of configuration, so you can easily configure Camel to your needs.
The options is listed in the Camel docs at: http://camel.apache.org/servletlistener-component.html

And in case you need to execute any custom logic when Camel is starting/stopping then we have an API for that, a CamelContextLifecycle interface. There is more details and examples at the Camel docs.

To see this in action, I suggest after reading this blog, check out the new example, as well the documentation for the camel-servletlistener component.

Dissecting the example

Having the two examples

We can take a peak at the difference between the two of them, when deploying to fresh installation of Apache Tomcat 7.0.30 using Java 1.6. 

servlet-tomcat-example
size: 5.8 MB
jars: 19
classes loaded: 4507
current heap size: 10 MB

servlet-tomcat-no-spring-example
size: 2.9 MB
jars: 10
classes loaded: 3698
current heap size: 8 MB

I used jconsole to look at the number of loaded classes in the JVM with the Apache Tomcat and the deployed example. The heap size was measured as the lowest value I could get after performing GC.

So we cut 10 JARs and 3MB from the distribution. As well avoid loading in the shy of 1000 classes.

Remarks

I just want to emphasize that the goal of this new camel-servletlistener component is to allow people to easily bootstrap their Camel applications in any web container, without the need to be tied to any particular 3rd party framework such as Spring. The Apache Camel project aims to be neutral and agnostic; allowing people to run Camel in any way and container of choice.



11 comments:

Magnus Palmér said...

Great blog post, thanks, I will have to test that!

I did some stuff a few days ago where I configured a Camel webapp using Spring but without any XML at all, no applicationContext.xml and no web.xml using Springs Java Config.
Reguires you to implement the org.springframework.web.WebApplicationInitializer though and register and refresh the context in it.

If you want I can write it as an example and submit.

Gnanaguru said...

Great to know this. !

Claus Ibsen said...

Magnus, that would be lovely.

Anonymous said...

What's FuseSource? Is that Red Hat?

Claus Ibsen said...

FuseSource is http://fusesource.com/

And Red Hat acquired FuseSource in September 2012: http://fusesource.com/redhat

kiran said...

Would this also work with Java DSL ?. I see both of the examples are xml configurations

Claus Ibsen said...

Yeah you can use Java DSL also.

Travis De Silva said...

Hi Claus,

Thanks for this and also your CIA book which is what I am using to learn the basics of Camel right now.

I have a question around web applications and camel and have been googling and haven't got a ideal solution as yet. Wonder if you could give your thoughts to the below use case.

A web application written in AngularJS (i.e. JavaScript MVC client framework) consumes a rest service (i.e. JAX-RS).

Within this rest service, I have a Camel route that goes and connects to an external system. Since Camel routes are Async, my jax-rs service does not wait for a response but returns back to the calling client which is not the behaviour I need.

I need for it to wait until the route gets executed and the appropriate response it sent back to the calling client.

I have looked at the CXFRS and the Servlet components and wondering if I should be using one of them or if there is a better way to do this as I feel those approaches might be a bit heavy.

I also tried the Request Reply pattern using setExchangePattern(ExchangePattern.InOut) but that did not work.

If there is a similar example that you can point me to would be very helpful.

Claus Ibsen said...

Travis,

Please use the forum or mailing lists for discussing Camel and getting help etc. There is a much bigger audience listing and ready to help, than posting comments on this blog.

James Carman said...

Claus,

The externalized configuration is achieved through JNDI in web applications. Will that not work?

Lars-Erik Helander said...

Hi Claus, you asked for methods to configure applications and I have found that using env-entry in web.xml and @Resource annotation in the components is an excellent way. You basically have four places where you could provide the actual values:
- a default value in your component
- a env-entry in a web-fragment in the component jar
- a env-entry in web.xml
- lookup in global JNDI

/Lasse