Author |
Message
|
dwitherspoon |
Posted: Mon Jan 31, 2005 1:49 pm Post subject: MQ resets CCSID and throws no exception |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
Hi folks,
I've just had a grueling couple of days trying to figure out what I was doing wrong. Long story short...I was writing a group of messages via Java Base Classes, and a JMS receiver would report 0 messages. No other messages or exceptions...just no messages.
My error was setting the CCSID in the messages to 437. What made this so hard to figure out was two things that MQ "did for me":
1. Browsing the messages from the Java Base Classes interface, when I set GMO_CONVERT on the get, it would have a problem (apparently) and reset the CCSID field on the message to 819. I knew 819 was right, and didn't realize I was setting it to 437. So when it was telling me that it was set to 819, I thought I was doing the right thing.
2. No exception was thrown.
So I think this creates a couple of bug reports:
1. If a conversion error or warning happens, an exception should be thrown both through JMS and the MQ Base Classes.
2. If a conversion error or warning happens, MQ should not change the CCSID to some other value than what came in on the message, since that makes it virtually impossible to troubleshoot what happened.
That was fun....not! _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
PeterPotkay |
Posted: Mon Jan 31, 2005 1:54 pm Post subject: |
|
|
 Poobah
Joined: 15 May 2001 Posts: 7722
|
I think you have to keep looking for the cause of your problem.
A browse will never alter the message on the queue, or its MQMD.
If the conversion has any problem, MQ does report it with a non zero return code and either a failed or warning completion code. _________________ Peter Potkay
Keep Calm and MQ On |
|
Back to top |
|
 |
dwitherspoon |
Posted: Mon Jan 31, 2005 2:05 pm Post subject: |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
But MQQueue.get returns void, so there is no facility for it to return a warning or error code, as far as I can tell. So the only way it could have told me there was an error or warning would have been for it thrown an exception. But none was thrown.
As to browse modifying the MQMD...I swear that's what is happening. If I use GMO_CONVERT, the characterSet variable (watching in the debugger) is 819 (even though it couldn't do the conversion). Browsing that same message without specyfing GMO_CONVERT, the characterSet variable is 437.
I have fixed the problem by finding the spot in my code where I was setting the CCSID to 437, and just let it default to the queue manager's setting (819). All is fine now, so I have most definitely found the problem.
I think there's a problem here, Houston. I'll be happy to prove it with some output from my browse. _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
jefflowrey |
Posted: Mon Jan 31, 2005 2:11 pm Post subject: |
|
|
Grand Poobah
Joined: 16 Oct 2002 Posts: 19981
|
dwitherspoon wrote: |
But MQQueue.get returns void, so there is no facility for it to return a warning or error code, as far as I can tell. So the only way it could have told me there was an error or warning would have been for it thrown an exception. But none was thrown. |
Without seeing your code, all we can really say is that "no exception was caught". _________________ I am *not* the model of the modern major general. |
|
Back to top |
|
 |
