Not able to get response from IBM MQ using JMS application
Asked Answered
L

3

8

We communicate with the third party using IBM MQ in request/reply fashion. We send them request and they give us reply. Current we both have a simple java based native IBM MQ application. We are planning to rewrite our code using spring jms. But we are not getting any response back within given time when spring jms is used. We are using JMSTemplate to send or receive messages. I am sharing my code snippet. Am I doing anything wrong here? Any other properties should I set here?

  // Request Part (we are sending request)

  String request // this is the request string
  byte[] reqData = request.getBytes(); // converting it into byte array to send

  TextMessage txtMsg = session.createTextMessage(String.valueOf(reqData));

  Destination replyToQName = jmsTemplate.getDestinationResolver().resolveDestinationName(session, responseQueueName, false);

  txtMsg.setJMSReplyTo(replyToQName);

  Destination requestQ = jmsTemplate.getDestinationResolver().resolveDestinationName(session, requestQueueName, false);

  ((JmsDestination) requestQ).setBooleanProperty( WMQConstants.WMQ_MQMD_WRITE_ENABLED, true );

  ((MQQueue) requestQ).setTargetClient(WMQConstants.WMQ_CLIENT_NONJMS_MQ); // setting this because third party application is native websphere mq java application 

  jmsTemplate.convertAndSend(requestQ, txtMsg);

  // saved msgId of request for late use
  String messageId =  txtMsg.getJMSMessageID();


  // Response fetching part

  Destination responseQ = jmsTemplate.getDestinationResolver().resolveDestinationName(session, responseQueueName, false);

  ((JmsDestination) responseQ).setBooleanProperty(WMQConstants.WMQ_MQMD_READ_ENABLED, true);

  ((JmsDestination) responseQ).setObjectProperty( WMQConstants.JMS_IBM_MQMD_CORRELID, msgIdText);

  jmsTemplate.setReceiveTimeout(30000L);

  String filter = "JMSCorrelationID='" + messageId + "'"; // to match request message's messageId with response message's correlationId

  TextMessage respMsg = (TextMessage) jmsTemplate.receiveSelected(responseQ, filter);

Below is my connectionFactory code:

 MQConnectionFactory factory = new MQQueueConnectionFactory();
 factory.setHostName("hostname");
 factory.setPort(1420);
 factory.setQueueManager("QM1");
 factory.setChannel("TEST.CHANNEL");
 factory.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
Levulose answered 6/3, 2018 at 21:19 Comment(2)
I don't know Spring JMS, but it looks like you manage the session lifecycle. If so my best guess would be the connection.start method hasn't been called. If you don't call this you can't receive any messages.Konikow
As I mentioned I am using JMSTemplate, getting session from JMSTemplate. I didn't mention that code in above snippet.Levulose
N
1

The main issue here is that basic diagnostics have not been performed, or if they have then the results not presented in the question. I don't know Spring but I do know basic MQ debugging. I also lived in Missouri, the "Show Me" state, long enough to adopt the state motto as my own. Show me how all the assumptions were verified. As an MQ Admin I'd work with the developer to confirm all the assumptions by visual inspection. Here's how I'd approach it:

Inspect the outbound message

  1. Stop the outbound channel
  2. PUT a request message
  3. GET(ENABLE) the XMitQ and browse the message
    a) Does the message appear?
    b) Does the message have the right format and values?
    c) Are the Reply-To fields correctly populated?
    d) Does the message expire and if so is the expiry sufficiently long?

Inspect the return message

  1. Stop the application
  2. Restart the outbound channel
  3. Browse the reply-to queue
    a) Does a message arrive?
    b) Is it correctly formatted and populated?

Summary
In the end there are only two likely scenarios where this can go wrong and both are easy to check.

First, it is possible the new program is not putting any message at all. This is actually quite common when refactoring code to use a new framework. Trying to debug without positively verifying a message gets PUT (and explicitly stating in the question how this was done and the result) is making an awfully big assumption. Don't assume. Verify a message is produced and tell us the details when asking so we can eliminate that as a root cause.

Second, working backward from the application taking the requests, it doesn't care which app sends the message if they are the same. Assuming the requestor app is actually PUTting a message, it can't be the same as the old one since it gets a different reaction from the remote server app. Compare messages for the same transaction from the old and the new app versions. Print them out in hex and compare byte for byte if necessary.

After performing this kind of differential diagnosis it would be possible narrow the focus and get to root cause. The list of things to check if no message is produced is quite different from the list of items to check if a message is actually produced. It might be possible to resolve this without doing basic diagnostics but that would be the exception. So my non-answer answer is: start by doing the basic diagnostics.

Neil answered 13/3, 2018 at 3:0 Comment(0)
C
0

You are converting the message id from bytes to string and then using it in filter string. I would prefer to using the below because MQ JMS will already does required transformation from bytes to sting.

String filter = "JMSCorrelationID='" + txtMsg.getJMSMessageID()  + "'";
Clapboard answered 7/3, 2018 at 6:14 Comment(1)
I tried using it, but still it is not working. Anything else am I missing here?Levulose
P
0

You have to use an ID: prefix, see also this IBM Technote:

// Create IBM MQ specific correlation ID
public static String jmsCorrelId(String correlId) {
    return "ID:" + javax.xml.bind.DatatypeConverter.printHexBinary(correlId.getBytes()).toLowerCase();
}

// Create IBM MQ specific JMS selector to receive message by correlation ID
public static String jmsCorrelIdSelector(String correlId) {
    return "JMSCorrelationID='" + jmsCorrelId(correlId) + "'";
}

Use above helper functions in your code like this:

String correlId = "MyCorrelId";
txtMsg.setJMSCorrelationID(correlId);
...
String filter = jmsCorrelIdSelector(correlId);
TextMessage respMsg = (TextMessage) jmsTemplate.receiveSelected(responseQ, filter);
Punak answered 7/3, 2018 at 12:11 Comment(3)
Thanks Daniel for your help. I tried to run my code using changes suggested by you. It still not working, even I tried using simple receive function without using any selector, still not receiving any response messages. Should I add any other properties in my code?Levulose
Does the receiver of your sent message actually reply to the reply queue? Can you see the reply message with a tool like MQ Explorer? Could it be that you are sending the message in a transaction, so without commit the replying application does not see the request?Punak
My current application is native ibm mq based java application. When we send request through it, we get reply back on our reply queue and our application consumes that message. Same request giving reply in our current application but not getting any reply in spring-jms application.Levulose

© 2022 - 2024 — McMap. All rights reserved.