J2EE applications that use Java Messaging Service (JMS) messaging are common, and there's plenty of documentation on how to make them work well. What is less well-documented is how to make a Java 2 Standard Edition (J2SE) application -- one without the benefits of an application server -- using a JMS messaging provider. This article shows how to make a standalone Java application work with WebSphere MQ as a JMS and JNDI client. Such an application can still take advantage of JMS asynchronous messaging without having to be deployed in a J2EE application server, such as IBM WebSphere Application Server.
The first question one might ask is: Why configure a standalone application to use asynchronous messaging? J2SE is designed for developing simple applications that usually run in a single Java virtual machine (JVM) on one computer. The applications that generally use messaging are developed on the Java 2 Enterprise Edition (J2EE) platform, which provides a variety of services for enterprise applications, including messaging. Messaging is provided by JMS, which includes a standard API for accessing messaging systems. JMS applications also use the Java Naming and Directory Interface (JNDI) API to access the messaging system's managed resources, namely connection factories and destinations.
Even an application designed to run for a single user on the desktop may need to integrate with other applications and services. Such an application can benefit from using asynchronous messaging to do so, and, as a Java application, should use the JMS API (with JNDI) to perform messaging.
You may already have an application written that uses JMS and JNDI. This article includes a download file containing a simple example of JMS clients which run via main() methods. While this is hardly a useful application, it is adequate to demonstrate messaging. We will walk through how we modified the sample application to work with WebSphere MQ; you would make similar changes to your application.
The sample application works much like a J2EE program in that it uses JNDI to access managed resources (connection factories and destinations) from the JMS provider, and uses JMS to send and receive messages. (The application does not use message-driven beans because those are a type of Enterprise JavaBean™, and would require this application to be a J2EE application.)
The configuration shown in this article makes the following assumptions:
- You are using WebSphere MQ V5.3 for Microsoft® Windows®. Versions for other platforms should work as well but have not been tested.
- WebSphere MQ is installed on your local machine (which is referred to in the
- Your WebSphere MQ installation has a queue manager named
QMGRwhose TCP listener is running on port
If your WebSphere MQ installation is different, you will need to modify these instructions and samples accordingly.
First we will look at how to set up point-to-point messaging using queues. Configuring the application and the messaging system requires the following steps:
- Obtain and install support pacs for WebSphere MQ.
- Modify your application's JNDI code to use the support pacs.
- Modify the administration tool to use the support pacs.
- Configure WebSphere MQ with the necessary JMS resources.
- Create or modify an application execution script that uses the support pacs.
- Run the application.
The code modifications necessary are minimal, and in fact can be limited to
jndi.properties file if your code uses one.
The main change related to your code is to modify the script for running the code
so that it has the necessary Java application resource (JAR) files on its
This example uses WebSphere MQ Version 5.3. Out of the box, this version does not
provide everything you need to support a JMS program. It includes an
implementation of the JMS interface, but not the JNDI interface. To add support
for JNDI to WebSphere MQ, you need to install support pac
ME01 (WebSphere MQ Initial Context), which in turn
requires support pac
MS0B (MQSeries Java classes for
PCF). (See Resources.)
To install these support pacs, simply unzip them. Each contains a JAR file you'll
need later. (The sample scripts assume you add the JAR files to the WebSphere MQ
Java\lib directory.) Other than making sure you have
the JAR files available and reading the accompanying documentation, there's no
further installation to perform.
In a J2EE application, using JNDI is pretty easy. You simply create an
InitialContext (with no parameters) and start using it.
This is because the J2EE container manages the JNDI contexts, including the one
for the component (Web application or EJB class) that contains your code.
For a J2SE (standalone) application, there is no J2EE container managing the JNDI contexts, just a simpler J2SE container (basically a plain JVM). The component model is much simpler -- no Web applications, no EJBs -- so all code has the same JNDI context. Therefore, establishing an initial JNDI context requires more work in J2SE.
In J2EE, you can usually simply say:
Context context = new InitialContext();
with no parameters and get the JNDI context you need.
In J2SE, creating the initial context is a little more difficult. You need to use
a different constructor,
Properties env = new Properties(); // fill in the context properties Context context = new InitialContext(env);
The context properties tell JNDI what context you want so that it can create the right one for you. In this case, we want one for accessing WebSphere MQ, namely the instance we have installed. To do so, we use code like this:
Properties env = new Properties(); env.put( Context.INITIAL_CONTEXT_FACTORY, "com.ibm.mq.jms.context.WMQInitialContextFactory"); env.put(Context.PROVIDER_URL, "localhost:1414/SYSTEM.DEF.SVRCONN"); Context context = new InitialContext(env);
This code sets a pair of context properties:
The name of the class JNDI we will use to create the InitialContext. Because we want to access WebSphere MQ through JNDI, the initial context factory we use is a WebSphere MQ class. (This class is provided by the ME01 support pac described above.)
Specifies how to find our running WebSphere MQ installation. Much like the URL for an HTML file or a JDBC data source, the information in this URL tells JNDI how to find and access WebSphere MQ using the implementation provided by the support pac.
Your PROVIDER_URL may need to differ from the value shown here. If your WebSphere
MQ install is on a different computer from the one you will run your client
application on, you need to change
localhost to the
hostname or IP address of the WebSphere MQ machine. Likewise, port
1414 is the default listener port number for the first
queue manager in WebSphere MQ. If your install's port number is different, or you
want to use a different queue manager, you need to specify its port.
And that's it. That's all the code you need to change, the code for instantiating
an initial JNDI context. From there, your code works the same. It uses JNDI to
access the JMS connection factory and JMS queue, and uses them to send and receive
messages. You can even store these JNDI context properties in a properties file
(the standard name is
jndi.properties) and then modify
them without having to change (and recompile and re-JAR) any code at all.
The JMS administration tool for WebSphere MQ is called
JMSAdmin.bat, located in the
Java\bin directory of the MQ install directory. It
needs to be modified to use the
ME01 support pacs.
Modify the script's classpath to add the support pacs'
mqcontext.jar JAR files, something like this (if the
JAR files were in the bin directory, which isn't really a good place):
The script will use the new classpath when it runs the administration class,
The JMS administration tool's configuration file,
JMSAdmin.config, also needs to be modified. Add lines
to the file (and comment out any corresponding lines) to make the following
Again, the URL for your installation may be different. In any case, these values are the same as what you used in your application's JNDI code. (JMSAdmin is just another WebSphere MQ client, just like your application.)
The JMS administration tool runs interactively, but it is easier to have it process a script that can be edited and run repeatedly. The script's filename can be anything; by convention, the extension is .scp. In this example, the filename is sampleconfig.scp. The two lines of interest right now are these:
def qcf(SampleQCF) qmgr(QMGR) tran(client) chan(SYSTEM.DEF.SVRCONN) + host(localhost) port(1414) def q(SampleQueue) qmgr(QMGR) qu(SAMPLE.QUEUE)
These two lines create a
javax.jms.QueueConnectionFactory with the JNDI name
SampleQCF and a
SampleQueue. This script assumes the queue manager is
QMGR; modify the script if your queue manager is
named differently. Like the
PROVIDER_URL value used
earlier, if your install is running on a different machine or your queue manager
is running on a different port, you will need to modify these settings in your
Once the script is ready, you run it from a command line like this:
C:\WebSphere MQ\Java\bin> JMSAdmin -v < sampleconfig.scp
In the WebSphere MQ Explorer, you should now see a queue named SampleQueue in the Console Root\WebSphere MQ\Queue Managers\QMGR\Queues folder.
The sample scripts for running the JMS clients require these items in the classpath:
- JMS API:
- J2EE Connector API:
- WebSphere MQ client:
- WebSphere MQ JMS implementation:
- MS0B support pac JAR file:
- ME01 support pac JAR file:
As explained earlier, the application's JNDI code must set the
PROVIDER_URL values. If those settings are being read
from a jndi.properties file, it will need to be in the application's classpath as
Now we're ready to test the application. Open two command windows, one for the
sender and one for the receiver. Go to the directory with the sample code, and run
the sender and receiver. Then type in a message like,
this is a test. You should see this in the sender
C:\standalonewmq> StandaloneSender java -cp "standalonewmq.jar;. . ." com.ibm.examples.StandaloneSender Sender started. Enter a message: this is a test Sent message <this is a test> with ID <ID:414d5120. . .20005001> Enter a message: Sender stopped. C:\standalonewmq>
And this is what you should see in the receiver window:
C:\standalonewmq> StandaloneReceiver java -cp " standalonewmq.jar;. . ." com.ibm.examples.StandaloneReceiver Receiver started. Received message <this is a test> with ID <ID:414d5120. . .20005001> Receiver stopped. C:\standalonewmq>
The result shows that a message containing
this is a test with an ID ending in
20005001 was sent and received. The example works.
The sample application also includes a publisher and subscriber for a topic. This publish/subscribe example assumes you have already done the setup for point-to-point messaging. The following additional steps are required:
- Obtain and install the publish/subscribe support pac for WebSphere MQ.
- Configure WebSphere MQ for publish/subscribe and start the broker.
- Configure WebSphere MQ with the necessary JMS resources.
- Create or modify an application execution script.
- Run the application.
We already performed the other steps when we setup WebSphere MQ for the point-to-point part of the example.
WebSphere MQ V5.3 does not include support for publish/subscribe. For that, you
need to add support pac
MA0C (WebSphere MQ (MQSeries) -
The latest fix packs for WebSphere MQ V5.3 (such as Fix Pack 8, CSD08) include MA0C, so if you already have a recent fix pack installed, you can skip installing MA0C. If you're not sure whether or not you have the support pac installed, go ahead and try to install it. If it is already installed, the installer will simply tell you so and then automatically exit.
To install the support pac, download it (see Resources), run it, and follow the instructions in the wizard.
Once you have the publish/subscribe support pac installed, you need to configure and start it. At this point, if you were to try running the publisher or subscriber (go ahead and try, if you like), you would get this error:
javax.jms.JMSException: MQJMS5087: Unexpected error 2085 accessing internal queue SYSTEM.JMS.REPORT.QUEUE
This error indicates that the internal queues WebSphere MQ requires to support
JMS publish/subscribe have not been created. To create these queues, run the
runmqsc in the WebSphere MQ bin directory (not
the Java\bin directory) with the configuration file
MQJMS_PSQ.mqsc on the appropriate queue manager (again,
assuming your queue manager is named QMGR). When you run the command, you should
see output like this:
C:\WebSphere MQ\bin> runmqsc QMGR < MQJMS_PSQ.mqsc . . . 8 MQSC commands read. No commands have a syntax error. All valid MQSC commands were processed.
Make sure the queue manager's publish/subscribe broker is running. To check, run
dspmqbrk command. It's probably not running, so the
output looks like this:
C:\WebSphere MQ\bin> dspmqbrk -m QMGR MQSeries Publish/Subscribe broker for queue manager QMGR not active
To start it, run the command
C:\WebSphere MQ\bin> strmqbrk -m QMGR MQSeries Publish/Subscribe broker started for queue manager QMGR.
If you run
dspmqbrk again, this time it should say
that the broker is running. (You can stop it later by running
endmqbrk -m QMGR.)
We now need to configure WebSphere MQ with a topic connection factory and a
topic. If you already ran the
C:\WebSphere MQ\Java\bin> JMSAdmin -v < sampleconfig.scp
then you have already created these resources and don't need to run it again. But let's take a look at what this part of the script is doing. The two relevant lines from the configuration script are these (again, assuming your queue manager is named QMGR):
def tcf(SampleTCF) qmgr(QMGR) def t(SampleTopic) topic(sampletopic)
The first line creates a
javax.jms.TopicConnectionFactory registered in JNDI
under the name
SampleTCF. The second line creates a
The sample scripts for running the JMS clients must have the classpath items listed for point-to-point. In addition, the publish/subscribe support uses XA (that is, distributed transactions), so the scripts also need this item in the classpath:
- the JTA API:
We are now ready to test publishing. Open three command windows, one for the
publisher and two for two subscribers. Go to the directory with the sample code,
and run the publisher and subscribers. Then type in a message, like
broadcast this and you should see this in the publisher
C:\standalonewmq> StandalonePublisher java -cp "standalonewmq.jar;. . ." com.ibm.examples.StandalonePublisher Publisher started. Enter a message: broadcast this Published message <broadcast this> with ID <ID:414d5120. . .20005b02> Enter a message: Publisher stopped. C:\standalonewmq>
You should see this in one subscriber window:
C:\standalonewmq> StandaloneSubscriber java -cp "standalonewmq.jar;. . ." com.ibm.examples.StandaloneSubscriber Subscriber started. Received message <broadcast this> with ID <ID:414d5120. . .20002406> Subscriber stopped. C:\standalonewmq>
And this in the other subscriber window:
C:\standalonewmq> StandaloneSubscriber java -cp "standalonewmq.jar;. . ." com.ibm.examples.StandaloneSubscriber Subscriber started. Received message <broadcast this> with ID <ID:414d5120. . .20002407> Subscriber stopped. C:\standalonewmq>
The single published message was sent to both subscribers. Each subscriber's message has a different ID because each subscriber gets its own copy of the message.
In this article, we've seen how a J2SE application can use WebSphere MQ using JMS and JNDI, without needing to be deployed in a J2EE container (such as WebSphere Application Server). We have seen:
- How to get the proper JNDI initial context.
- How to set the classpath appropriately using the JAR files included with WebSphere MQ.
- What support pacs you need and how to use them.
- How to configure WebSphere MQ.
- How to administer WebSphere MQ resources so that they can be accessed as JMS resources using JNDI.
You are now prepared to convert your existing applications and develop new ones.
Trial version of WebSphere MQ 5.3
WebSphere Business Integration - Event Broker (WBI-EB)
WebSphere Business Integration - Message Broker (WBI-MB)
IBM WebSphere MQ support site
- The IBM support site for all
pac MS0B - MQSeries Java classes for PCF
pac ME01 - WebSphere MQ - Initial Context Factory
Java Technology - Java 2 Platform, Standard Edition (J2SE)
Core Java - Java Naming and Directory Interface (JNDI)
Java Technology - Java 2 Platform, Enterprise Edition (J2EE)
J2EE - Java Message Service (JMS)
J2EE - Enterprise JavaBeans Technology (EJB)
Running a standalone Java application on WebSphere MQ V6.0
WebSphere MQ Using Java (IBM Publication SC34-6066-02; January 2004)
MQSeries Publish/Subscribe Applications (IBM RedBook SG24-6282-00; September 2001)
Introducing the Java Message Service
Creating and Testing a Message-Driven Bean using WebSphere Studio Application Developer
Develop an Asynchronous Logging Framework using log4j with JMS and WebSphere MQ
JMS Topologies and Configurations with WebSphere Application Server and WebSphere Studio Version 5
JMS Applications with WebSphere Studio V5 -- Part 1: Developing a JMS Point-to-Point Application
JMS Applications with WebSphere Studio V5 -- Part 2: Developing a JMS Publish-Subscribe Application
JMS Applications with WebSphere Studio V5 -- Part 3: Developing a Publish-Subscribe Message-Driven Bean
Writing a standalone JMS application with WebSphere Studio V5.1
Developing and Testing Message-driven Bean Applications with the MQ Simulator for Java Developers in WebSphere Studio V5.0
How WebSphere Application Server handles poison messages
Bobby Woolf is a WebSphere J2EE Consultant for IBM Software Services for WebSphere (ISSW). Bobby assists clients in developing applications for WebSphere Application Server using WebSphere Studio Application Developer. He is a co-author of Enterprise Integration Patterns and The Design Patterns Smalltalk Companion. He also has a blog on the IBM developerWorks Web site called J2EE in Practice. Bobby is a frequent conference speaker.