Apache Camel Integration in JBoss

Apache Camel is a powerful routing and conversion engine use in many projects. In this article we present some best practices when integrating Camel into the JBoss application server aka WildFly/EAP7. Most of this is straight-forward, yet we also faced some problems with the thread pool management.

Step 1: Add Camel components

First you will have to add all the Camel components you need, such as camel-core, camel-cdi, camel-http4, etc.  to your Maven POM:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-core</artifactId>
    <version>${org.apache.camel.version}</version>

    <exclusions>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>

        <exclusion>
            <artifactId>jaxb-core</artifactId>
            <groupId>com.sun.xml.bind</groupId>
        </exclusion>

        <exclusion>
            <artifactId>jaxb-impl</artifactId>
            <groupId>com.sun.xml.bind</groupId>
        </exclusion>
    </exclusions>
</dependency>

Note the exclusions which will prevent adding JARs to the resulting artifact that are already contained within the application server. Instead, you may have to add a jboss-deployment-structure.xml to your deployment referencing all dependent modules:

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.apache.commons.io"/>
            <module name="com.sun.xml.bind"/>
            ...
        </dependencies>
    </deployment>
</jboss-deployment-structure>

The main purpose of this is to avoid version clashes in used libraries/modules and to downsize deployments.

Step 2: Startup Camel

Add a @Startup class that will initialize Camel at application startup. Camel registers itself with CDI so that you may inject all Camel objects into your EJBs automatically.

@Singleton
@Startup
public class StartupCamel {
  @Inject
  private CamelContext context;
  @Inject
  private Logger logger;

  @PostConstruct
  public void startup() {
    logger.info("Starting camel routes using {}", context);

    try {
      configureThreadPool();

      addComponents(); // Your custom components, if any
      addRoutes();
      addTypeConverters();

      context.start();
      logger.info("Camel routes started");
    } catch (final Exception e) {
      logger.error("Error starting up camel", e);
    }}}

Step 3: Thread pooling

We experienced quite some problems with the thread pooling. The problem is that Camel manages its threads itself (and uses them a lot). This may interfere with the JEE environment where the creation of your threads is strictly prohibited by the JEE specification:

The enterprise bean must not attempt to manage threads. The enterprise bean must not attempt to start, stop, suspend, or resume a thread, or to change a thread’s priority or name. The enterprise bean must not attempt to manage thread groups. [EJB 3.1 spec, page 599]

In our case this resulted in unpredictable and confusing OutOfMemoryErrors:

java.lang.OutOfMemoryError: unable to create new native thread

Luckily, since JEE 7 there is an elegant solution to this problem: the (managed) ExecutorService. This feature allows us to implement some simple wrapper classes to be used as the Camel thread pool manager that integrate seamlessly with the application server’s thread pooling:

@Inject
private ImexThreadPoolProvider provider;
...
private void configureThreadPool() {
 context.getExecutorServiceManager().setThreadPoolFactory(provider);
}
public class ImexThreadPoolProvider implements ThreadPoolFactory {
  @Inject
  private ImexExecutorService executorService;

  @Override
  public ExecutorService newCachedThreadPool(final ThreadFactory tf) {
    return executorService;
  }
  ...
}
public class ImexExecutorService implements ScheduledExecutorService
{
  @Resource
  private ManagedScheduledExecutorService managedExecutorService;
  ...
  @Override
  public <T> Future<T> submit(final Callable<T> task)
  {
    return managedExecutorService.submit(task);
  }
  ...
}

 

 

Posted in All