Author |
Message
|
fjb_saper |
Posted: Wed Feb 10, 2016 1:52 pm Post subject: PCF messages and JMS getting a 3013 |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
Hi,
I am trying to implement PCF messages over JMS Using MQ 8.0.0.4, following the guidelines in https://www.ibm.com/developerworks/community/blogs/messaging/entry/using_pcf_with_mq_jms?lang=en
So no problem on the outbound request message. Getting a response that looks o.k.
However on the new PCFMessage(datainput); I am getting the following exception:
Code: |
pletion Code '2', Reason '3013'.
com.ibm.mq.headers.MQDataException: MQJE001: Completion Code '2', Reason '3013'.
at com.ibm.mq.headers.pcf.PCFParameter.nextParameter(PCFParameter.java:167)
at com.ibm.mq.headers.pcf.PCFMessage.initialize(PCFMessage.java:854)
at com.ibm.mq.headers.pcf.PCFMessage.<init>(PCFMessage.java:156) |
Any Idea what I might be doing wrong?
Here is the code snippet loading the message into the DataInput and the PCFMessage...
Note there is no difference when loading the message as javax.jms.Message or javax.jms.BytesMessage.
Note that event though the format on the queue in MQADMIN it shows up as blank when querying the jms property JMS_IBM_MQMD_FORMAT... The right value is shown under the JMS_IBM_FORMAT property...
Code: |
Message mymsg = null;
while((mymsg = cons.receive(5000L)) != null){
String format = mymsg.getStringProperty(JmsConstants.JMS_IBM_MQMD_FORMAT);
log.trace("Received pcf response with format " + format);
// byte[] payload = null;
// payload = bmsg.getBody(byte[].class);
// ByteArrayInputStream bais = new ByteArrayInputStream(payload);
ByteArrayInputStream bais = new ByteArrayInputStream(
mymsg.getBody(byte[].class));
DataInput di = new DataInputStream(bais);
com.ibm.mq.headers.pcf.PCFMessage resp = new com.ibm.mq.headers.pcf.PCFMessage(di);
|
Anybody successful in using JMS to do PCF this way? _________________ MQ & Broker admin |
|
Back to top |
|
 |
tomleend |
Posted: Mon Feb 15, 2016 12:44 pm Post subject: |
|
|
Acolyte
Joined: 24 Jan 2014 Posts: 51
|
Hello fjb_saper,
I have been doing some basic testing of PCF messages over the classes for JMS API and have also reproduced the same problem you have reported when connecting to my Windows queue manager. My client and server is using v8.0.0.4.
In short, I suspect the issue here is down to data conversion of the data in the PCF response message.
This also might explain why it fails for me (on the Windows platform) but works for Matt (who wrote the DevWorks blog post) on z/OS...
Anyway, when I write a JMS/PCF application using the classic JMS v1.1 API, I can do this:
Code: |
MQQueue replyQ = (MQQueue) session.createTemporaryQueue();
replyQ.setIntProperty(WMQConstants.WMQ_RECEIVE_CONVERSION, WMQConstants.WMQ_RECEIVE_CONVERSION_QMGR);
|
And then everything works okay, just as you have it in the code snippet you provided.
Now, when I switch to using the newer JMS v2.0 API, my code does this:
Code: |
Queue replyQ = context.createTemporaryQueue(); |
But I am not able to cast that Queue object to an MQQueue object. The following exception gets thrown:
java.lang.ClassCastException: com.ibm.msg.client.jms.internal.JmsTemporaryQueueImpl incompatible with com.ibm.mq.jms.MQQueue
As a result, I cannot make the setIntProperty(String, int) call to enable the GMO_CONVERT functionality and get the queue manager to convert the data in the PCF response message. As a result, I get the:
com.ibm.mq.headers.MQDataException: MQJE001: Completion Code '2', Reason '3013'.
exception.
Can you try updating your test case to see if you get similar behaviour?
I guess also that the fact I can cast the TemporaryQueue object returned from the createTemporaryQueue() method on a JMSSession to an MQQueue object, but cannot do likewise when using the same method on a JMSContext, might be a bug? Probably worth raising a PMR to get my theory confirmed... |
|
Back to top |
|
 |
mqjeff |
Posted: Mon Feb 15, 2016 1:09 pm Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
I guess it's not exactly clear why you want to do PCF over JMS...
The PCFAgent classes in the later releases of MQ are really very friendly.
Also, I wouldn't really expect any data conversion to happen on PCF messages... given that most of the structures are essentially binary, and the string parts are only allowed in a very small number of CCSIDs...
That said, the createTemporaryQueue method returns a JMS Temporary Queue. You should be able to cast that to an MQTemporaryQueue, or otherwise just call the setObjectProperty method.
But, again. Not sure why you would JMS in the first place. _________________ chmod -R ugo-wx / |
|
Back to top |
|
 |
tomleend |
Posted: Mon Feb 15, 2016 1:31 pm Post subject: |
|
|
Acolyte
Joined: 24 Jan 2014 Posts: 51
|
Hi mqjeff,
With regard to why data conversion might be having an affect here, I am not sure. I can't say I'm an expert in PCF but that certainly seems to be the root cause here (for my tests anyway). There must be something going on I don't quite understand yet...
As for casting to an MQTemporaryQueue, this also fails:
java.lang.ClassCastException: com.ibm.msg.client.jms.internal.JmsTemporaryQueueImpl incompatible with com.ibm.mq.jms.MQTemporaryQueue
Again, I suspect this might have something to do with way in which this object is being constructed when using a JMSContext as opposed to a JMSSession. So that's a little strange.
// Addition:
Doing this:
Code: |
Queue replyQ = context.createTemporaryQueue();
System.out.println(replyQ.getClass()); |
Actually results in the following being logged:
class com.ibm.msg.client.jms.internal.JmsTemporaryQueueImpl
Whereas, for the other case, it is indeed an MQTemporaryQueue being returned:
class com.ibm.mq.jms.MQTemporaryQueue
Looks like a layer of wrapping has been missed... |
|
Back to top |
|
 |
tczielke |
Posted: Mon Feb 15, 2016 1:39 pm Post subject: |
|
|
Guardian
Joined: 08 Jul 2010 Posts: 941 Location: Illinois, USA
|
PCF messages do have to be converted when they pass between big-endian <-> little endian systems. This has to do with most of the data being binary integer. That being said, Java is different in how it handles endianness. You can run a Java PCF program on a little endian server, have it PUT the messages, and they will be PUT by default as big endian. Under the covers, I believe Java pretends that everything is big endian (i.e. at its byte code level), and then when it needs to compile down to the machine level it takes the endianness of the processor into account. At least that is my understanding, based on what I have read.
That being said, it sounds like there is a potential endianness issue with JMS and PCF going on here. An MQ trace here might show if some data was misrepresented from an Encoding (i.e. endianness) stand point. _________________ Working with MQ since 2010. |
|
Back to top |
|
 |
fjb_saper |
Posted: Mon Feb 15, 2016 2:01 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
The only way I got this to work was by using following:
Code: |
HeaderList hl = new HeaderList(datainput, MQConstants.MQFMT_ADMIN, ccsid, encoding); |
Note the order of the last 2 params might be inversed as it is from memory.
datainput is derived from the bytearray extracted from the javax.jms.BytesMessage...
CCSID is a challenge as now JmsConstants.JMS_IBM_CodedCharSet returns a String instead of an int. (IBM437)...
Does anyone know how to get the correspondance table for the string CCSID to the int CCSID?
The equivalent encoding property is returned fine.
Of course after that you still have to evaluate each of the header, but you can use reflection and request:
Method m = header.getClass().getMethod(methodname, null); with the name being one of the following...
- getParameterName()
- getParameter()
- getValue()
and finish with Object obj = m.invoke(header, null);
It is just a shame that you cannot use any of the nice methods to return you a PCFMessage....  _________________ MQ & Broker admin
Last edited by fjb_saper on Mon Feb 15, 2016 2:07 pm; edited 1 time in total |
|
Back to top |
|
 |
mqjeff |
Posted: Mon Feb 15, 2016 2:06 pm Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
The current question is less about whether the data gets converted or not (and, I did forget about Encoding and was focused on CCSID... ).
It's really about "how do I convert a JMS object into an MQ Object in Java, so I can use MQ Java native methods with the MQ Object.
And I still don't know why one would use JMS to talk PCF. If one wants to use JMS facilities to construct connections, one can then get (or at least used to be able to get) an MQQueueManagerConnection object out of the JMSSession or something. Then one could pass that to the PCFAgent and have it handle the temporary queue and etc. etc. etc.
 _________________ chmod -R ugo-wx / |
|
Back to top |
|
 |
fjb_saper |
Posted: Mon Feb 15, 2016 2:12 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
mqjeff wrote: |
The current question is less about whether the data gets converted or not (and, I did forget about Encoding and was focused on CCSID... ).
It's really about "how do I convert a JMS object into an MQ Object in Java, so I can use MQ Java native methods with the MQ Object.
And I still don't know why one would use JMS to talk PCF. If one wants to use JMS facilities to construct connections, one can then get (or at least used to be able to get) an MQQueueManagerConnection object out of the JMSSession or something. Then one could pass that to the PCFAgent and have it handle the temporary queue and etc. etc. etc.
 |
Obviously, if you need to do it from within an app server (like Tomcat) there are problems with using PCFMessageAgent and java base as you do get bizarre results needing a restart of the appserver (Tomcat). The JMS way does not require a restart of the appserver (ex: after redeploy of the app) and returns a consistent experience....
AFAIK you'd have to extract information from the MQQueueManagerConnection object as the PCFAgent / PCFMessageAgent are not accepting this class in a constructor...) Might be easier to just use the JMS connection and fill the message correctly...
What I did not try yet was to load the header list and write the list back with the default encoding of the qmgr (0) and see if that would get a different return code if loaded back into the PCFMessage ... I guess probably not because I already expected it to be in the qmgr's default encoding... I guess just another problem between Big Endian and Little Endian... _________________ MQ & Broker admin |
|
Back to top |
|
 |
mqjeff |
Posted: Tue Feb 16, 2016 5:59 am Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
My brain thought that there was a straight forward way to get a normal MQ connection object from a JMS MQ connection object. The joys of memory.
What would require the restart of the app server? The PCF classes are included in a normal MQ Java install these days. _________________ chmod -R ugo-wx / |
|
Back to top |
|
 |
tczielke |
Posted: Tue Feb 16, 2016 6:07 am Post subject: |
|
|
Guardian
Joined: 08 Jul 2010 Posts: 941 Location: Illinois, USA
|
fjb_saper wrote: |
What I did not try yet was to load the header list and write the list back with the default encoding of the qmgr (0) and see if that would get a different return code if loaded back into the PCFMessage ... I guess probably not because I already expected it to be in the qmgr's default encoding... I guess just another problem between Big Endian and Little Endian... |
What I have observed working with MQ Java is that the default encoding is big endian, regardless of the queue manager's default encoding. The Java code also places the data in a big endian format. For example, if you take a Java PCF sample that does not set the Encoding and run it on a little endian server like Linux x86, the PCF data is PUT with a big endian encoding and in a big endian format, eventhough the queue manager's default encoding is little endian. Not sure if this exactly applies to what you are doing, but just an FYI. _________________ Working with MQ since 2010. |
|
Back to top |
|
 |
fjb_saper |
Posted: Tue Feb 16, 2016 6:08 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
mqjeff wrote: |
My brain thought that there was a straight forward way to get a normal MQ connection object from a JMS MQ connection object. The joys of memory.
What would require the restart of the app server? The PCF classes are included in a normal MQ Java install these days. |
After redeploy of the app the connections don't work correctly. Especially if you try connections to multiple servers in a row... Say the first one is not up and you get an error (expected), the second one is up but you don't get the expected result unless you bounce the Tomcat server.
Does not happen with JMS... no need to bounce the server after deploy... results are consistent with expectations...  _________________ MQ & Broker admin |
|
Back to top |
|
 |
mqjeff |
Posted: Tue Feb 16, 2016 6:13 am Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
That sounds like a PMR. It also sounds like missing some kind of an exception check or not using the right kind of connection pool.
Using a normal JMSDestination should create a temporary queue, anyway? So you wouldn't need to explicitly create one for the replytoqueue? _________________ chmod -R ugo-wx / |
|
Back to top |
|
 |
fjb_saper |
Posted: Tue Feb 16, 2016 7:22 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
mqjeff wrote: |
Using a normal JMSDestination should create a temporary queue, anyway? So you wouldn't need to explicitly create one for the replytoqueue? |
Where did you read that? In JMS I've always created a temp queue explicitly off the session or context..., I thought this is why you tell the connection factory what the model queue is...  _________________ MQ & Broker admin |
|
Back to top |
|
 |
|