0

After I went to multiple sites and learned JMS I wrote a JMS standalone client to read messages from a database and send them one by one. I also want to receive message one by one message and then update the database. I need to send a message to a queue and the other application using standard JMS which will consume a TextMessage and whose body will be read as an ISO-8859-1 string. Also they will similarly send reply as a TextMessage. I wrote a for loop to read the message one by one from the DB.

I am new to JMS so could you please correct me whether my below code works properly to read and send messages to a queue and receive and update the DB. Is there any thing I need to change in the JMS Type or any thing I need to correct. Does the for loop work fine?

/*MQ Configuration*/
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName(url);
mqQueueConnectionFactory.setChannel(channel);//communications link
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(qmgr);//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");

int messageCount = 0;

Queue queue = queueSession.createQueue(replytoQueueName);
QueueSender queueSender = null;
QueueReceiver queueReceiver=null;

for (Testbean testBean : testbeanList) {
    String testMessage = testBean.getMessage();                 
    /*Create text message */
    textMessage = queueSession.createTextMessage(testMessage);

    logger.info("Text messages sent: " + messageCount);

    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 = queueSession.createSender(queueSession.createQueue(outputQName));
    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 = queueSession.createReceiver(queue,jmsCorrelationID);

    /*Receive the message from*/
    Message message = queueReceiver.receive(60*1000);
    //   String responseMsg = ((TextMessage) message).getText();

    byte[] by = ((TextMessage) message).getText().getBytes("ISO-8859-1");

    logger.info(new String(by));
    String responseMsg = new String(by,"UTF-8");

    testDAO rmdao = new testDAO();
    rmdao.updateTest(responseMsg, jmsCorrelationID);        

    messageCount += 1;
}

queueSender.close();
queueReceiver.close();
queueSession.close();
queueConnection.close();
JoshMc
  • 10,239
  • 2
  • 19
  • 38
Maxtech
  • 111
  • 16

1 Answers1

2

Couple of things:

  • I would create your QueueSender and the Queue object its sending messages to outside the for loop since they don't appear to be changing.
  • Without the corresponding consumer code it's ultimately impossible to tell if the selector will work or not, but not invoking setCorrelationID() on the message you send looks a bit strange to me. Using the provider-assigned message ID may be a common pattern with IBM MQ request/reply applications, but the general pattern for using a correlation ID is to invoke setJMSCorrelationID() on the sent message. This makes the code more clear and also allows the application to directly control the uniqueness of the correlation ID. This is potentially important for application portability (e.g. if you migrated from IBM MQ to a different JMS provider) since different JMS providers use styles/formats of message ID specific to their particular implementation. Also, regarding the message ID the JMS spec states, "The exact scope of uniqueness is provider defined," which in my opinion is not a strong enough guarantee of uniqueness especially when using something like java.util.UUID.randomUUID().toString() is so simple.
  • You should ensure that you're using an XA transaction for both the JMS & database work so that they are atomic.
  • Close your JMS resources in a finally block.
Justin Bertram
  • 29,372
  • 4
  • 21
  • 43
  • @Maxtech is getting based on the correlationID in the reply being set to the messageID of the original request message. This is a common pattern with IBM MQ request/reply applications. – JoshMc Feb 06 '19 at 18:35
  • Thank you updating your answer. To clarify IBM MQ guarantees if you let it generate the messageID that the messageID will be unique similar to the UUID you reference. You stated that JMS spec states "uniqueness is provider defined", and in this case the provider is IBM MQ. IBM MQ documents this in the Knowledge center. I have an answer to another question "[Get MQ messageId in string format](https://stackoverflow.com/questions/45729239/get-mq-messageid-in-string-format/45741083#45741083)" that I just updated with a link to the IBM documentation on IBM MQ generated messageID uniqueness. – JoshMc Feb 07 '19 at 00:18
  • As I mentioned the common IBM reply program pattern is to copy the inbound messageID to the outbound correlationID, but that is not to saw that is the only pattern and another is to copy the inbound correlationID to the outbound correlationID. The only way to know what the app needs to do is to know what the replying application is doing. – JoshMc Feb 07 '19 at 00:22
  • Thanks for clarifying the message ID uniqueness guarantees that IBM MQ provides. However, other JMS providers may not make the same guarantees which is why I mentioned application portability in my answer. It's generally best not to rely on provider-specific guarantees as that can lead to vendor lock-in. The JMS spec itself doesn't provide specific message ID uniqueness guarantees so in my opinion JMS application shouldn't rely on it but rather should ensure their applications make their own guarantees. – Justin Bertram Feb 07 '19 at 00:34