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

A common approach to processing PCF responses in JMS is to extract the bytes payload of the message, wrap it in a 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.

If this situation arises, you will probably see a "MQRCCF_STRUCTURE_TYPE_ERROR" (reason code 3013) in the constructor:

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.

The following code is an outline example of the code you might use.
Attention: The code is an outline example only and does not contain any error handling information.

      // 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);