JMS - Java Message Service



Transactional J2EE to IBM Websphere MQ version 5.2.1 / 5.3 / 6.0 (formerly MQseries)

In the following we will deal with: MQ v5.2.1 is a somewhat tricky issue. I haven't actually done transactional interfacing - because at the time I came around, it was too old (I couldn't get a copy to try out). However, there are solid indications that transactions (XA) !are! supported. Check out decompiled code from com.ibm.mq.MQEnvironment in com.ibm.mq.jar (MA88), which tries to load the OSE class from com.ibm.mqetclient.jar:

package com.ibm.mq;

import com.ibm.mqservices.Trace;
import java.io.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import javax.resource.spi.ConnectionManager;

public class MQEnvironment {
    ...
    static boolean getXaClientEnabled()
    {
        return xaClientEnabled;
    }
    ...
    static boolean xaClientEnabled = false;
    ...
    static {
        try {
            Class.forName("com.ibm.mq.OSE");
            ...
        }
        catch(Exception exception) {
            ...
}   }   }

That's exactly how MQ 5.3.1 and 6.0 operates in an transactional environment. Anyway, IBM certainly don't support a transactional client - and that's what normally prevent customers from having consultants like me doing magic tricks and taking things in production.

For all MQ versions, the following basic set of jar-files are used for transactional communication from J2EE client directly to MQ :



MQ v5.2.1 MA88

25-07-2002 09:39 249.780 com.ibm.mq.jar
25-07-2002 09:39 39.267 com.ibm.mqbind.jar
25-07-2002 09:39 1.339.712 com.ibm.mqjms.jar
28-01-2002 09:29 17.978 connector.jar
28-01-2002 09:30 22.769 fscontext.jar
28-01-2002 09:30 77.116 providerutil.jar

MQ v5.3 CSD 11 (you need a login to access files)

01-03-2003 00:00 3.000 com.ibm.mqetclient.jar (required only if you want to interact transactionally)
02-08-2005 01:00 344.964 com.ibm.mq.jar
02-08-2005 01:00 41.816 com.ibm.mqbind.jar
02-08-2005 01:00 1.785.421 com.ibm.mqjms.jar
02-08-2005 01:00 17.978 connector.jar
02-08-2005 01:00 22.769 fscontext.jar
02-08-2005 01:00 77.116 providerutil.jar

MQ v6.0 (out-of-the box)

24-05-2005 01:00 3.363 com.ibm.mqetclient.jar (required only if you want to interact transactionally)
24-05-2005 02:00 421.771 com.ibm.mq.jar
24-05-2005 02:00 1.230.751 com.ibm.mqjms.jar
24-05-2005 02:00 2.099.749 dhbcore.jar
24-05-2005 02:00 22.769 fscontext.jar
24-05-2005 02:00 77.116 providerutil.jar
But you don't necessarily need them in the application server classpath - and that's what we'll be avoiding here.

Specific for the MQ versions :

MQ 5.2.1 has been out of support since 2003-12-31 and will require installation of a fixpack
"MA88" to support Java at all. It's going to be hard to get, because most IBM download locations have taken them off-line (except the link provided here - where you don't even have to do a logon). Then, however, a J2EE client will connect to MQ using the usual set of J2EE client jar-files mentioned above. I honestly haven't tried J2EE clients from machines without the MQ installation - but odds are, it should work.

MQ 5.3 really comes with J2EE support "out-of-the-box". But if you want to connect transactional, you need to seek out a special IBM update "MQt5302w/C48UVML" sized 4.825.675 bytes for the "MQ Extended Transactional Client Installation" to get the com.ibm.mqetclient.jar for MQ 5.3. Oddly enough, it's not included in any of the normal CSD's up to level 11 (and probably beyond). Also, if you want to deal with publish/subscribe messaging, you need support pack "MA0C" - and then you need to setup a bunch of standard queues... From a J2EE connection point of view, MQ 5.3 is equally flexiable as 6.0 - doing both transactional/non-transactional connect from remote machines without a MQ installation (only with jar-files in active classloader).

