0

I have to process messages in Dead Letter Queue (DLQ) using JMS API. The goal is to read body of the original messages and it's user properties. I realize that such approach to DLQ processing might be considered as bad design, but I have to deal with it anyway.

Once read with JMS, body of DLQ message contains body of the original one, prepended with DL header and a structure very similar to RFH2 header of the original message (so containing all the needed user properties).

The question is, how to parse these 2 structures in java?

Yet I only found a doc about how DLH could be constructed from raw data (https://www.ibm.com/support/knowledgecenter/SS8JB4/com.ibm.wbpm.main.doc/topics/esbprog_bindings_wmq5.html). But while DLH seems to be a fixed-lenght structure, RFH2 is definitely not - so the most tricky part of parsing is there.

Any idea would be appreciated.

UPDATE

Here is what I have found:

1) DLH was parsed from raw byte array without any problem, as simple as follows:

MQDLH rfh = new MQDLH(new DataInputStream(new ByteArrayInputStream(bytes)));

Once constructed, all the properties are available.

2) MQRFH2 could be created in a similar manner, if MQLONG values were written there as usual, in big endian. But for some reason, completely unclear to me, in this case all MQLONG are little endian.

So, to create MQRFH2 from raw bytes I have to reverse bytes for all MQLONGs. Not a problem for a fixed part (as described in https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.dev.doc/q032000_.htm), but a bit more complicated for variable part.

I haven't seen any confirmation in docs, but it seems that each folder in variable part is prepended with MQLONG (well, just 4-bytes integer) containing folder length. Once these values were converted from LE to BE as well, MQRFH2 seem to be working correctly.

user3714601
  • 1,156
  • 9
  • 27

1 Answers1

3

I wouldn't process the DLQ with a JMS application. It will be so, so tricky and you will spend days or weeks trying to get it right. I would write a regular Java application to do it, far simpler.

i.e.

MQMessage rcvMsg = new MQMessage();
MQDLH dlh = new MQDLH(rcvMsg);
MQRFH2 rfh2 = new MQRFH2(rcvMsg);
byte[] bData = new byte[rcvMsg.getDataLength()];
rcvMsg.readFully(bData);

Updated on March 4, 2020.

I am normally not into banging my head against the wall but if you want to then here is the code that I would try:

ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
DataInput di = new DataInputStream(bais);

MQDLH dlh = new MQDLH(di);
MQRFH2 rfh2 = new MQRFH2(di)

// Get all folders
String[] folderStrings = rfh2.getFolderStrings();

// or you can get individual name/values using
// get***FieldValue() methods of the MQRFH2 class.

/*
 * At this point, the cursor for "di" is pointing
 * to the beginning of the message payload and I
 * would normal do:
 */
byte[] bData = new byte[mqMsg.getDataLength()];
mqMsg.readFully(bData);
Roger
  • 7,062
  • 13
  • 20
  • I thought about using MQI, but the main problem is that I can not use MQI within XA transaction, which is basically required. – user3714601 Mar 04 '20 at 08:24
  • Or another option probably could be reading with MQI and trying to put also with MQI the "original" message (so readable with JMS) to another queue, but it comes at a price of one more application. Not really sure ... – user3714601 Mar 04 '20 at 08:39
  • @Roger, I have updated the question. Please drop a line if you see any problem with such approach. Besides the fact that it's dirty) – user3714601 Mar 04 '20 at 17:34
  • See my update. Also, you don't need XA if you are moving messages from the DLQ. Just use MQ API's commit and/or backout. – Roger Mar 04 '20 at 17:59