dwitherspoon |
Posted: Tue Feb 01, 2005 5:49 am Post subject: |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
Here's my code:
Code: |
import com.ibm.mq.*;
public class MyBrowser
{
public static void main(String[] args)
{
char mySwitch='n';
// Set up MQ
MQEnvironment.hostname = "GAZOO";
MQEnvironment.port = 1414;
MQEnvironment.channel = "SERVER.PAYFDVL1";
String qmgrStr = "PAYFDVL1";
String queueStr = "ADP.ES.PAYF.OUT.FILE";
MQQueueManager qMgr = null;
MQQueue browseQueue = null;
int numMsgs=0;
try
{
/* Create a queue manager */
qMgr = new MQQueueManager(qmgrStr);
if(qMgr == null)
throw new IllegalStateException("Could not connect to MQ with supplied parameters");
/* Open the queue in browse mode. */
int openOptions = MQC.MQOO_BROWSE + MQC.MQOO_INPUT_SHARED;
browseQueue = qMgr.accessQueue(queueStr, openOptions, null, null,
null);
System.out.println("OPEN - '" + queueStr);
}
catch (MQException ex)
{
if (ex.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE)
System.out.println(" No more messages");
else
{
System.out.println("MQ error: Completion code "
+ ex.completionCode + " Reason code " + ex.reasonCode);
System.exit(1);
}
}
MQGetMessageOptions gmo = new MQGetMessageOptions();
MQMessage myMessage = new MQMessage();
while (true)
{
try
{
myMessage.clearMessage();
gmo.matchOptions = MQC.MQMO_NONE;
gmo.options = MQC.MQGMO_BROWSE_NEXT + MQC.MQGMO_NO_WAIT;
// Should we convert?
if (mySwitch == 'y')
gmo.options = gmo.options + MQC.MQGMO_CONVERT;
// Clobber so we aren't looking for a specific message
myMessage.correlationId = MQC.MQCI_NONE;
myMessage.messageId = MQC.MQMI_NONE;
browseQueue.get(myMessage, gmo);
System.out.println("------------------------------------------------------------");
System.out.println("Message number " + ++numMsgs);
dumpHexId(myMessage.messageId);
System.out.println("****Message descriptor****");
System.out.println(" StrucId : 'MD '" + " Version : "
+ myMessage.getVersion());
System.out.println(" Report : " + myMessage.report
+ " MsgType : " + myMessage.messageType);
System.out.println(" Expiry : " + myMessage.expiry
+ " Feedback : " + myMessage.feedback);
System.out.println(" Encoding : " + myMessage.encoding
+ " CodedCharSetId : " + myMessage.characterSet);
System.out.println();
}
catch (MQException ex)
{
if (ex.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE)
{
System.out.println("Stopped after processing " + numMsgs + " messages");
break;
}
System.out.println("MQ error: Completion code "
+ ex.completionCode + " Reason code " + ex.reasonCode);
if (ex.reasonCode == MQException.MQRC_OPTIONS_ERROR)
{
System.out.println(" again ..........");
System.exit(1);
}
}
catch (java.io.IOException ex)
{
System.out.println("An IO error occurred: " + ex);
}
}
try
{
browseQueue.close();
System.out.println(" CLOSE of queue");
qMgr.disconnect();
System.out.println(" DISCONNECT from queue manager");
}
catch (MQException ex)
{
System.out.println("MQ error: Completion code " + ex.completionCode
+ " Reason code " + ex.reasonCode);
}
System.out.println("**************************");
System.out.println("MyBrowser finished");
}
static void dumpHexId(byte[] myId)
{
System.out.print("Msg ID: ");
for (int i = 0; i < myId.length; i++)
{
char b = (char) (myId[i] & 0xFF);
if (b < 0x10)
{
System.out.print("0");
}
System.out.print((Integer.toHexString(b)).toUpperCase());
}
System.out.println("");
}
}
|
Here is output from this code with mySwitch set to NOT request a conversion
Quote: |
OPEN - 'ADP.ES.PAYF.OUT.FILE
------------------------------------------------------------
Message number 1
Msg ID: 414D51205041594644564C312020202041FE8A7220001501
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
------------------------------------------------------------
Message number 2
Msg ID: 414D51205041594644564C312020202041FE8A7220001503
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
------------------------------------------------------------
Message number 3
Msg ID: 414D51205041594644564C312020202041FE8A7220001601
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 437
------------------------------------------------------------
Message number 4
Msg ID: 414D51205041594644564C312020202041FE8A7220001603
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 437
MQJE001: Completion Code 2, Reason 2033
Stopped after processing 4 messages
CLOSE of queue
DISCONNECT from queue manager
**************************
MyBrowser finished
|
Now here's output on the same queue, same messages, with a conversion requested
Quote: |
OPEN - 'ADP.ES.PAYF.OUT.FILE
------------------------------------------------------------
Message number 1
Msg ID: 414D51205041594644564C312020202041FE8A7220001501
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
------------------------------------------------------------
Message number 2
Msg ID: 414D51205041594644564C312020202041FE8A7220001503
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
------------------------------------------------------------
Message number 3
Msg ID: 414D51205041594644564C312020202041FE8A7220001601
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
------------------------------------------------------------
Message number 4
Msg ID: 414D51205041594644564C312020202041FE8A7220001603
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
MQJE001: Completion Code 2, Reason 2033
Stopped after processing 4 messages
CLOSE of queue
DISCONNECT from queue manager
**************************
MyBrowser finished |
Check the message numbers between the two runs to convince yourself that these are really the same messages on the same queue. Now check the CodedCharSetId values spit out for the last two messages. When a convert is not requested, it comes out as 437. When a convert is requested, it fails, no exception is thrown, and the CCSID is changed to 819. I also added setting MQException.log hoping that this would spit out more info, but nothing gets produced.
The doc on MQGMO_CONVERT says
Quote: |
If conversion cannot be performed successfully, the message data is returned unconverted, and the CCSID and Encoding fileds are set to the values for the unconverted message. The completion code is MQCC_WARNING in this case. |
That would be fine, except that there's no warning coming out, so the program is completely unaware of the warning, and besides that, the only evidence that something is wrong has been covered up. _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
fjb_saper |
Posted: Tue Feb 01, 2005 2:42 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
Yes but you are not checking the completion code on success.
If it is only a warning no exception should be thrown.
Nor are you accessing the message text.
Does an exception get thrown if you try to access the message payload?
All you are requesting here is some information on the envellope.
Now check completion code on success and see what the difference is.
Enjoy  |
|
Back to top |
|
 |
