How to process IBM MQ message headers
IBM MQ messages can optionally include additional headers, or alternative headers, to the MQRFH2 header, which contains JMS properties. WebSphere Application Server application programs can use the com.ibm.mq.headers classes to access headers in messages from IBM MQ and to construct headers in messages to IBM MQ.
IBM MQ message headers
IBM MQ messages always include a message descriptor (MQMD). They can also include headers that contain additional information about the messages; for example, messages to or from JMS applications usually include an MQRFH2 header that contains message properties. IBM MQ defines the format and usage of some headers (for example, MQRFH2) and also allows users and third-party software providers to define their own custom headers.
Typically it is not necessary for application programs to process IBM MQ message headers. Most IBM MQ applications either do not use headers at all, or only use the MQRFH2 header, and the service integration and IBM MQ messaging providers automatically process the MQRFH2 header when we are communicating with these applications. However, if we are communicating with an IBM MQ application that uses or creates additional or different headers, then our WAS application can use the com.ibm.mq.headers classes to create the headers in messages it sends, and process them in messages it receives.
In the IBM MQ message, the headers (if there are headers) are at the start of the message, before the message payload. Each header contains fields that describe the following header, or the payload if there are no more headers; the MQMD contains the fields that describe the first header, or the payload if there are no headers. The MQMD and the MQRFH2 header do not normally appear in a JMS message. When the messaging provider converts an IBM MQ message into a JMS message, it uses information from the MQMD and MQRFH2 header to set JMS header fields and properties. Similarly, when the messaging provider converts a JMS message into an IBM MQ message, it uses the JMS header fields and properties to construct the MQMD and MQRFH2 header.
The JMS provider handles other headers in IBM MQ messages by converting the IBM MQ message to or from a JMS BytesMessage; the headers appear at the start of the message body, followed by the IBM MQ message payload (if any). The JMS_IBM_Format property of the JMS message indicates the format of the data in the message body (in this case, first header) and the JMS_IBM_Encoding and JMS_IBM_Character_Set properties indicate its encoding and CCSID.
Processing IBM MQ message headers in a JMS BytesMessage
The com.ibm.mq.headers package contains classes and interfaces we can use to parse and manipulate IBM MQ headers in the body of a JMS BytesMessage. The MQHeader interface provides general-purpose methods for accessing header fields and for reading and writing message content. Each header type has its own class that implements the MQHeader interface and adds getter and setter methods for individual fields. For example, the MQCIH class represents the MQCIH (CICS Bridge) header type. The header classes perform any necessary data conversion automatically, and can read or write data in any specified numeric encoding or character set (CCSID).
Two helper classes, MQHeaderIterator and MQHeaderList, assist with reading and decoding (parsing) the header content in messages:
- MQHeaderIterator works like a java.util.Iterator. For as long as there are more headers in the message, the next() method returns true, and the nextHeader() or next() method returns the next header object.
- MQHeaderList works like a java.util.List. Like MQHeaderIterator, it parses header content, but it also allows us to search for particular headers, add new headers, remove existing headers, update header fields, and then write the header content back to a message. Alternatively, we can create an empty QHeaderList, then populate it with header instances and write it to a message once or repeatedly.
Every header class implements the MQHeader interface, which provides the methods int read (java.io.DataInput message, int encoding, int characterSet) and int write (java.io.DataOutput message, int encoding, int characterSet). The java.io.DataInputStream and java.io.DataOutputStream classes implement DataInput and DataOutput respectively. We can obtain DataInput and DataOutput objects from byte arrays carried in JMS messages, as in the following example, which processes a single MQCIH header:
import java.io.*; import javax.jms.*; import com.ibm.mq.headers.*; ... BytesMessage bytesMessage = (BytesMessage) msg; // Message received from JMS consumer byte[] bytes = new byte [(int) bytesMessage.getBodyLength ()]; bytesMessage.readBytes (bytes); DataInput in = new DataInputStream (new ByteArrayInputStream (bytes)); QCIH cih = new MQCIH (in, bytesMessage.getIntProperty("JMS_IBM_Encoding"), 819);Alternatively, we can use the MQHeaderIterator class to process a sequence of headers, replacing the line starting MQCIH cih = new MQCIH with:
MQHeaderIterator it = new MQHeaderIterator (in, bytesMessage.getStringProperty("JMS_IBM_Format"), bytesMessage.getIntProperty("JMS_IBM_Encoding"), 819); while (it.hasNext()) { MQHeader item = (MQHeader) it.next(); ... }This example creates a single header (an MQCIH type header) and adds it into a BytesMessage:
import java.io.*; import javax.jms.*; import com.ibm.mq.constants.CMQC; import com.ibm.mq.headers.*; ... QCIH header = new MQCIH(); ByteArrayOutputStream out = new ByteArrayOutputStream (); header.write (new DataOutputStream (out), CMQC.MQENC_NATIVE, 819); byte[] bytes = out.toByteArray (); BytesMessage newMsg = origSes.createBytesMessage(); newMsg.writeBytes(bytes);This example uses the MQHeaderList class to add two headers into a BytesMessage:
import java.io.*; import javax.jms.*; import com.ibm.mq.constants.CMQC; import com.ibm.mq.headers.*; ... byte[] outheaders = null; byte[] outbody = ... try { MQHeaderList it = new MQHeaderList (); MQHeader header1 = ... // Could be any header type MQHeader header2 = ... // Could be any header type ByteArrayOutputStream out = new ByteArrayOutputStream (); DataOutput dout = new DataOutputStream(out); it.add(header1); it.add(header2); it.write(dout); outheaders = out.toByteArray(); } catch (Exception e) { System.out.println("error generating MQ message headers : " + e); } BytesMessage newMsg = origSes.createBytesMessage(); newMsg.writeBytes(outheaders); newMsg.writeBytes(bytes); newMsg.setStringProperty("JMS_IBM_Format", "MQCICS"); newMsg.setIntProperty("JMS_IBM_Encoding", CMQC.MQENC_NATIVE); newMsg.setIntProperty("JMS_IBM_Character_Set", 819);Always use the correct values for the encoding and characterSet arguments. When we read headers, specify the encoding and CCSID with which the byte content was originally written. When writing headers, specify the encoding and CCSID to produce. The data conversion is performed automatically by the header classes.
More information about the com.ibm.mq.headers classes
The com.ibm.mq.headers package is part of the IBM MQ Resource Adapter, which is installed automatically in WAS. This package comprises a set of classes and interfaces that allow the Java programmer to work with IBM MQ Message Headers. These include the MQHeaderIterator and MQHeaderList classes mentioned in this topic, and classes for some commonly used IBM MQ Message Headers, including:
- MQCIH - CICS bridge header
- MQIIH - IMS™ information header
- MQSAPH - SAP header
You can also define classes representing our own headers.