MQ 6.0 seems like it provides the most basic stuff - and so far little extra setup is required. I'm gonna use it here for demostrations - even though I tried most things with MQ 5.3 as well.

Contained in this session:
J2EE client, external JNDI support, MQ setup

This example will create a client, using external file-based JNDI, sending messages to a MQ - which subsequely is caught by a Message Driven Bean (MDB) running from a Weblogic 8.1 installation.

Initially, we will run without a security manager and require that the MQ installation and the J2EE applications are running from the same machine. Later will introduce the security manager and perform authentication from another machine.

First, edit the JMSAdmin.config file under IBM\WebSphereMQ\Java\bin installation to set the external JNDI provider Context Factory:


setting up JMSAdmin configuration in the MQ installation
JMSAdmin.config

...
	INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory
	#INITIAL_CONTEXT_FACTORY=com.sun.jndi.ldap.LdapCtxFactory
	#INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory
	#INITIAL_CONTEXT_FACTORY=com.ibm.ejs.ns.jndi.CNInitialContextFactory
	#INITIAL_CONTEXT_FACTORY=com.ibm.websphere.naming.WsnInitialContextFactory
	#
	#  The following line specifies the URL of the service provider's initial
	#  context. It currently refers to an LDAP root context. Examples of a
	#  file system URL and WebSphere's JNDI namespace are also shown, commented
	#  out.
	#
	PROVIDER_URL=file:/C:/jms-jndi-directory
	#PROVIDER_URL=ldap://localhost:389/ou=Groups,o=Airius.com
	#PROVIDER_URL=ldap://polaris/o=ibm,c=us
	#PROVIDER_URL=file:/C:/JNDI-Directory
	#PROVIDER_URL=iiop://localhost/
...
	#
	#  The following line specifies the security authentication model in use,
	#  and may be 'none' (for anonymous authentication), 'simple', or 'CRAM_MD5'.
	#
	SECURITY_AUTHENTICATION=none
...

	#Leave out the following entries as they probably already are
	#PROVIDER_USERDN
	#PROVIDER_PASSWORD
...



Secondly, it's necessary to configure the Websphere MQ version 6.0 installation by defining the QUEUE manager... Calling it BEAMQ (after all, we're using it with BEA Weblogic server).

Start the MQ navigator and define the queue manager using standard settings...

Websphere MQ navigator definition of new queue manager

MQ navigator wizard for queue manager

Make sure you define a port not already used. Choosing port 1421 here - but that could practically be any other port not already used...

Websphere MQ setup of queue manager

Once the queue manager is in place, define the actual queue. Basicly, it means accepting all recommended standard settings.

Websphere MQ queue setup wizard

Websphere MQ local queue setup

Websphere MQ local queue setup

Websphere MQ local queue setup

Set up the external JNDI provider through JMSAdmin - with definitions matching the queue manager and queue, defined above.


setting up external JNDI through JMSAdmin
MQSC commands


def xaqcf(TOPSECURITY_XAQCF) qmgr(BEAQM) channel(SYSTEM.DEF.SVRCONN) hostname(semp20) port(1421) transport(CLIENT)
def q(TOPSECURITY_QUEUE) queue(TOPSECURITY.QUEUE) qmgr(BEAQM)


You find definition of the MQSC commands either in the "MQseries MQSC Command Reference" or on page 39 in the "MQseries Using Java - MQ 6.0".

"xaqcf" defines a transactional queue connection factory:

TOPSECURITY_XAQCF/ClassName=com.ibm.mq.jms.MQXAQueueConnectionFactory
TOPSECURITY_XAQCF/FactoryName=com.ibm.mq.jms.MQXAQueueConnectionFactoryFactory
We're using the same queue manager for both non-transactional and transactional interaction. "hostname" is defined as "semp20" (2GHz sempron) and the queue manager operates from port 1421.

JMSAdmin management console start command

JMSAdmin management console

Once having configured the external JNDI provider, you should be able to locate a file c:\jms-jndi\directory\.bindings with plain-text contents as outlined in the following. As a routine check, you'll find the port/machine name from above.


After configuration using JMSAdmin..
c:\jms-jndi-directory\.bindings

