Red Hat Training

A Red Hat training course is available for Red Hat Fuse

2.4. Integration with JMS

The camel-jms component provides messaging support. It integrates with the EAP Messaging (HornetQ) subsystem. Integration with other JMS implementations is possible by using the JBoss generic JMS Resource Adapter.

2.4.1. Configuring EAP JMS

With the help of standard EAP XML configuration files, you can configure the EAP messaging subsystem. The following example displays the configuration of a new JMS queue on the messaging subsystem, by adding the XML configuration to the jms-destinations section.
<jms-queue name="WildFlyCamelQueue">
  <entry name="java:/jms/queue/WildFlyCamelQueue"/>
</jms-queue>
However, you can also use a CLI script to add the queue.
jms-queue add --queue-address=WildFlyCamelQueue --entries=queue/WildFlyCamelQueue,java:/jms/queue/WildFlyCamelQueue

2.4.2. Configuring Camel Route

The following examples of JMS producer and consumer illustrates the use of EAP embedded HornetQ server to publish and consume messages, to and from destinations.
However, it also displays the use of CDI in conjunction with the camel-cdi component. You can inject the JMS ConnectionFactory instances into the Camel RouteBuilder via JNDI lookups.

2.4.2.1. JMS Producer

You can start the RouteBuilder by injecting the DefaultJMSConnectionFactory connection factory from JNDI. However, the connection factory is defined within the messaging subsystem. Also, a timer endpoint runs after every 10 seconds to share an XML payload to the EAPCamelQueue destination.
@Startup
@ApplicationScoped
@ContextName("jms-camel-context")
public class JmsRouteBuilder extends RouteBuilder {

  @Resource(mappedName = "java:jboss/DefaultJMSConnectionFactory")
  private ConnectionFactory connectionFactory;

  @Override
  public void configure() throws Exception {
    JmsComponent component = new JmsComponent();
    component.setConnectionFactory(connectionFactory);

    getContext().addComponent("jms", component);

    from("timer://sendJMSMessage?fixedRate=true&period=10000")
    .transform(constant("<?xml version='1.0><message><greeting>hello world</greeting></message>"))
    .to("jms:queue:WildFlyCamelQueue")
    .log("JMS Message sent");  
  }
}
When you add a JMS message to the EAPCamelQueue destination, a log message appears. Use the EAP Administration console to verify that the messages are placed onto the queue.

2.4.2.2. JMS Consumer

To consume JMS messages, inject and set the connection factory from JNDI on the JMSComponent instance. When the JMS endpoint consumes messages from the EAPCamelQueue destination, the content is logged to the console.
@Override
public void configure() throws Exception {
  JmsComponent component = new JmsComponent();
  component.setConnectionFactory(connectionFactory);

  getContext().addComponent("jms", component);

  from("jms:queue:WildFlyCamelQueue")
  .to("log:jms?showAll=true");  
}

2.4.2.3. JMS Transactions

To enable the Apache Camel JMS routes to participate in JMS transactions, you need to configure some spring classes to enable them to work with the EAP transaction manager and connection factory. The following example illustrates how to use CDI to configure a transactional JMS Camel route.
The camel-jms component requires a transaction manager of type org.springframework.transaction.PlatformTransactionManager. Therefore, you can create a bean extending JtaTransactionManager.
Note
Use the annotation @Named to make the bean available to Camel. It enables you to register the bean within the camel bean registry. Also, inject the EAP transaction manager and user transaction instances by using CDI.
@Named("transactionManager")
public class CdiTransactionManager extends JtaTransactionManager {

  @Resource(mappedName = "java:/TransactionManager")
  private TransactionManager transactionManager;

  @Resource
  private UserTransaction userTransaction;

  @PostConstruct
  public void initTransactionManager() {
    setTransactionManager(transactionManager);
    setUserTransaction(userTransaction);
  }
}
Declare the transaction policy that you want to implement. Use the annotation to make the bean available to Camel. Inject the transaction manager, so that you can create a TransactionalTemplate using the desired transaction policy. For example, PROPAGATION_REQUIRED in this instance.
@Named("PROPAGATION_REQUIRED")
public class CdiRequiredPolicy extends SpringTransactionPolicy {
  @Inject
  public CdiRequiredPolicy(CdiTransactionManager cdiTransactionManager) {
    super(new TransactionTemplate(cdiTransactionManager,
      new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED)));
  }
}
Also, you can configure the Camel RouteBuilder class and inject the dependencies you need for the Camel JMS component as shown in the given example:
@Startup
@ApplicationScoped
@ContextName("jms-camel-context")
public class JMSRouteBuilder extends RouteBuilder {

  @Resource(mappedName = "java:/JmsXA")
  private ConnectionFactory connectionFactory;

  @Inject
  CdiTransactionManager transactionManager;

  @Override
  public void configure() throws Exception {
    // Creates a JMS component which supports transactions
    JmsComponent jmsComponent = JmsComponent.jmsComponentTransacted(connectionFactory, transactionManager);
    getContext().addComponent("jms", jmsComponent);

    from("jms:queue:queue1")
      .transacted("PROPAGATION_REQUIRED")
      .to("jms:queue:queue2");

       from("jms:queue:queue2")
      .to("log:end")
      .rollback();
  }

2.4.2.4. Remote JMS destinations

You can send messages from one EAP instance to HornetQ destinations configured on an other EAP instance, through remote JNDI. To send messages, you need to configure an exported JMS queue. Only JNDI names bound in the java:jboss/export namespace are appropriate for remote clients.
<jms-queue name="RemoteQueue">
  <entry name="java:jboss/exported/jms/queues/RemoteQueue"/>
</jms-queue>
Note
Configure the queue on the EAP client application server and EAP remote server.