I am trying to develop a JMS standalone application to read and write to a Queue on MQSeries. My boss asked me to use pure java JMS (not ibm.m
The issue here is the requirement that "My boss asked me to use pure java JMS (not ibm.mq lib) to do that." JMS is a specification and each implementation must comply with the API and the semantics, but is free to do whatever they want at a low level. It is always necessary to use the implementation classes provided by the transport vendor. Therefore if you use WebSphere MQ as the transport, you will need to use the IBM MQ JMS classes to write a JMS application.
That said, if you stick with pure JMS API calls you would be able to plug in any transport vendor's classes. This is what is usually intended when you are given requirements such as that mentioned in the original post.
There's an article describing exactly what you are looking to do called Running a standalone Java application on WebSphere MQ V6.0 It uses only the JMS API and it uses JNDI in a local file system (a .bindings file). By swapping out the IBM JMS classes for another vendor and using their JNDI tools you would be able to plug in any JMS transport without changing your code using this approach.
If you want to do the same thing without JNDI, look at the sample programs provided with the MQ client install where you obtained your Java classes. In a UNIX/Linux system these are in /opt/mqm/samp
and on Windows they are in install_dir/tools/jms/samples
. The SimpleRequestor.java
sample has the following code for initializing your connection factory without JNDI:
try {
// Create a connection factory
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
JmsConnectionFactory cf = ff.createConnectionFactory();
// Set the properties
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, "localhost");
cf.setIntProperty(WMQConstants.WMQ_PORT, 1414);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, "SYSTEM.DEF.SVRCONN");
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, "QM1");
Because this approach does not use JNDI, you are required to write code that is not transportable across transport vendors. It is IBM WebSphere MQ specific.
If you grabbed the MQ jars from somewhere and do not have the full install (and thus do not have the samples) you can download it as SupportPac MQC7. The download is free. In general you should use the latest client, even with a back-level queue manager. Obviously you do not get V7 functionality from a V6 QMgr but the JMS implementation in the V7 client is much improved, even for V6 functionality. If for some reason you really must use the V6 client, you can download it as SupportPacMQC6. Whichever client version you use, make sure to use the corresponding Infocenter.
V6 Infocenter
V7 Infocenter
Finally, the landing page with an index for all the SupportPacs is here.
This is fairly common. Here are some examples.
A complete (synchronous) standalone JMS application with TextMessage.
It is IBM WebSphere MQ specific.
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import com.ibm.mq.jms.JMSC;
import com.ibm.mq.jms.MQQueueConnectionFactory;
public class JMSApplicationStandAlone {
public static void main(String[] args) {
try {
/*MQ Configuration*/
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName("localhost");
mqQueueConnectionFactory.setChannel("MQ.CHANNEL");//communications link
mqQueueConnectionFactory.setPort(1416);
mqQueueConnectionFactory.setQueueManager("QUEUE.MGR");//service provider
mqQueueConnectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
/*Create Connection */
QueueConnection queueConnection = mqQueueConnectionFactory.createQueueConnection();
queueConnection.start();
/*Create session */
QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
/*Create response queue */
Queue queue = queueSession.createQueue("QUEUE.RESPONSE");
/*Create text message */
TextMessage textMessage = queueSession.createTextMessage("put some message here");
textMessage.setJMSReplyTo(queue);
textMessage.setJMSType("mcd://xmlns");//message type
textMessage.setJMSExpiration(2*1000);//message expiration
textMessage.setJMSDeliveryMode(DeliveryMode.PERSISTENT); //message delivery mode either persistent or non-persistemnt
/*Create sender queue */
QueueSender queueSender = queueSession.createSender(queueSession.createQueue("QUEUE.REQEST"));
queueSender.setTimeToLive(2*1000);
queueSender.send(textMessage);
/*After sending a message we get message id */
System.out.println("after sending a message we get message id "+ textMessage.getJMSMessageID());
String jmsCorrelationID = " JMSCorrelationID = '" + textMessage.getJMSMessageID() + "'";
/*Within the session we have to create queue reciver */
QueueReceiver queueReceiver = queueSession.createReceiver(queue,jmsCorrelationID);
/*Receive the message from*/
Message message = queueReceiver.receive(60*1000);
String responseMsg = ((TextMessage) message).getText();
queueSender.close();
queueReceiver.close();
queueSession.close();
queueConnection.close();
} catch (JMSException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Note: Replace the configuration values
Typically with JMS you would define the QueueConnectionFactory
in your container via whatever configuration mechanism it makes available then add it to the container's JNDI registry. Each container would have it's own methods for doing that (i.e. Tomcat versus WebSphere).
If you want to forgo JNDI, you could create an instance of com.ibm.mq.jms.MQQueueConnectionFactory directly and set the hostname, port, queueManager, and channel properties on it. You can then use that object as you would an instance of javax.jms.QueueConnectionFactory
since it implements it.
If you don't mind writing WMQ-specific code then you can do
MQConnectionFactory cf = new MQConnectionFactory();
cf.setHostName(HOSTNAME);
cf.setPort(PORT);
cf.setChannel(CHANNEL);
cf.setQueueManager(QMNAME);
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
then usual JMS resources
Connection c = cf.createConnection();
Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue q = s.createQueue("myQueue"); // replace with real queue name
MessageProducer p = s.createProducer(q);
and finally create and send a message
Message m = s.createTextMessage("Hello, World!);
p.send(m);
(i've typed that in off the top of my head so can't rule out a typo, but it's fundamentally correct). If you're really supposed to be using 'pure JMS' - i.e. with no provider-specific objects - then you need to bind a MQConnectionFactory object in JNDI (take a look at the JMSAdmin tool, it's in the docs) then look it up from your application, i.e.
InitialContext ic = new InitialContext(); // or as appropraite
ConnectionFactory cf = (ConnectionFactory)ic.lookup("myMQfactory"); // replace with JNDI name
I can't teach you JMS in a single post, but I can point you to some of the resources that I used to learn it myself: