Red Hat Training

A Red Hat training course is available for Red Hat Fuse

Chapter 106. ServletListener Component

ServletListener Component

Available as of Camel 2.11
This component is used for bootstrapping Camel applications in web applications. For example beforehand people would have to find their own way of bootstrapping Camel, or rely on 3rd party frameworks such as Spring to do it.
Sidebar
This component supports Servlet 2.x onwards, which mean it works also in older web containers; which is the goal of this component. Though Servlet 2.x requires to use a web.xml file as configuration.
For Servlet 3.x containers you can use annotation driven configuration to boostrap Camel using the @WebListener, and implement your own class, where you boostrap Camel. Doing this still puts the challenge how to let end users easily configure Camel, which you get for free with the old school web.xml file.
Maven users will need to add the following dependency to their pom.xml for this component:
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-servletlistener</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>

Using

You would need to chose one of the following implementations of the abstract class org.apache.camel.component.servletlistener.CamelServletContextListener.
  • JndiCamelServletContextListener which uses the JndiRegistry to leverage JNDI for its registry.
  • SimpleCamelServletContextListener which uses the SimpleRegistry to leverage a java.util.Map as its registry.
To use this you need to configure the org.apache.camel.component.servletlistener.CamelServletContextListener in the WEB-INF/web.xml file as shown below:
<web-app>

  <!-- the test parameter is only to be used for unit testing -->
  <!-- you should not use this option for production usage -->
  <context-param>
    <param-name>test</param-name>
    <param-value>true</param-value>
  </context-param>

  <!-- you can configure any of the properties on CamelContext, eg setName will be configured as below -->
  <context-param>
    <param-name>name</param-name>
    <param-value>MyCamel</param-value>
  </context-param>

  <!-- configure a route builder to use -->
  <!-- Camel will pickup any parameter names that start with routeBuilder (case ignored) -->
  <context-param>
    <param-name>routeBuilder-MyRoute</param-name>
    <param-value>org.apache.camel.component.servletlistener.MyRoute</param-value>
  </context-param>

  <!-- register Camel as a listener so we can bootstrap Camel when the web application starts -->
  <listener>
    <listener-class>org.apache.camel.component.servletlistener.SimpleCamelServletContextListener</listener-class>
  </listener>

</web-app>

Options

The org.apache.camel.component.servletlistener.CamelServletContextListener supports the following options which can be configured as context-param in the web.xml file.
Option Type Description
propertyPlaceholder.XXX To configure property placeholders in Camel. You should prefix the option with "propertyPlaceholder.", for example to configure the location, use propertyPlaceholder.location as name. You can configure all the options from the Properties component.
jmx.XXX To configure JMX. You should prefix the option with "jmx.", for example to disable JMX, use jmx.disabled as name. You can configure all the options from org.apache.camel.spi.ManagementAgent. As well the options mentioned on the JMX page.
name String To configure the name of the CamelContext.
messageHistory Boolean Camel 2.12.2: Whether to enable or disable Message History (enabled by default).
streamCache Boolean Whether to enable Stream Caching.
trace Boolean Whether to enable Tracer.
delayer Long To set a delay value for Delay Interceptor.
handleFault Boolean Whether to enable handle fault.
errorHandlerRef String Refers to a context scoped Error Handler to be used.
autoStartup Boolean Whether to start all routes when starting Camel.
useMDCLogging Boolean Whether to use MDC Logging.
useBreadcrumb Boolean Whether to use breadcrumb.
managementNamePattern String To set a custom naming pattern for JMX MBeans.
threadNamePattern String To set a custom naming pattern for threads.
properties.XXX To set custom properties on CamelContext.getProperties. This is seldom in use.
routebuilder.XXX To configure routes to be used. See below for more details.
CamelContextLifecycle Refers to a FQN classname of an implementation of org.apache.camel.component.servletlistener.CamelContextLifecycle. Which allows to execute custom code before and after CamelContext has been started or stopped. See below for further details.
XXX To set any option on CamelContext.

Examples

Configuring routes

You need to configure which routes to use in the web.xml file. You can do this in a number of ways, though all the parameters must be prefixed with "routeBuilder".

Using a RouteBuilder class

By default Camel will assume the param-value is a FQN classname for a Camel RouteBuilder class, as shown below:
  <context-param>
    <param-name>routeBuilder-MyRoute</param-name>
    <param-value>org.apache.camel.component.servletlistener.MyRoute</param-value>
  </context-param>
You can specify multiple classes in the same param-value as shown below:
  <context-param>
    <param-name>routeBuilder-routes</param-name>
    <!-- we can define multiple values separated by comma -->
    <param-value>
      org.apache.camel.component.servletlistener.MyRoute,
      org.apache.camel.component.servletlistener.routes.BarRouteBuilder
    </param-value>
  </context-param>
The name of the parameter does not have a meaning at runtime. It just need to be unique and start with "routeBuilder". In the example above we have "routeBuilder-routes". But you could just as well have named it "routeBuilder.foo".

Using package scanning

