Author |
Message
|
jonstrande |
Posted: Thu Aug 29, 2002 5:41 am Post subject: Trouble w\JMSMessageID, JMSCorrelationID & message sele |
|
|
Newbie
Joined: 29 Aug 2002 Posts: 3 Location: Hershey PA
|
Hello all,
I am using MQ/JMS classes to send a message to a queue and then get a message out of the queue. The messages are being written to the 'IN' channel and read back out of an 'OUT' channel. Basically what we are doing is using MQ as a front end for our EIS systems. I post a message in the IN channel to MQ and MQ taskes the message, fulfills the request and puts the response in the OUT channel.
I need to make sure that I read the corresponding message in the OUT channel that is 'tied' to the message that I wrote to the IN channel.
I would like to use the getJMSCorrelationID, but that returns null, even if I set it to someting. I have tried getJMSMessageID but the response message doesn't seem to tie back to the original...
Here is my code - enclosed in a try/catch:
Code: |
MQQueueConnectionFactory factory = new MQQueueConnectionFactory();
factory.setMethods()...
QueueConnection connection = factory.createQueueConnection();
if(connection != null){
QueueSession session = null;
boolean transacted = false;
System.out.println("calling createQueueSession()");
session = connection.createQueueSession(transacted,
javax.jms.Session.AUTO_ACKNOWLEDGE);
connection.start();
System.out.println("calling createQueue() - in");
Queue inQueue = session.createQueue(inQueueName);
QueueSender queueSender = session.createSender(inQueue);
System.out.println("calling createTextMessage()");
Message message = session.createTextMessage();
message.setStringProperty("testing", new java.util.Date().toString());
System.out.println("calling send(message) ");
message.setJMSCorrelationID("test");
queueSender.send(message);
String messageID = message.getJMSMessageID();
System.out.println(messageID);
System.out.println("calling createQueue() - out");
Queue outQueue = session.createQueue(outQueueName);
QueueReceiver queueReceiver = session.createReceiver
(outQueue, "CorrelId = 'test'");
QueueBrowser qb = session.createBrowser(outQueue);
java.util.Enumeration e = qb.getEnumeration();
System.out.println(" got browsableQueue");
while(e.hasMoreElements()){
Message queueMessage = (Message)e.nextElement();
if(queueMessage != null){
byte [] correlationID =
queueMessage.getJMSCorrelationIDAsBytes();
String stringID = "";
for(int i =0; i < correlationID.length; i++){
stringID += Byte.toString(correlationID[i]);
}
System.out.print(stringID + " - " +
queueMessage.getJMSCorrelationID());
}
}
Message m = queueReceiver.receive(1000);
if(m != null){
TextMessage tm = (TextMessage)m;
if(tm != null){
System.out.println("JMSMessageID=" + tm.getJMSMessageID());
System.out.println("TimeStamp" + tm.getJMSTimestamp());
String receiveString = tm.getText();
System.out.println("Receive Message: " + receiveString);
}
else{
System.out.println("tm is null");
}
}
else{
System.out.println("m is null");
}
queueSender.close();
queueReceiver.close();
session.close();
connection.close();
System.out.println("connection closed");
}
|
I DO NOT get back a correlation ID, even when I expressly set it.
Here is the output - I have several messages in there:
testing MQ connection...
calling createConnection()
calling createQueueSession()
calling createQueue() - in
calling createTextMessage()
calling send(message)
ID:414d51204d45525420202020202020203d6a49f8000dc012
calling createQueue() - out
got browsableQueue
000000000000000000000000 - null
000000000000000000000000 - null
000000000000000000000000 - null
000000000000000000000000 - null
000000000000000000000000 - null
000000000000000000000000 - null
000000000000000000000000 - null
000000000000000000000000 - null
000000000000000000000000 - null
calling queueReceiver.receive(1000)
m is null
connection closed
Thoughts? Comments? Suggestions?
Thank you in advance!
Jon
jstrande@hersheys.com |
|
Back to top |
|
 |
jonstrande |
Posted: Thu Aug 29, 2002 6:34 am Post subject: |
|
|
Newbie
Joined: 29 Aug 2002 Posts: 3 Location: Hershey PA
|
I got this working.
There are several things I was doing wrong, not the least of which was the fact that when the trigger ran on the IN channel, the CorrelId was not being carried forward to the message in the OUT channel.
Let me know if you want more information as to the resolution.
Jon |
|
Back to top |
|
 |