#This file is used by the JNDI FSContext.
#Sun Aug 14 16:56:00 CEST 2005
TOPSECURITY_QUEUE/ClassName=com.ibm.mq.jms.MQQueue
TOPSECURITY_QUEUE/FactoryName=com.ibm.mq.jms.MQQueueFactory
TOPSECURITY_QUEUE/RefAddr/0/Content=6
TOPSECURITY_QUEUE/RefAddr/0/Encoding=String
TOPSECURITY_QUEUE/RefAddr/0/Type=VER
TOPSECURITY_QUEUE/RefAddr/1/Content=-2
TOPSECURITY_QUEUE/RefAddr/1/Encoding=String
TOPSECURITY_QUEUE/RefAddr/1/Type=EXP
TOPSECURITY_QUEUE/RefAddr/2/Content=-2
TOPSECURITY_QUEUE/RefAddr/2/Encoding=String
TOPSECURITY_QUEUE/RefAddr/2/Type=PRI
TOPSECURITY_QUEUE/RefAddr/3/Content=-2
TOPSECURITY_QUEUE/RefAddr/3/Encoding=String
TOPSECURITY_QUEUE/RefAddr/3/Type=PER
TOPSECURITY_QUEUE/RefAddr/4/Content=1208
TOPSECURITY_QUEUE/RefAddr/4/Encoding=String
TOPSECURITY_QUEUE/RefAddr/4/Type=CCS
TOPSECURITY_QUEUE/RefAddr/5/Content=0
TOPSECURITY_QUEUE/RefAddr/5/Encoding=String
TOPSECURITY_QUEUE/RefAddr/5/Type=TC
TOPSECURITY_QUEUE/RefAddr/6/Content=273
TOPSECURITY_QUEUE/RefAddr/6/Encoding=String
TOPSECURITY_QUEUE/RefAddr/6/Type=ENC
TOPSECURITY_QUEUE/RefAddr/7/Content=1
TOPSECURITY_QUEUE/RefAddr/7/Encoding=String
TOPSECURITY_QUEUE/RefAddr/7/Type=FIQ
TOPSECURITY_QUEUE/RefAddr/8/Content=TOPSECURITY.QUEUE
TOPSECURITY_QUEUE/RefAddr/8/Encoding=String
TOPSECURITY_QUEUE/RefAddr/8/Type=QU
TOPSECURITY_QUEUE/RefAddr/9/Content=BEAQM
TOPSECURITY_QUEUE/RefAddr/9/Encoding=String
TOPSECURITY_QUEUE/RefAddr/9/Type=QMGR
TOPSECURITY_XAQCF/ClassName=com.ibm.mq.jms.MQXAQueueConnectionFactory
TOPSECURITY_XAQCF/FactoryName=com.ibm.mq.jms.MQXAQueueConnectionFactoryFactory
TOPSECURITY_XAQCF/RefAddr/0/Content=6
TOPSECURITY_XAQCF/RefAddr/0/Encoding=String
TOPSECURITY_XAQCF/RefAddr/0/Type=VER
TOPSECURITY_XAQCF/RefAddr/1/Content=1
TOPSECURITY_XAQCF/RefAddr/1/Encoding=String
TOPSECURITY_XAQCF/RefAddr/1/Type=TRAN
TOPSECURITY_XAQCF/RefAddr/10/Content=false
TOPSECURITY_XAQCF/RefAddr/10/Encoding=String
TOPSECURITY_XAQCF/RefAddr/10/Type=SFIPS
TOPSECURITY_XAQCF/RefAddr/11/Content=false
TOPSECURITY_XAQCF/RefAddr/11/Encoding=String
TOPSECURITY_XAQCF/RefAddr/11/Type=SPAG
TOPSECURITY_XAQCF/RefAddr/12/Content=true
TOPSECURITY_XAQCF/RefAddr/12/Encoding=String
TOPSECURITY_XAQCF/RefAddr/12/Type=UCP
TOPSECURITY_XAQCF/RefAddr/13/Content=5000
TOPSECURITY_XAQCF/RefAddr/13/Encoding=String
TOPSECURITY_XAQCF/RefAddr/13/Type=PINT
TOPSECURITY_XAQCF/RefAddr/14/Content=10
TOPSECURITY_XAQCF/RefAddr/14/Encoding=String
TOPSECURITY_XAQCF/RefAddr/14/Type=MBS
TOPSECURITY_XAQCF/RefAddr/15/Content=1
TOPSECURITY_XAQCF/RefAddr/15/Encoding=String
TOPSECURITY_XAQCF/RefAddr/15/Type=FIQ
TOPSECURITY_XAQCF/RefAddr/16/Content=
TOPSECURITY_XAQCF/RefAddr/16/Encoding=String
TOPSECURITY_XAQCF/RefAddr/16/Type=LA
TOPSECURITY_XAQCF/RefAddr/17/Content=5000
TOPSECURITY_XAQCF/RefAddr/17/Encoding=String
TOPSECURITY_XAQCF/RefAddr/17/Type=RINT
TOPSECURITY_XAQCF/RefAddr/18/Content=true
TOPSECURITY_XAQCF/RefAddr/18/Encoding=String
TOPSECURITY_XAQCF/RefAddr/18/Type=TCM
TOPSECURITY_XAQCF/RefAddr/19/Content=SYSTEM.DEFAULT.MODEL.QUEUE
TOPSECURITY_XAQCF/RefAddr/19/Encoding=String
TOPSECURITY_XAQCF/RefAddr/19/Type=TM
TOPSECURITY_XAQCF/RefAddr/2/Content=BEAQM
TOPSECURITY_XAQCF/RefAddr/2/Encoding=String
TOPSECURITY_XAQCF/RefAddr/2/Type=QMGR
TOPSECURITY_XAQCF/RefAddr/20/Content=
TOPSECURITY_XAQCF/RefAddr/20/Encoding=String
TOPSECURITY_XAQCF/RefAddr/20/Type=TQPFX
TOPSECURITY_XAQCF/RefAddr/21/Content=1
TOPSECURITY_XAQCF/RefAddr/21/Encoding=String
TOPSECURITY_XAQCF/RefAddr/21/Type=MRET
TOPSECURITY_XAQCF/RefAddr/3/Content=semp20
TOPSECURITY_XAQCF/RefAddr/3/Encoding=String
TOPSECURITY_XAQCF/RefAddr/3/Type=HOST
TOPSECURITY_XAQCF/RefAddr/4/Content=1421
TOPSECURITY_XAQCF/RefAddr/4/Encoding=String
TOPSECURITY_XAQCF/RefAddr/4/Type=PORT
TOPSECURITY_XAQCF/RefAddr/5/Content=SYSTEM.DEF.SVRCONN
TOPSECURITY_XAQCF/RefAddr/5/Encoding=String
TOPSECURITY_XAQCF/RefAddr/5/Type=CHAN
TOPSECURITY_XAQCF/RefAddr/6/Content=819
TOPSECURITY_XAQCF/RefAddr/6/Encoding=String
TOPSECURITY_XAQCF/RefAddr/6/Type=CCS
TOPSECURITY_XAQCF/RefAddr/7/Content=\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000
TOPSECURITY_XAQCF/RefAddr/7/Encoding=String
TOPSECURITY_XAQCF/RefAddr/7/Type=CT
TOPSECURITY_XAQCF/RefAddr/8/Content=0
TOPSECURITY_XAQCF/RefAddr/8/Encoding=String
TOPSECURITY_XAQCF/RefAddr/8/Type=CTO
TOPSECURITY_XAQCF/RefAddr/9/Content=0
TOPSECURITY_XAQCF/RefAddr/9/Encoding=String
TOPSECURITY_XAQCF/RefAddr/9/Type=SRC