dwitherspoon |
Posted: Wed Feb 02, 2005 6:11 am Post subject: |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
OK...I've looked high and low for a way to check a completion code on success, and I can't find a thing. All varieties of get on MQQueue return void, so it's not there. There's no static completion code variable available in MQMessage, MQQueue, or MQQueueManager. MQEnvironment has no global static completion code.
Can you fill me in on how to check that from Java?
Besides, if I look at the details for MQQueue.get, it says that, for example, if too big a message is attempted, an exception is thrown with a completion code of MQCC_WARNING. So this leads me to think that exceptions should be thrown on warnings.
The C/C++ API lets you pass in a variable to capture the completion code, but that's not the case in Javaland.
By the way, I can access the data with no problem, and I get no exception thrown. _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
jefflowrey |
Posted: Wed Feb 02, 2005 6:42 am Post subject: |
|
|
Grand Poobah
Joined: 16 Oct 2002 Posts: 19981
|
You should actually be checking the completion code on the exception object, as you noticed.
My memory says that in the case where a CONVERT fails, then the exception thrown is 2033 with a warning completion code.
And since your code is treating all 2033s the same, that would explain the failure of your code to notice the failed conversion.
But my memory could be wrong. _________________ I am *not* the model of the modern major general. |
|
Back to top |
|
 |
dwitherspoon |
Posted: Wed Feb 02, 2005 6:58 am Post subject: |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
But no exception is thrown!
The 2033 is just the get call throwing an exception because no message is available, which is why you see a message saying that the program "stopped after processing X messages". If any other exception were thrown, then you'd be seeing a message like
Quote: |
MQ Error: Completion code 2 Reason code 1234. |
So I think your memory is wrong on this one. _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
dwitherspoon |
Posted: Wed Feb 02, 2005 7:00 am Post subject: |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
Ooops...that didn't come out right. I meant to say that the only exception thrown is the 2033, indicating no more messages available. _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
jefflowrey |
Posted: Wed Feb 02, 2005 8:03 am Post subject: |
|
|
Grand Poobah
Joined: 16 Oct 2002 Posts: 19981
|
dwitherspoon wrote: |
Ooops...that didn't come out right. I meant to say that the only exception thrown is the 2033, indicating no more messages available. |
My point was that 2033 is not limited to meaning that no more messages are available.
You should also examine the completion code on the 2033 to determine if it is a success or a warning. If it is a success, then you know that no more messages are available. If it is a warning, then the conversion may have failed.
But it might not have been a 2033 that exhibited this behavior. _________________ I am *not* the model of the modern major general. |
|
Back to top |
|
 |
dwitherspoon |
Posted: Wed Feb 02, 2005 8:38 am Post subject: |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
OK...just for grins, I have modified the catch block as follows:
Code: |
catch (MQException ex)
{
// Did we get a warning or an error?
if (ex.completionCode != 0)
System.out.println("We got a warning or an error!!!");
System.out.println("MQ error: Completion code "
+ ex.completionCode + " Reason code " + ex.reasonCode);
break;
}
catch (java.io.IOException ex)
{
System.out.println("An IO error occurred: " + ex);
}
|
Running this way, I get one message displayed, and that is the 2033 that happens when I've hit the end of the queue after processing all messages on the queue. On a per-message basis, no exception is thrown, and no warning is generated. Here's the output:
Quote: |
OPEN - 'ADP.ES.PAYF.OUT.FILEXFER
------------------------------------------------------------
Message number 1
Msg ID: 414D51205041594644564C312020202041FE8A7220006F01
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
Data read ok
------------------------------------------------------------
Message number 2
Msg ID: 414D51205041594644564C312020202041FE8A7220006F02
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
Data read ok
------------------------------------------------------------
Message number 3
Msg ID: 414D51205041594644564C312020202041FE8A7220007601
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
Data read ok
------------------------------------------------------------
Message number 4
Msg ID: 414D51205041594644564C312020202041FE8A7220007603
****Message descriptor****
StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 273 CodedCharSetId : 819
Data read ok
MQJE001: Completion Code 2, Reason 2033
We got a warning or an error!!!
MQ error: Completion code 2 Reason code 2033
CLOSE of queue
DISCONNECT from queue manager
**************************
MyBrowser finished |
The line saying "Data read ok" is me doing a readFully() on the message to access the data, and so I can hit the data portion of the message without an exception. I don't think there's any doubt now, is there, that no exception is being thrown even though a warning is really being generated under the covers. _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
fjb_saper |
Posted: Wed Feb 02, 2005 12:26 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
I believe the real question we need to ask is what are you really trying to do.
If the system is working as designed and using this as a fall back position while you are trying to do something weird with it then this is all ok.
If you are working the system as intended by the api and not getting the expected results -- time to open a PMR.
The expected behavior is you let the qmgr/frontend handle the CCSID to translate from message CCSID to calling program CCSID when using get with convert.
Enjoy  |
|
Back to top |
|
 |
dwitherspoon |
Posted: Wed Feb 02, 2005 5:22 pm Post subject: |
|
|
 Acolyte
Joined: 09 Dec 2003 Posts: 59
|
PMR time, I would say.
I have worked around the problem, and so I am not stymied at this point. So as you say, the API is not behaving as advertised. So I'll contact IBM for a PMR. I just wanted to vet it out here, since I know some IBM MQ support folks lurk here to see if I was right in my expectations. _________________ Good...Fast...Cheap. Choose any two. |
|
Back to top |
|
 |
|