middlewareonline |
Posted: Sat Oct 05, 2002 11:11 am Post subject: |
|
|
Acolyte
Joined: 09 Jul 2001 Posts: 73
|
Could you please elaborate what changes you made to make it work.
I guess fex that I can tell is CorrID should have been JMSCorrelationID in selector and use hex code of the correlation id value. Also, correlation Id should be prefixed with "ID:" ( JMS standard).
Is there anything else that I am missing ?
Raj |
|
Back to top |
|
 |
jonstrande |
Posted: Mon Oct 07, 2002 4:47 am Post subject: |
|
|
Newbie
Joined: 29 Aug 2002 Posts: 3 Location: Hershey PA
|
Raj,
Sure, here is what I did (This is sort of contact admin code, but you get the idea):
Code: |
message.setJMSCorrelationID("12681"); //random number for testing
System.out.println(message.getJMSCorrelationID());
queueSender.send(message);
String testString = message.getJMSCorrelationID();
byte [] bytes = testString.getBytes();
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length ; i++){
sb.append(Integer.toHexString(bytes[i]));
}
int correlationIDLength = 48;
int zerosToFill = correlationIDLength - sb.length();
for(int i = 0; i < zerosToFill; i++ ){
sb.append("0");
}
QueueReceiver queueReceiver = session.createReceiver(inQueue,
"JMSCorrelationID = 'ID:"+sb.toString()+"'");
|
What I did was move all my MQ code into a 'MQService' class and hide the details from the user. So there is currently only one public method:
Code: |
public String sendMessage(String messageContent)
|
This works since we are sending XML through MQ and the XML is a string based representation of the XML. Inside the MQService class I create the Correlation ID for the user and take care of all the communication details for them.
Hope this helps!
Jon |
|
Back to top |
|
 |