If your .bindings file looks messy, you can do a sort <.bindings>.bindings.sorted to obtain a better structure. It won't affect the functionality - and looks a lot nicer. Please take notice of "TRAN=1" which is caused by the setting "transport(CLIENT)" or "tran(CLIENT)". That's the only possiblity when not connecting to MQ from the same machine with the MQ installation. Now, the MQ should be set up to facilitate communications. We need a MDB and client to perform our operations...


From MQ to Weblogic: the MDB code - pritty much as simple as it gets
TopsecurityMDB.java

package dk.topsecurity;

import weblogic.rmi.RemoteException;

import javax.ejb.*;
import javax.jms.*;
import javax.naming.*;

/**
 * The message bean, which - through external JNDI provider - is using a 
 * context factory, that uses IBM mq classes - and treats the MQ as an 
 * external JMS provider.
 *
 */
public class TopsecurityMDB implements MessageDrivenBean, MessageListener {

  public void ejbActivate() { System.out.println("ejbActivate called"); }

  public void ejbRemove() { System.out.println("ejbRemove called"); }

  public void ejbPassivate() { System.out.println("ejbPassivate called"); }

  public void ejbCreate () throws CreateException { System.out.println("ejbCreate called"); }

  public void setMessageDrivenContext(MessageDrivenContext ctx) {
    System.out.println("setMessageDrivenContext called");
    m_context = ctx;
  }

