### JMS

Messaging support is provided through the http://camel.apache.org/jms.html[JMS,window=_blank]
component which integrates with the {wildfly} Messaging (https://activemq.apache.org/artemis/)[ActiveMQ Artemis,window=_blank]) subsystem.

Integration with other JMS implementations is possible through configuration of vendor specific resource adapters, or if not available, by using the JBoss Generic JMS resource adapter.


#### {wildfly} JMS configuration

You can configure the {wildfly} https://docs.jboss.org/author/display/WFLY8/Messaging+configuration[messaging subsystem,window=_blank] through the standard {wildfly} XML configuration files.
For example, standalone.xml or domain.xml.

For the examples, that follow you use the embedded ActiveMQ Artemis in memory instance. You first configure a new JMS queue on the messaging subsystem by adding the following XML configuration to the jms-destinations section.

[source,xml,options="nowrap"]
<jms-queue name="WildFlyCamelQueue">
  <entry name="java:/jms/queue/WildFlyCamelQueue"/>
</jms-queue>

Alternatively you could use a CLI script to add the queue.

[source,options="nowrap"]
$ jms-queue add --queue-address=WildFlyCamelQueue --entries=queue/WildFlyCamelQueue,java:/jms/queue/WildFlyCamelQueue

Also, you can create a `messaging-deployment` configuration within a custom jms.xml deployment descriptor. See section 'Deployment of -jms.xml files' within the {wildfly} messaging subsystem documentation for more information.

#### Camel route configuration
The following JMS producer and consumer examples make use of {wildfly}'s embedded ActiveMQ Artemis server to publish and consume messages to and from destinations.

The examples also use CDI in conjunction with the camel-cdi component. JMS ConnectionFactory instances are injected into the Camel RouteBuilder through JNDI lookups.

##### JMS Producer

The `DefaultJMSConnectionFactory` connection factory is injected into the RouteBuilder from JNDI. Under the {wildfly} XML configuration, you can find the connection factory, within the messaging subsystem.

Next a timer endpoint runs every 10 seconds to send an XML payload to the WildFlyCamelQueue destination that has been configured earlier.

[source,java,options="nowrap"]
----
@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");
  }
}
----

A log message will be output to the console each time a JMS message is added to the WildFlyCamelQueue destination. To verify that the messages really are being placed onto the queue, you can use the {wildfly} administration console.

image::jms-queue-browse.png[]


##### JMS Consumer

To consume JMS messages the Camel RouteBuilder implementation is similar to the producer example.

As before, the connection factory is discovered from JNDI, injected and set on the JMSComponent instance.

When the JMS endpoint consumes messages from the WildFlyCamelQueue destination, the content is logged to the console.

[source,java,options="nowrap"]
----
@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");
}
----

##### JMS Transactions
To enable Camel JMS routes to participate in JMS transactions, some additional configuration is required. Since camel-jms is built around spring-jms, you need to configure some Spring classes to enable them to work with {wildfly}'s transaction manager and connection factory. The following code example demonstrates 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 start by creating a bean extending `JtaTransactionManager`. Note that the bean is annotated with `@Named` to allow the bean to be registered within the Camel bean registry. Also note that the {wildfly} transaction manager and user transaction instances are injected using CDI.

[source,java,options="nowrap"]
----
@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);
  }
}
----

Next, you need to declare the transaction policy that you want to use. Again, use the `@Named` annotation to make the bean available to Camel. The transaction manager is also injected so that a TransactionTemplate can be created with the desired transaction policy. PROPAGATION_REQUIRED in this instance.

[source,java,options="nowrap"]
@Named("PROPAGATION_REQUIRED")
public class CdiRequiredPolicy extends SpringTransactionPolicy {
  @Inject
  public CdiRequiredPolicy(CdiTransactionManager cdiTransactionManager) {
    super(new TransactionTemplate(cdiTransactionManager,
      new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED)));
  }
}

Now you can configure our Camel RouteBuilder class and inject the dependencies needed for the Camel JMS component. The {wildfly} XA connection factory is injected together with the transaction manager that has been configured earlier.

In this example RouteBuilder, whenever any messages are consumed from queue1, they are routed to another JMS queue named queue2. Messages consumed from queue2 result in JMS transaction being rolled back using the rollback() DSL method. This results in the original message being placed onto the dead letter queue(DLQ).

[source,java,options="nowrap"]
----
@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");

    // Force the transaction to roll back. The message will end up on the Wildfly 'DLQ' message queue
    from("jms:queue:queue2")
      .to("log:end")
      .rollback();
  }
----

##### Remote JMS destinations

It is possible for one {wildfly} instance to send messages to ActiveMQ Artemis destinations configured on another {wildfly} instance through https://docs.jboss.org/author/display/WFLY8/Remote+JNDI+Reference[remote JNDI,window=_blank].

Some additional {wildfly} configuration is required to achieve this. First an exported JMS queue is configured.

Only JNDI names bound in the `java:jboss/exported` namespace are considered as candidates for remote clients, so the queue is named appropriately.

[NOTE]
====
You must configure the queue on the {wildfly} client application server __and__{wildfly} remote server.
====

[source,xml,options="nowrap"]
<jms-queue name="RemoteQueue">
  <entry name="java:jboss/exported/jms/queues/RemoteQueue"/>
</jms-queue>

Before the client can connect to the remote server, user access credentials need to be configured. On the remote server run the https://docs.jboss.org/author/display/WFLY8/add-user+utility[add user utility,window=_blank] to create a new application user within the 'guest' group. This example has a user with the name 'admin' and a password of 'secret'.

The RouteBuilder implementation is different to the previous examples. Instead of injecting the connection factory, you need to configure an InitialContext and retrieve it from JNDI ourselves.

The `configureInitialContext` method creates this InitialContext. Notice that you need to set a provider URL which should reference your remote {wildfly} instance host name and port number. This example uses the {wildfly} JMS http-connector, but there are alternatives documented https://docs.jboss.org/author/display/WFLY8/Messaging+configuration[here,window=_blank].

Finally the route is configured to send an XML payload every 10 seconds to the remote destination configured earlier - 'RemoteQueue'.

[source,java,options="nowrap"]
----
@Override
public void configure() throws Exception {
  Context initialContext = configureInitialContext();
  ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup("java:jms/RemoteConnectionFactory");

  JmsComponent component = new JmsComponent();
  component.setConnectionFactory(connectionFactory);

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

  from("timer://foo?fixedRate=true&period=10000")
  .transform(constant("<?xml version='1.0><message><greeting>hello world</greeting></message>"))
  .to("jms:queue:RemoteQueue?username=admin&password=secret")
  .to("log:jms?showAll=true");
}

private Context configureInitialContext() throws NamingException {
  final Properties env = new Properties();
  env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
  env.put(Context.PROVIDER_URL, System.getProperty(Context.PROVIDER_URL, "http-remoting://my-remote-host:8080"));
  env.put(Context.SECURITY_PRINCIPAL, System.getProperty("username", "admin"));
  env.put(Context.SECURITY_CREDENTIALS, System.getProperty("password", "secret"));
  return new InitialContext(env);
}
----

#### Security

Refer to the link:index.html#_jms_security[JMS security section].

ifndef::red-hat-fuse[]

#### Code examples on GitHub

An example https://github.com/wildfly-extras/wildfly-camel-examples/tree/master/camel-jms[camel-jms application,window=_blank] is available on GitHub.

endif::[]

ifdef::red-hat-fuse[]

#### Quickstart examples in Fuse on EAP

A quickstart example is available in your Fuse on EAP installation at `quickstarts/camel/camel-jms` directory.

endif::red-hat-fuse[]

