Version 12

    Please note that this wiki is OUT of DATE and only applies to older versions of Websphere mq where they did not have an adapter.

    If you are using Websphere 6.0 or above, please use the adapter configurations specified in:

     

    IBM Webspher MQ Adapter Installation

    JBoss Websphere MQ Adapter Installation

     

    -


    In this Wiki page we explain how to set up JBoss AS such that WebSphere MQ Queues can be used for messaging with External parties. The way we set it up is as follows:

     

    • We set up a Message Driven Bean (MDB) that listens to an WebSphere MQ queue. This MDB picks up messages from the queue and handles it. In our case, it is put in the normal JMS incoming queue for our system.

    • We have a MDB that listens to the outgoing JMS Queue, picks up those messages that need to be returned to a WebSphere MQ queue, and sends them to the WebSphere MQ queue.

     

    The hardest part was to make JBoss AS listen to WebSphere MQ queues similar to listening to (normal) JMS queues. This is explained first. Next, we explain how to put a message in the MQ queue, which in our case is done via the outgoing MDB.

     

    Prequisites

     

    We assume that you have installed WebSphere MQ and JBoss AS on one and the same server. In the documentation below, we assume that you have setup a MQ Queue Manager named TEST. In this queue manager, three queues have to be defined:

    • DLQ, the dead letter queue;

    • TEST_REQUEST, the request queue on which incoming request massages are put;

    • TEST_RESPONSE, the response queue on which the response it put.

     

    Of course, all of these queues can be either local or remote queue definitions.

    The queue manager listen to port 1414.

     

    For connecting JBoss AS to WebSphere MQ, no channel needs to be set up.

     

    Adding WebSphere MQ JNDI to JBoss AS JNDI

     

    To connect JBoss AS to WebSphere MQ, we add the queues set up in WebSphere to the JNDI of JBoss AS. This can be done in the following way.

     

    First, we have to copy the jar files to connect to WebSphere MQ into the lib directory of the server you want to connect. The following three files need to be made available to JBoss:

    • com.ibm.mq.jar

    • com.ibm.mqbind.jar (Note: If you are using WebSphere MQ v. 6 and above this file is not available. You should use dhbcore.jar from the distribution instead.

    • com.ibm.mqjms.jar

     

    Next, we have to make the WebSphere MQ JNDI available to the outside world. For this, you need to download two Support Pacs for WebSphere:

     

    ME01 includes a piece of Java code that allows a Java program to perform naming and directory service functions through a standard interface (called JNDI).

    MS0B provides the capability to perform administration tasks on a queue manager by sending and receiving WebSphere MQ messages. MS0B is required for ME01 to work.

     

    If you make use of an old version in WebSphere MQ (including 5.3 with no upgrades/fixes), the MS0B available via the link above will not work. An old version of MS0B can be found here: ms0b.zip (192 kB).

     

    After downloading the ZIP files, extract them in the Java subdirectory of your WebSphere distribution. You now get two jar files:

    • mqcontext.jar from the ME01 support pac, and

    • com.ibm.mq.pcf.jar from the MS0B support pac.

     

    Copy these two files into the lib of the JBoss AS server instance (which by default is default).

     

    The combination of these two jars make it possible to add the WebSphere MQ JNDI context of a specific Queue Manager in your WebSphere MQ server to the JBoss JNDI. This can be done by adding the following MBean configuration to your jboss-service.xml:

     

    <!-- WebSphere MQ context JNDI -->
    <mbean code="org.jboss.naming.ExternalContext"
           name="DefaultDomain:service=ExternalContext,jndiName=wsmq">
      <attribute name="JndiName">wsmq</attribute>
      <attribute name="Properties">
        java.naming.factory.initial=com.ibm.mq.jms.context.WMQInitialContextFactory
        java.naming.provider.url=localhost:1414/SYSTEM.DEF.SVRCONN
        java.naming.security.authentication=none
      </attribute>
      <attribute name="InitialContext">javax.naming.InitialContext</attribute>          
    </mbean>
    

     

    After starting JBoss, the JNDI of the Queue Manager listing to port 1414 is added to the JBoss JNDI and bound to prefix wsmq.

     

    Note that you have to have set up a queue manager in WebSphere MQ that listens to port 1414 to get this up and running.

     

    Set up WebSphere MQ connection factory

     

    To set up the new WebSphere MQ JMS provider, create a file named wsmq-ds.xml in the directory where your JMS configuration is situated (SERVER_HOME/deploy/jms) and put in the following XML:

     

    <?xml version="1.0" encoding="UTF-8"?>
    <connection-factories>
     
      <!-- ==================================================================== -->
      <!-- WSMQ connection factories                                            -->
      <!-- ==================================================================== -->
     
       <!-- The WSMQ JMS provider loader -->
      <mbean code="org.jboss.jms.jndi.JMSProviderLoader"
        name="jboss.mq:service=JMSProviderLoader,name=WSMQJMSProvider">
        <attribute name="ProviderName">WSMQJMSProvider</attribute>
        <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
        <attribute name="QueueFactoryRef">wsmq/TEST</attribute>
        <attribute name="TopicFactoryRef">wsmq/TEST</attribute>
      </mbean>
    
      <!-- The WSMQ JMS connection factory -->
      <no-tx-connection-factory>
        <jndi-name>WSMQJms</jndi-name>
        <rar-name>jms-ra.rar</rar-name>
        <connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
        <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
        <config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/WSMQJMSProvider</config-property>
        <max-pool-size>20</max-pool-size>
      </no-tx-connection-factory>
    
    </connection-factories>
    

     

    This creates the WebSphere MQ JMS Provider, which connects to your Queue Manager (wsmq/TEST) and the WebSphere MQ Connection Factory that can be used for outbound connections to the JMS provider.  Please note that the tx-connection-factory or the no-tx-connection-factory is for outbound only and has no impact on the inbound adapter.  The connection factory defined here will be used by your producers to send messages.

     

    Set up container configuration for EJB2(if using EJB3, skip this and move to the next Section)

     

    To make an MDB listen to a WebSphere MQ queue we need to set up some additional EJB configurations. This can be done by adding a new invoker/proxy binding and a new container configuration to the SERVER_HOME/conf/standardjboss.xml.

     

    The invoker/proxy binding we set up is the following:

    <!-- The JmsProviderAdapterJNDI must match the ProviderName in SERVER_HOME/deploy/jms/wsmq-ds.xml file. -->
    <invoker-proxy-binding>
      <name>wsmq-message-driven-bean</name>
      <invoker-mbean>default</invoker-mbean>
      <proxy-factory>org.jboss.ejb.plugins.jms.JMSContainerInvoker</proxy-factory>
      <proxy-factory-config>
        <JMSProviderAdapterJNDI>WSMQJMSProvider</JMSProviderAdapterJNDI>
        <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
        <CreateJBossMQDestination>false</CreateJBossMQDestination>
        <!-- WARN: Don't set this to zero until a bug in the pooled executor is fixed -->
        <MinimumSize>1</MinimumSize>
        <MaximumSize>15</MaximumSize>
        <KeepAliveMillis>30000</KeepAliveMillis>
        <MaxMessages>1</MaxMessages>
        <MDBConfig>
          <ReconnectIntervalSec>10</ReconnectIntervalSec>
          <DLQConfig>
            <DestinationQueue>wsmq/DLQ</DestinationQueue>
            <MaxTimesRedelivered>10</MaxTimesRedelivered>
            <TimeToLive>0</TimeToLive>
          </DLQConfig>
        </MDBConfig>
      </proxy-factory-config>
    </invoker-proxy-binding>
    

    Note that a dead letter queue needs to be set up in WebSphere MQ. We named it DLQ.

     

    Next, we set up a container configuration:

    <container-configuration extends="Standard Message Driven Bean">
      <container-name>WSMQ Message Driven Bean</container-name>
      <invoker-proxy-binding-name>wsmq-message-driven-bean</invoker-proxy-binding-name>
    </container-configuration>
    

     

    Add the configuration to your MDB configuration

     

    After having configured the container configuration, you can add the following deployment descriptor to the META-INF/jboss.xml in the jar you want to deploy:

    <message-driven>
      <ejb-name>TestMQListener</ejb-name>                       
      <destination-jndi-name>wsmq/TEST_REQUEST</destination-jndi-name>
      <configuration-name>WSMQ Message Driven Bean</configuration-name>
    </message-driven>
    

     

    If you make use of Xdoclet for generating this deployment descriptors, use the following:

    /**
     * @ejb.bean name="TestMQListener"
     *           display-name="Name for TestMQListener"
     *           description="Description for TestMQListener"
     *           destination-type="javax.jms.Queue"
     *           acknowledge-mode="Auto-acknowledge"
     * 
     * @jboss.container-configuration name = "WSMQ Message Driven Bean"
     *
     * @jboss.destination-jndi-name name="wsmq/TEST_REQUEST"
     */
    
    public class TestMQListenerimplements MessageDrivenBean, MessageListener {
    
      ...
    
    }
    

     

     

    Set up container configuration for EJB3

    By default, the inbound adapter will look for the connection factories specified in java:/DefaultJMSProvider.  For ejb3, we need to alter the activation configuration for the inbound jca adapter to look in a different place for it's connection factories(java:/WSMQJMSProvider).  We can do this either through annotations or through xml files.

     

    Annotations

    @MessageDriven(activateConfig =
    {
          @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
          @ActivationConfigProperty(propertyName="destination", propertyValue="wsmq/TEST_REQUEST"),
          @ActivationConfigProperty(propertyName="providerAdapterJNDI", propertyValue="java:/WSMQJMSProvider")
    })
    

     

    XML Configuration

     

    Inside if the ejb-jar.xml file, you would add a providerAdapterJNDI activation configuration property as follows.

     

    <enterprise-beans>
          <message-driven>
           ...
           <activation-config>   
              <activation-config-property>
                   <activation-config-property-name>providerAdapterJNDI</activation-config-property-name>
                   <activation-config-property-value>java:/WSMQJMSProvider</activation-config-property-value>
              </activation-config-property>
            </activation-config>
          </message-driven>
       </enterprise-beans>
    

     

    Put messages in WebSphere MQ queue

     

    Apart from listening to a WebSphere MQ queue, you also want to be able to put a message in a response queue, in our example wsmq/TEST_RESPONSE. This works similar to putting messages on a JMS queue:

     

    // lookup connection factory in JNDI context
    QueueConnectionFactory connectionFactory = (QueueConnectionFactory) jndiContext.lookup("java:/WSMQJms");
    
    // open a connection
    QueueConnection connection = connectionFactory.createQueueConnection();
                        
    // create a new session
    QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    
    // get the response queue
    Queue responseQueue = (Queue) jndiContext.lookup("wsmq/TEST_RESPONSE");
    
    // strip off the JMS header if you do not want this to show up in your message
    ((MQQueue)responseQueue).setTargetClient(JMSC.MQJMS_CLIENT_NONJMS_MQ);
    
    // create a message sender and send the message
    QueueSender sender = session.createSender(responseQueue);
    
    // make a new (text) message containing the XML message
    TextMessage response = session.createTextMessage(someStringToSend);
    
    // send the message
    sender.send(response);
    

     

    This should to the job. Of course, you have to close some connections, preferably in a try-catch-finally construction.