  /**
   * onMessage required by the MessageListener interface - receives messages
   * from the external JMS provider
   */
  public void onMessage(Message msg) {
    TextMessage tm = (TextMessage) msg;
    try {
      String text = tm.getText();
      System.out.println("Received message from JMS provider : " + text);
    }
    catch(JMSException ex) {
      ex.printStackTrace();
    }
  }

  private MessageDrivenContext m_context;
}



The generic bean descriptor..

ejb-jar.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>TopsecurityMDB example1</ejb-name>
      <ejb-class>dk.topsecurity.TopsecurityMDB</ejb-class>
      <transaction-type>Container</transaction-type>
      <message-driven-destination>
        <destination-type>javax.jms.Queue</destination-type>
      </message-driven-destination>
    </message-driven>
    <message-driven>
      <ejb-name>TopsecurityMDB example2</ejb-name>
      <ejb-class>dk.topsecurity.TopsecurityMDB</ejb-class>
      <transaction-type>Container</transaction-type>
      <message-driven-destination>
        <destination-type>javax.jms.Queue</destination-type>
      </message-driven-destination>
    </message-driven>
  </enterprise-beans>
  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>TopsecurityMDB example1</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
    <container-transaction>
      <method>
        <ejb-name>TopsecurityMDB example2</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
  </assembly-descriptor>
</ejb-jar>



... the weblogic specific descriptor...

weblogic-ejb-jar.xml

<?xml version="1.0"?>
<!DOCTYPE weblogic-ejb-jar PUBLIC "-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB//EN" "http://www.bea.com/servers/wls600/dtd/weblogic-ejb-jar.dtd">
<!-- Sample MessageDriven bean Weblogic deployment descriptor -->
<weblogic-ejb-jar>
  <weblogic-enterprise-bean>
    <ejb-name>TopsecurityMDB example1</ejb-name>
    <message-driven-descriptor>
      <pool>
        <max-beans-in-free-pool>5</max-beans-in-free-pool>
        <initial-beans-in-free-pool>2</initial-beans-in-free-pool>
      </pool>
      <destination-jndi-name>TOPSECURITY_QUEUE</destination-jndi-name>
      <initial-context-factory>com.sun.jndi.fscontext.RefFSContextFactory</initial-context-factory>
      <provider-url>file:/C:/jms-jndi-directory</provider-url>
      <connection-factory-jndi-name>TOPSECURITY_XAQCF</connection-factory-jndi-name>
    </message-driven-descriptor>
    <jndi-name>TopsecurityMDB1</jndi-name>
  </weblogic-enterprise-bean>
  <weblogic-enterprise-bean>
    <ejb-name>TopsecurityMDB example2</ejb-name>
    <message-driven-descriptor>
      <destination-jndi-name>TOPSECURITY_QUEUE</destination-jndi-name>
      <initial-context-factory>com.sun.jndi.fscontext.RefFSContextFactory</initial-context-factory>
      <provider-url>file:/C:/jms-jndi-directory</provider-url>
      <connection-factory-jndi-name>TOPSECURITY_XAQCF</connection-factory-jndi-name>
    </message-driven-descriptor>
    <jndi-name>TopsecurityMDB2</jndi-name>
  </weblogic-enterprise-bean>
