22.10. Configure a Generic JMS Resource Adapter for Use with a Third-party JMS Provider

Summary

JBoss EAP 6 can be configured to work with third-party JMS providers, however not all JMS providers produce a JMS JCA resource adapter for integration with Java application platforms. This procedure covers the steps required to configure the generic JMS resource adapter included in JBoss EAP 6 to connect to a JMS provider. In this procedure, Tibco EMS 6.3 is used as an example JMS provider, however other JMS providers may need a different configuration.

Important

Before using the generic JMS resource adapter, check with the JMS provider to see if they have their own resource adapter that can be used with JBoss EAP 6. The generic JMS JCA resource adapter should only be used when a JMS provider does not provide its own resource adapter.

Prerequisites

  • JMS provider server is already configured and ready for use. Any binaries required for the provider's JMS implementation will be needed.
  • You will also need to know the values of the following JMS provider properties to be able to lookup its JMS resources (connection factories, queues and topics).
    • java.naming.factory.initial
    • java.naming.provider.url
    • java.naming.factory.url.pkgs
    In the example XML used in this procedure, these parameters are written as PROVIDER_FACTORY_INITIAL, PROVIDER_URL, and PROVIDER_CONNECTION_FACTORY respectively. Replace these placeholders with the JMS provider values for your environment.

Procedure 22.10.  Configure a Generic JMS Resource Adapter for Use with a Third-party JMS Provider

  1. Create a JBoss Module for the JMS provider

    Create a JBoss module that contains all the libraries required to connect and communicate with the JMS provider. This module will be named org.jboss.genericjms.provider.
    1. Create the following directory structure: EAP_HOME/modules/system/layers/base/org/jboss/genericjms/provider/main
    2. Copy the binaries required for the provider's JMS implementation to EAP_HOME/modules/system/layers/base/org/jboss/genericjms/provider/main.

      Note

      For Tibco EMS, the binaries required are tibjms.jar and tibcrypt.jar from the Tibco installation's lib directory.
    3. Create a module.xml file in EAP_HOME/modules/system/layers/base/org/jboss/genericjms/provider/main as below, listing the JAR files from the previous steps as resources:
      <module xmlns="urn:jboss:module:1.1" name="org.jboss.genericjms.provider">
        <resources> 
          <!-- all jars required by the JMS provider, in this case Tibco -->
          <resource-root path="tibjms.jar"/> 
          <resource-root path="tibcrypt.jar"/>
        </resources> 
        <dependencies> 
          <module name="javax.api"/> 
          <module name="javax.jms.api"/> 
        </dependencies> 
      </module>
  2. Configure a JNDI external context to the JMS provider

    The JMS resources (connection factories and destinations) are looked up in the JMS provider. We will add an external context in the JBoss EAP 6 instance so that any local lookup for this resource will automatically look up the resource on the remote JMS provider.

    Note

    In this procedure, EAP_HOME/standalone/configuration/standalone-full.xml is used as the JBoss EAP 6 configuration file.
    In EAP_HOME/standalone/configuration/standalone-full.xml, under <subsystem xmlns="urn:jboss:domain:naming:1.4">, add:
    <bindings>
      <external-context name="java:global/remoteJMS/"
        module="org.jboss.genericjms.provider" 
        class="javax.naming.InitialContext">
        <environment>
          <property name="java.naming.factory.initial" value="${PROVIDER_FACTORY_INITIAL}"/>
          <property name="java.naming.provider.url" value="${PROVIDER_URL}"/>
          <property name="java.naming.factory.url.pkgs" value="${PROVIDER_URL_PKGS}"/>
        </environment>
      </external-context>
    </bindings>
    These three properties' values must be replaced by the correct value to connect to the remote JMS provider. Take care when replacing the placeholder text to keep the ${} intact.
  3. Enable Lookup by String

    There are some JMS provider (such as Tibco EMS) that do not support the JNDI lookup(Name) method. In these cases, add the org.jboss.as.naming.lookup.by.string property with a value true to workaround this issue.

    Example 22.2.  Enable Lookup by String with Tibco EMS

    A complete definition for an external-context to Tibco EMS would be as follows.
    <bindings>
      <external-context name="java:global/remoteJMS/"
          module="org.jboss.genericjms.provider"
          class="javax.naming.InitialContext">
        <environment>
          <property name="java.naming.factory.initial" value="com.tibco.tibjms.naming.TibjmsInitialContextFactory"/>
          <property name="java.naming.provider.url" value="TIBCO_EMS_SERVER_HOST_NAME:PORT"/>
          <property name="java.naming.factory.url.pkgs" value="com.tibco.tibjms.naming"/>
          <property name="org.jboss.as.naming.lookup.by.string" value="true"/>
        </environment>
      </external-context>
    </bindings>
    With this external context, any JNDI lookup to a resource starting with java:global/remoteJMS/ will be done on the remote JMS provider (after removing this prefix). As an example, if a Message-Driven Bean perform a JNDI lookup for java:global/remoteJMS/Queue1, the external context will connect to the remote JMS provider and perform a lookup for the Queue1 resource.
  4. Configure the Generic JMS Resource Adapter

    In EAP_HOME/standalone/configuration/standalone-full.xml, add the generic resource adapter configuration to <subsystem xmlns="urn:jboss:domain:resource-adapters:1.1">.

    Example 22.3.  Tibco EMS Resource Adapter Configuration

    A complete resource adapter definition for Tibco EMS would be as follows.
    <resource-adapter id="org.jboss.genericjms">
      <module slot="main" id="org.jboss.genericjms"/>
      <transaction-support>NoTransaction</transaction-support>
      <connection-definitions>
        <connection-definition class-name="org.jboss.resource.adapter.jms.JmsManagedConnectionFactory"
          jndi-name="java:/jms/XAQCF"
          pool-name="XAQCF">
          <config-property name="ConnectionFactory">
            XAQCF
          </config-property>
          <config-property name="JndiParameters">
      java.naming.factory.initial=com.tibco.tibjms.naming.TibjmsInitialContextFactory;java.naming.provider.url=TIBCO_EMS_SERVER_HOST_NAME:PORT
          </config-property>
          <security>
            <application/>
          </security>
        </connection-definition>
      </connection-definitions>
    </resource-adapter>
  5. Configure the default message-driven bean pool with the generic resource adapter.

    In EAP_HOME/standalone/configuration/standalone-full.xml, in <subsystem xmlns="urn:jboss:domain:ejb3:1.5">, update the <mdb> configuration with:
    <mdb>
      <resource-adapter-ref resource-adapter-name="org.jboss.genericjms"/>
      <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
    </mdb>
