PCF processing in JMS
IBM® MQ Programmable Change Format (PCF) messages are a flexible, powerful way in which to query and modify attributes of a queue manager, and the PCF classes provided in the IBM MQ classes for Java provide a convenient way of accessing their functionality in a Java application. The functionality can also be accessed from IBM MQ classes for JMS, however there is a potential problem.
The common model for processing PCF responses in JMS
DataInputStream
and pass it to the
com.ibm.mq.headers.pcf.PCFMessage
constructor.
Message m = consumer.receive(10000);
//Reconstitute the PCF response.
ByteArrayInputStream bais =
new ByteArrayInputStream(((BytesMessage)m).getBody(byte[].class));
DataInput di = new DataInputStream(bais);
PCFMessage pcfResponseMessage = new PCFMessage(di);
See Using the IBM MQ Headers package for some examples.
Unfortunately this is not a totally reliable approach for all platforms - in general the approach works for big-endian platforms, but not for little-endian platforms.
What is the problem?
The problem is that in parsing the message headers, the PCFMessage
class has to
deal with issues of numeric encoding - the headers contain length fields which are in some encoding,
that is big-endian or little-endian.
If you pass a "pure" DataInputStream
to the constructor, the
PCFMessage
class has no good indication of the encoding, and has to assume a
default - quite possibly incorrectly.
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)
This message almost invariably means that the encoding has been misinterpreted. The probable reason for this is that the data that has been read is little-endian data which has been interpreted as big-endian.
The solution
The way to avoid this problem is to pass the PCFMessage
constructor something
which will tell the constructor the numeric encoding of the data it is working with.
To do this, make an MQMessage
from the data received.
// get a response into a JMS Message
Message receivedMessage = consumer.receive(10000);
BytesMessage bytesMessage = (BytesMessage) receivedMessage;
byte[] bytesreceived = new byte[(int) bytesMessage.getBodyLength()];
bytesMessage.readBytes(bytesreceived);
// convert to MQMessage then to PCFMessage
MQMessage mqMsg = new MQMessage();
mqMsg.write(bytesreceived);
mqMsg.encoding = receivedMessage.getIntProperty("JMS_IBM_Encoding");
mqMsg.format = receivedMessage.getStringProperty("JMS_IBM_Format");
mqMsg.seek(0);
PCFMessage pcfMsg = new PCFMessage(mqMsg);