simon.starkie |
Posted: Wed Apr 23, 2003 9:16 pm Post subject: I have the same problem. The same workaround fixed. But why? |
|
|
Disciple
Joined: 24 Mar 2002 Posts: 180
|
I had the same problem as jonstrande and the same workaround he used also solved the problem for me (convert CorrelId character string into bytes).
I have heard that there is a known problem with JMS mapping the CorrelId from MQ to JMS. For example, another programmer at our site who also had this problem and got around it by using the MQJI classes to directly reference the CorrelId in the MD rather than using the JMS CorrelId (CID).
Is there a bug in IBM's JMS implementation or are we all making the same mistake
Here is my code (not great code, but hopfully you get the idea)
/**
* @author Ann Starkie
*
* To change this generated comment edit the template variable "typecomment":
* Window>Preferences>Java>Templates.
* To enable and disable the creation of type comments go to
* Window>Preferences>Java>Code Generation.
*/
import javax.jms.*;
import com.ibm.mq.jms.*;
import java.io.*;
public class testJMS
{
private QueueSession qSession;
public static void main(String[] args) {
// Parameters
// 1. Request Queue Name
// 2. Reply Queue Name
// 3. Queue Manager Name
// 4. Input File
String RequestQName = args[0];
String ReplyQName = args[1];
String qManagerName = args[2];
String qFile = args[3];
String theUser = args[4];
String thePassword = args[5];
//Note that any password specified in the createQueueConnection() method
//is not authenticated by the IBM's MQ JMS implementation without you
//implementing your own security exits.
// "Ann Starkie" works, but not "Simon Starkie" (gets MQJMS2013)
//BOTH are in group mqm!!!!!!!!!!!!!!!!!!!!
MQQueueConnectionFactory qConnFactory = new MQQueueConnectionFactory();
try
{
qConnFactory.setQueueManager(qManagerName);
QueueConnection qConn = qConnFactory.createQueueConnection(theUser,thePassword);
QueueSession qSession =
qConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue requestQueue = new MQQueue("queue:///" + RequestQName);
QueueSender requestQueueSender = qSession.createSender(requestQueue);
Queue replyQueue = new MQQueue("queue:///" + ReplyQName);
QueueSender replyQueueSender = qSession.createSender(replyQueue);
//SEND
TextMessage message = qSession.createTextMessage();
// open the file
FileInputStream fis = new FileInputStream(qFile);
// read all its bytes
long filelen = new File(qFile).length();
byte[] vec = new byte[(int)filelen];
fis.read(vec);
int n=1;
StringBuffer vec3 = new StringBuffer();
for(int i = 0; i < filelen ; i++)
{
vec3.append((char)vec[i]);
}
fis.close();
message.setText(vec3.toString());
String RequestMessage = message.getText();
System.out.println( "\n" + "Request Message=\n" + RequestMessage);
String theCorrelId = "simon_says_hello";
message.setJMSCorrelationID(theCorrelId);
requestQueueSender.send(message);
String testString = message.getJMSCorrelationID();
System.out.println("SEND JMSCorrelId=" + testString);
//RECEIVE
// convert CorrelId character string into bytes
byte [] bytes = testString.getBytes();
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length ; i++)
{
sb.append(Integer.toHexString(bytes[i]));
}
int correlationIDLength = 48;
int zerosToFill = correlationIDLength - sb.length();
for(int i = 0; i < zerosToFill; i++ )
{
sb.append("0");
}
// prepare to receive messages
qConn.start(); // MUST START QueueConnection TO RECEIVE ANY MESSAGES
// THIS WORKS
System.out.println("RECEIVE JMSCorrelId=" + sb.toString());
QueueReceiver qReceiver = qSession.createReceiver(replyQueue,"JMSCorrelationID = 'ID:"+sb.toString()+"'");
// THIS DOES NOT WORK - THE MESSAGE IS NOT FOUND
// System.out.println("RECEIVE JMSCorrelId=" + theCorrelId);
// QueueReceiver qReceiver = qSession.createReceiver(replyQueue,"JMSCorrelationID = 'ID:"+"simon_says_jello"+"'");
// THIS DOES NOT WORK - THE MESSAGE IS NOT FOUND
// System.out.println("RECEIVE JMSCorrelId=" + theCorrelId);
// QueueReceiver qReceiver = qSession.createReceiver(replyQueue,"JMSCorrelationID = 'ID:"+theCorrelId+"'");
// receive the message using CorrelId or timeout after 10 seconds
Message inMessage = qReceiver.receive(10000); // get the message or timeout after 10000 milliseconds
// Check to see if the receive call has actually returned a
// message. If it hasn't, report this and throw an exception...
if( inMessage == null )
{
System.out.println( "The attempt to read the message back again " +
"failed, apparently because it wasn't there");
qReceiver.close();
throw new JMSException("Failed to get message back again");
}
// ...otherwise display the message
System.out.println( "\n" + "Reply Message CorrelId=" + inMessage.getJMSCorrelationID());
if (inMessage != null)
{
if (inMessage instanceof TextMessage)
{
message = (TextMessage) inMessage;
System.out.println("Reading message: " +
message.getText());
}
}
qSession.close();
}
catch (JMSException e)
{
System.out.println("Exception: " + e.toString());
}
catch (FileNotFoundException e)
{
System.out.println("File Not Found Exception: " + e.toString());
}
catch (IOException e)
{
System.out.println("File IOException: " + e.toString());
}
}
} |
|
Back to top |
|
 |
kingdon |
Posted: Thu Apr 24, 2003 4:17 am Post subject: |
|
|
Acolyte
Joined: 14 Jan 2002 Posts: 63 Location: UK
|
This seems to crop up at regular intervals, but I have never been able to reproduce any problems with the MQJMS implementation. There are however, plenty of places where you can trip up in the application code. For example:
sb.append(Integer.toHexString(bytes[i]));
won't work in the general case because you need to catch values which return a single digit and prefix a '0'.
// THIS DOES NOT WORK - THE MESSAGE IS NOT FOUND
// System.out.println("RECEIVE JMSCorrelId=" + theCorrelId);
// QueueReceiver qReceiver = qSession.createReceiver(replyQueue,"JMSCorrelationID = 'ID:"+"simon_says_jello"+"'");
won't work because you don't prefix string values of correlationID with ID:, and "jello" is not equal to "hello"
// THIS DOES NOT WORK - THE MESSAGE IS NOT FOUND
// System.out.println("RECEIVE JMSCorrelId=" + theCorrelId);
// QueueReceiver qReceiver = qSession.createReceiver(replyQueue,"JMSCorrelationID = 'ID:"+theCorrelId+"'");
won't work because of the ID:
Other easy to make mistakes include a typo in the name of the identifier (e.g. JMSCorelationID or JMSCorrelationId) and forgetting the quotes around the literal.
Cheers,
James. |
|
Back to top |
|
 |
simon.starkie |
Posted: Fri Apr 25, 2003 6:20 am Post subject: Please post a sample. |
|
|
Disciple
Joined: 24 Mar 2002 Posts: 180
|
Thanks James.
Could you please post the code you used to test MQJMS.
Cheers. |
|
Back to top |
|
 |