</weblogic-ejb-jar>

... and the minor change necessary for config.xml in order to run the sample (unless you're running in development mode with hot-deployment - and just need to drop the .jar file in the applications direcotry)... In my case, it's obvious I'm using a Weblogic installtion with application directory: C:\bea\user_projects\domains\mqtest\applications.

config.xml

...
    <Application Name="_appsdir_TopsecurityMQ_jar"
        Path="C:\bea\user_projects\domains\mqtest\applications"
        StagedTargets="myserver" StagingMode="stage" TwoPhase="true">
        <EJBComponent Name="TopsecurityMQ" Targets="myserver" URI="TopsecurityMQ.jar"/>
    </Application>
...

We need a client to initiate a stream of messages processed by MQ and the Weblogic server... Check out the shaded area for required authentication. Will be explained in another document.


From J2EE stand-alone client to MQ
TopsecurityMQXAClient.java

package dk.topsecurity;

import javax.jms.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.*;
import com.ibm.mq.jms.*;

import javax.transaction.xa.Xid;
import javax.transaction.xa.XAResource;


public class TopsecurityMQXAClient implements ExceptionListener {

/** 
 * Setting up authorisation username. Used by classes in com.ibm.mqjms.jar
 * Setting up queue connection factory (QCF)
 * Setting up name of queue, as defined in the MQ setup
 * Setting up url for file-based, external JNDI provider 
 * Setting up context factory to use with external JNDI
 */

  public String mq_username = "noname"; //"Administrator";
  public String mq_qcf = "TOPSECURITY_XAQCF";
  public String mq_qname = "TOPSECURITY_QUEUE";
  public String mq_url = "file:/C:/jms-jndi-directory";
  public String mq_jndi =  "com.sun.jndi.fscontext.RefFSContextFactory";

/**
 * main method - binding to the Websphere MQ installation - and delivering a
 * number of messages.
 */
 
  public static void main(String[] args) {

    TopsecurityMQXAClient sender = null;
    try {
      sender = new TopsecurityMQXAClient();
      sender.setupQueueConnection();
      for(int i=0;;i++) {
        sender.send(sender.setMessage("Hello no "+i+" from client at "+new Date()));
        Thread.sleep(1000L);
      }
    }
    catch(JMSException je) {
      System.out.println("Caught JMSException: "+je);
      Exception le = je.getLinkedException();
      if (le != null) 
        System.out.println("Linked exception: "+le);
      je.printStackTrace();
    } catch(Exception e) {
       e.printStackTrace();
     } finally {
      try {
      if (sender != null)
        sender.cleanup();
      } catch (Exception e) { }
    }
  }

  private void setupQueueConnection() throws Exception {

    //set the username which to use for authentication
    System.out.println("Initial user.name="+System.getProperty("user.name"));
    System.setProperty("user.name",mq_username);
    System.out.println("Authrorisation required user.name="+System.getProperty("user.name"));


    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, mq_jndi);
    env.put(Context.PROVIDER_URL, mq_url);
//    env.put(Context.SECURITY_PRINCIPAL, "Administrator");

    InitialDirContext ctx = new InitialDirContext(env);
    com.ibm.mq.jms.MQXAQueueConnectionFactory factory =
            (com.ibm.mq.jms.MQXAQueueConnectionFactory)ctx.lookup(mq_qcf);

    System.out.println("Factory = " +factory);

    /* Create a QueueConnection, QueueSession
     * When a connection is made, use the createQueueSession method on the
     * QueueConnection to obtain a session. Parameters: 
     * boolean= determines whether the session is transacted or non-transacted.
     * int =  that determines the acknowledge mode.
     * Simplest case is that of the non-transacted session with AUTO_ACKNOWLEDGE
     * - p319 in the IBM redbook.
     */
    xaconnection = factory.createXAQueueConnection();
    xasession = xaconnection.createXAQueueSession();
    QueueSession normalsession = xasession.getQueueSession();

   ioQueue = (Queue)ctx.lookup(mq_qname);

    queueSender = normalsession.createSender(ioQueue);

/* //we only use this when we want to receive messages transactionally
    xaconnection.start();
*/
    xaconnection.setExceptionListener(this);
  }


  /**
   * For test purpose, create one of many possible types of messages: 
   * BytesMessage, MapMessage, ObjectMessage, StreamMessage
   */
  TextMessage setMessage(String text) throws Exception {

    TextMessage msg = xasession.createTextMessage();
    msg.setText(text);
    return(msg);
  }

  /**
   * Send message off to MQ
   */
  void send(TextMessage msg) throws Exception {

    System.out.println("To " + ioQueue.getQueueName() + " sending message=" + msg.getText());

    XAResource xares = xasession.getXAResource();
    Xid xid = new XidImpl(102);

    xares.start(xid, XAResource.TMNOFLAGS);

    System.out.println("Sending the message on queue " + ioQueue.getQueueName());
    try {
      queueSender.send(msg);
      System.out.println("sending successfull");
    } catch(Exception ex) {
      System.out.println("sending unsuccessfull");
      System.out.println(ex);
    }

    xares.end(xid,XAResource.TMNOFLAGS);
    //xares.prepare(xid);
    xares.commit(xid, true);
    System.out.println("sending completed");

  }

  public void onException(JMSException jms) {
    System.out.println("onException: jms" + jms);
    jms.printStackTrace();
  }

  void cleanup() throws Exception {
    if (xasession != null) {
      xasession.close();
      xasession = null;
    }
    if (xaconnection != null)
      xaconnection.close();
      xaconnection = null;
  }

  private Queue ioQueue;
  private XAQueueSession xasession;
  private XAQueueConnection xaconnection;
  private XAQueueConnectionFactory factory;
  private QueueSender queueSender;
  private InitialContext ctx;
  private TextMessage msg;

  static class XidImpl implements Xid {
     private byte _branch[] = new byte[64];
     private byte _global[] = new byte[64];
                                                                          
     public XidImpl(int id) {
       _branch[60] = (byte) ((id <<< 24) & 0xFF);
       _branch[61] = (byte) ((id <<< 16) & 0xFF);
       _branch[62] = (byte) ((id <<<  8) & 0xFF);
       _branch[63] = (byte) ( id         & 0xFF);
     }
                                                                          
     public byte[] getGlobalTransactionId() { return _global; }
                                                                          
     public byte[] getBranchQualifier() { return _branch; }
                                                                          
     public int getFormatId() { return 0; }
  }


}