You can also tell Camel to use package scanning, which mean it will look in the given package for all classes of RouteBuilder types and automatic adding them as Camel routes. To do that you need to prefix the value with "packagescan:" as shown below:
  <context-param>
    <param-name>routeBuilder-MyRoute</param-name>
    <!-- define the routes using package scanning by prefixing with packagescan: -->
    <param-value>packagescan:org.apache.camel.component.servletlistener.routes</param-value>
  </context-param>

Using a XML file

You can also define Camel routes using XML DSL, though as we are not using Spring or Blueprint the XML file can only contain Camel route(s). In the web.xml you refer to the XML file which can be from "classpath", "file" or a "http" url, as shown below:
  <context-param>
    <param-name>routeBuilder-MyRoute</param-name>
    <param-value>classpath:routes/myRoutes.xml</param-value>
  </context-param>
And the XML file is:
<?xml version="1.0" encoding="UTF-8"?>
<!-- the xmlns="http://camel.apache.org/schema/spring" is needed -->
<routes xmlns="http://camel.apache.org/schema/spring">

  <route id="foo">
    <from uri="direct:foo"/>
    <to uri="mock:foo"/>
  </route>

  <route id="bar">
    <from uri="direct:bar"/>
    <to uri="mock:bar"/>
  </route>

</routes>
Notice that in the XML file the root tag is <routes> which must use the namespace "http://camel.apache.org/schema/spring". This namespace is having the spring in the name, but that is because of historical reasons, as Spring was the first and only XML DSL back in the time. At runtime no Spring JARs is needed. Maybe in Camel 3.0 the namespace can be renamed to a generic name.

Configuring propert placeholders

Here is a snippet of a web.xml configuration for setting up property placeholders to load myproperties.properties from the classpath
  <!-- setup property placeholder to load properties from classpath -->
  <!-- we do this by setting the param-name with propertyPlaceholder. as prefix and then any options such as location, cache etc -->
  <context-param>
    <param-name>propertyPlaceholder.location</param-name>
    <param-value>classpath:myproperties.properties</param-value>
  </context-param>
  <!-- for example to disable cache on properties component, you do -->
  <context-param>
    <param-name>propertyPlaceholder.cache</param-name>
    <param-value>false</param-value>
  </context-param>

Configuring JMX

Here is a snippet of a web.xml configuration for configuring JMX, such as disabling JMX.
  <!-- configure JMX by using names that is prefixed with jmx. -->
  <!-- in this example we disable JMX -->
  <context-param>
    <param-name>jmx.disabled</param-name>
    <param-value>true</param-value>
  </context-param>

JNDI or Simple as Camel Registry

This component uses either JNDI or Simple as the Registry. This allows you to lookup Beans and other services in JNDI, and as well to bind and unbind your own Beans.
This is done from Java code by implementing the org.apache.camel.component.servletlistener.CamelContextLifecycle.

Using custom CamelContextLifecycle

In the code below we use the callbacks beforeStart and afterStop to enlist our custom bean in the Simple Registry, and as well to cleanup when we stop.
/**
 * Our custom {@link CamelContextLifecycle} which allows us to enlist beans in the {@link JndiContext}
 * so the Camel application can lookup the beans in the {@link org.apache.camel.spi.Registry}.
 * <p/>
 * We can of course also do other kind of custom logic as well.
 */
public class MyLifecycle implements CamelContextLifecycle<SimpleRegistry> {

    @Override
    public void beforeStart(ServletCamelContext camelContext, SimpleRegistry registry) throws Exception {
        // enlist our bean(s) in the registry
        registry.put("myBean", new HelloBean());
    }

    @Override
    public void afterStart(ServletCamelContext camelContext, SimpleRegistry registry) throws Exception {
        // noop
    }

    @Override
    public void beforeStop(ServletCamelContext camelContext, SimpleRegistry registry) throws Exception {
        // noop
    }

    @Override
    public void afterStop(ServletCamelContext camelContext, SimpleRegistry registry) throws Exception {
        // unbind our bean when Camel has been stopped
        registry.remove("myBean");
    }
}
Then we need to register this class in the web.xml file as shown below, using the parameter name "CamelContextLifecycle". The value must be a FQN which refers to the class implementing the org.apache.camel.component.servletlistener.CamelContextLifecycle interface.
  <context-param>
    <param-name>CamelContextLifecycle</param-name>
    <param-value>org.apache.camel.component.servletlistener.MyLifecycle</param-value>
  </context-param>
As we enlisted our HelloBean Bean using the name "myBean" we can refer to this Bean in the Camel routes as shown below:
public class MyBeanRoute extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        from("seda:foo").routeId("foo")
            .to("bean:myBean")
            .to("mock:foo");
    }
}
Important: If you use org.apache.camel.component.servletlistener.JndiCamelServletContextListener then the CamelContextLifecycle must use the JndiRegistry as well. And likewise if the servlet is org.apache.camel.component.servletlistener.SimpleCamelServletContextListener then the CamelContextLifecycle must use the SimpleRegistry

See Also