Result

The generic JMS resource adapter is now configured and ready for use. When creating a new Message-driven Bean, use code similar below to use the resource adapter.

Example 22.4. Use the Generic Resource Adapter

@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
  // The generic JMS resource adapter requires the JNDI bindings
  // for the actual remote connection factory and destination
  @ActivationConfigProperty(propertyName = "connectionFactory", propertyValue = "java:global/remoteJMS/XAQCF"),
  @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:global/remoteJMS/Queue1"),
  @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
  @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
  public class HelloWorldQueueMDB implements MessageListener {
  public void onMessage(Message message) {
  // called every time a message is received from the `Queue1` queue on the JMS provider.
  }
}

Warning

When using the generic JMS resource adapter, ensure you set the session to be transacted, to avoid a potential NullPointerException (NPE) error. The NPE error occurs because the generic JMS resource adapter attempts processing of parameters, when the Java EE specification states that they are not to be processed.
connection.createSession(true, Session.SESSION_TRANSACTED);

Example 22.5. Use the Pooled Connection

You can also use the pooled connection factory from the resource adapter.
@Resource(lookup = "java:/jms/XAQCF")
private ConnectionFactory cf;

Example 22.6. Perform a Lookup

It is not possible to inject a resource from an external context directly but it is possible to inject an external context and then perform a lookup. For example, a lookup for a queue deployed in a Tibco EMS broker would be as follows.
@Resource(lookup = "java:global/remoteJMS")
private Context context;

...

Queue queue = (Queue) context.lookup("Queue1")