From here on, you have basicly two choices: First solution is simple and usually get people quickly from idea to working solution - but it makes it impossible to simultaneously support MQ 5.2.1 / 5.3 / 6.0 in a single environment. Naturally, I prefere the last solution.

In order to compile the example, you only need the first two of the usual set of jar-files. But in order to run the stand-alone client, you better get hold of them all. Put them into the library .\mqlib in the build environment. From there they will be extracted by out ant build-script and included into the finally built jar-file containing the MDB application. That will ensure including at the lowest possible class-loader level.



To turn the sources into a deplayable entity, an ant script "build.xml" is provided. It requires setting of environment variable WL_HOME into the script.

build.xml

<project name="TopsecurityMQ" default="all" basedir=".">

  <target name="init">
    <property name="wl_home" value="C:/bea/weblogic81"/>

    <property environment="env"/>
    <property name="JAVAC" value="modern"/>
    <property name="build.compiler" value="${JAVAC}"/>
    <property name="source" value="./src"/>
    <property name="compiledir" value="./build"/>
    <property name="mqlibdir" value="./mqlib"/>
    <property name="earstage" value="./earstage"/>
    <property name="project_name"   value="TopsecurityMQ"/>
    <property name="mqjava" value="${mqlibdir}/com.ibm.mq.jar"/>
    <property name="mqjms"  value="${mqlibdir}/com.ibm.mqjms.jar"/>
  </target>

  <target name="all" depends="init, clean, compile, buildjar, ejbc"/>

  <target name="clean" depends="init">
    <!-- Create the time stamp -->
    <tstamp/>
    <delete dir="${compiledir}" />
    <mkdir dir="${compiledir}"/>
    <mkdir dir="${compiledir}/META-INF"/>
    <delete dir="${earstage}" />
    <mkdir dir="${earstage}" />
    <mkdir dir="${earstage}/META-INF" />
  </target>

  <target name="compile" depends="clean">
    <javac srcdir="${source}" destdir="${compiledir}" 
      classpath="${wl_home}\server\lib\weblogic.jar;${mqjava};${mqjms}" includes="**/*.java"/>
  </target>

  <target name="buildjar" depends="compile">
    <copy file="${source}/ejb-jar.xml" todir="${compiledir}/META-INF" overwrite="yes"/>
    <copy file="${source}/weblogic-ejb-jar.xml" todir="${compiledir}/META-INF" overwrite="yes"/>