kingdon |
Posted: Wed May 14, 2003 11:50 am Post subject: |
|
|
Acolyte
Joined: 14 Jan 2002 Posts: 63 Location: UK
|
Hi,
Posting the test code used for the product isn't something I'm allowed to do, but I've created a simple example program that demonstrates three of the common use cases for JMSCorrelationID. I believe this has already been sent directly to Simon, but I'll also send it to Brandon for putting on the repository, as it may be helpful for others as well.
Cheers,
James. |
|
Back to top |
|
 |
simon.starkie |
Posted: Wed May 14, 2003 1:27 pm Post subject: Thanks, we got the JMS CorrelId sample. |
|
|
Disciple
Joined: 24 Mar 2002 Posts: 180
|
It is a very nice sample including several test cases.
Case B in the sample is consistent with the best practice I have been recommending here. That is, use the unique MessageId from request message that is made available to JMS after the message has been successfully sent to the Messaging Service (in this case MQ).
The MessageId is used as the CorrelId for the subsequent JMS receive.
The triggered application (again, this is a request-reply model to invoke a CICS MQ app) "turns around" the MessageId by moving it to the CorrelId.
The JMS receive is waiting on a CorrelId that is actually the unique MessageId from the send. This particular MessageId value eventually returns to the JMS app receive as the CorrelId because of the "turn around" of the MessageId by the CICS app as previously descried.
In other words, the CICS app does not have to worry about preserving the "user key" in the request message's CorrelId - it simply overlays the CorrelId with the MessageId of the request message. Also, the JMS app does not have to worry about constructing a unique CorrelId - it gets it from the MessageId that was assigned when the message was sent.
Thanks for the excellent help and support from IBM. |
|
Back to top |
|
 |
mverh |
Posted: Wed Nov 12, 2003 6:50 am Post subject: |
|
|
Voyager
Joined: 06 Mar 2002 Posts: 97
|
Did the sample code showing the use of msgId and corellId within a JMS req/rep ever get posted? I looked but didn't see it. If you have a copy I'd appreciate it if you emailed it to me at marc_verhiel@candle.com...thx |
|
Back to top |
|
 |
bower5932 |
Posted: Wed Nov 12, 2003 7:28 am Post subject: |
|
|
 Jedi Knight
Joined: 27 Aug 2001 Posts: 3023 Location: Dallas, TX, USA
|
I'll send you a copy off-line. |
|
Back to top |
|
 |
techno |
Posted: Wed May 12, 2004 10:23 am Post subject: |
|
|
Chevalier
Joined: 22 Jan 2003 Posts: 429
|
I see correlationid getting converted to hexa and all. Is this valid even for generated MsgId ( copying generated msgid to corrid) also? What is the concept here?
Thanks |
|
Back to top |
|
 |
jefflowrey |
Posted: Wed May 12, 2004 11:01 am Post subject: |
|
|
Grand Poobah
Joined: 16 Oct 2002 Posts: 19981
|
techno wrote: |
I see correlationid getting converted to hexa and all. Is this valid even for generated MsgId ( copying generated msgid to corrid) also? What is the concept here?
Thanks |
The Message ID field and the Correlation ID field in the MQMD are defined as BYTE24 fields. Which means that they consist of 24 *bytes*, not *characters*.
A byte can hold binary values that are not legal as characters. You can't simply treat a byte as a String and expect it to work. _________________ I am *not* the model of the modern major general. |
|
Back to top |
|
 |
techno |
Posted: Wed May 12, 2004 3:49 pm Post subject: |
|
|
Chevalier
Joined: 22 Jan 2003 Posts: 429
|
I have another similar thread going on parallel to this ....
But getJMSCorrelationID() is giving String. How do I use correlationid in selector? As byte24 or String?
Thanks, |
|
Back to top |
|
 |
jefflowrey |
Posted: Wed May 12, 2004 4:07 pm Post subject: |
|
|
Grand Poobah
Joined: 16 Oct 2002 Posts: 19981
|
techno wrote: |
I have another similar thread going on parallel to this .... |
Yes. I know.
Please don't do that.
techno wrote: |
But getJMSCorrelationID() is giving String. How do I use correlationid in selector? As byte24 or String? |
See my amended/edited response in that other thread.
I got scared and ran away on the remainder of your question in that thread. You seemed to be talking about running Java on z/OS.  _________________ I am *not* the model of the modern major general. |
|
Back to top |
|
 |
|