<unzip dest="${compiledir}">
    <fileset dir="${mqlibdir}">
        <include name="**/*.jar"/>
        <exclude name="**/weblogic*.jar"/>
    </fileset>
</unzip>

    <jar jarfile="${compiledir}/${project_name}.jar"
      basedir="${compiledir}" includes="**/TopsecurityMDB*.class,**/*.xml,com/**/*.class,*.properties"
      update="yes">
      <manifest>
        <attribute name="Built-By" value="${user.name}"/>
      </manifest>
    </jar>
    <jar jarfile="${earstage}/${project_name}_client.jar"
      basedir="${compiledir}"  includes="**/TopsecurityMQ*Client*.class"
      update="yes">
    </jar>
  </target>
  <target name="ejbc" depends="buildjar">
    <java classname="weblogic.ejbc" fork="yes" failonerror="yes" classpath="${wl_home}\server\lib\weblogic.jar">
      <sysproperty key="weblogic.home" value="${compiledir}"/>
      <arg line="-compiler javac ${compiledir}/${project_name}.jar ${earstage}/${project_name}.jar"/>
    </java>
  </target>
  
</project>

In case you're wondering, how environment may look like, I can ensure you, that you need no MQ jar-files in global classpath - or MQ-installation-ddl-file in the executable path to complete this assignment. At no point are you required to install MQ or the MQ ETC at the client machine.

Enough talk, do the compilation.. (yeah, I compile an extra class)

compile console snaphot

If you check out the files in .\earstage you'll find a small one (the client) and a big one (the bean). I know it's maybe cleaner to build an ear file and pack the com.ibm.mq*.jar classes individually into that. But here, we've kept the mq classes at the lowest classloader level - with the bean only.

compile console snaphot

Since we're not concerned about transactional parts, we've left out transactional settings - which the compilers complains somewhat about. No worries about that. The deployment..

Weblogic startup console snapshot

First - test the MDB put using the Websphere MQ navigatior to put message on queue:

Websphere MQ navigator message control

Websphere MQ navigator message administrator

Weblogic console snapshot of response to MQ manipulation

And running the client (stop with Ctrl-break)...

send-tx.cmd

set BEA_HOME=C:\bea
set WL_HOME=C:\bea\weblogic81
java -classpath .;.\earstage\TopsecurityMQ_client.jar;.\mqlib\weblogic.jar;.\mqlib\com.ibm.mqetclient.jar;.\mqlib\com.ibm.mq.jar;.\mqlib\com.ibm.mqjms.jar;.\mqlib\fscontext.jar;.\mqlib\providerutil.jar;.\mqlib\dbhcore.jar;.\TopsecurityMQ_client.jar   dk/topsecurity/TopsecurityMQXAClient



MQ client console snapshot

and the response from the MDB... (circle is completed)

Weblogic console snapshot of response to console client

So... what basicly happens is that the command-line client (knowing nothing about Weblogic) sends off messages directly to MQ using support layer jar-files. Once messages have arrived into MQ, the MDB from Weblogic grabs them and displays their contents.

You can also stop the Weblogic application server and browse the messages directly with the MQ navigator.

Basicly this example demonstrates most basic aspects of MQ interfacing :