英文:
Websphere MQ: reading from DLQ with JMS
问题
我必须使用JMS API处理死信队列(Dead Letter Queue,DLQ)中的消息。目标是读取原始消息的主体和其用户属性。我意识到这种处理DLQ的方法可能被视为不良设计,但无论如何我都必须处理它。
使用JMS读取DLQ消息后,消息主体包含原始消息的主体,前面附加了DL头,并且结构与原始消息的RFH2头非常相似(因此包含了所有所需的用户属性)。
问题是,如何在Java中解析这两种结构?
目前我只找到一个关于如何从原始数据构造DLH的文档(链接:https://www.ibm.com/support/knowledgecenter/SS8JB4/com.ibm.wbpm.main.doc/topics/esbprog_bindings_wmq5.html)。但是虽然DLH似乎是一个固定长度的结构,但RFH2显然不是固定长度的——所以解析最棘手的部分就在这里。
对于任何想法,我都将不胜感激。
更新
以下是我找到的内容:
1)DLH可以从原始字节数组中轻松解析,就像以下简单的方式:
MQDLH rfh = new MQDLH(new DataInputStream(new ByteArrayInputStream(bytes)));
构造完成后,所有属性都可用。
2)如果MQRFH2中的MQLONG值按照通常的方式写入,采用大端序,那么MQRFH2也可以以类似的方式创建。但由于某种原因,我完全不清楚,这种情况下所有的MQLONG都是小端序。
因此,要从原始字节创建MQRFH2,我必须对所有MQLONG的字节进行反转。对于固定部分来说这不是问题(如https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.dev.doc/q032000_.htm中所述),但对于可变部分来说稍微复杂一些。
我没有在文档中看到任何确认,但似乎可变部分中的每个文件夹都以包含文件夹长度的MQLONG(4字节整数)为前缀。一旦这些值也从小端序转换为大端序,MQRFH2似乎可以正常工作。
英文:
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:
-
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.
- 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.
答案1
得分: 3
我不会使用JMS应用程序来处理DLQ。这将非常非常棘手,你将花费几天甚至几周的时间来尝试做对。我会编写一个普通的Java应用程序来完成这个任务,简单得多。
即:
MQMessage rcvMsg = new MQMessage();
MQDLH dlh = new MQDLH(rcvMsg);
MQRFH2 rfh2 = new MQRFH2(rcvMsg);
byte[] bData = new byte[rcvMsg.getDataLength()];
rcvMsg.readFully(bData);
2020年3月4日更新。
通常我不喜欢在墙上撞头,但如果你想要的话,我会尝试以下代码:
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
DataInput di = new DataInputStream(bais);
MQDLH dlh = new MQDLH(di);
MQRFH2 rfh2 = new MQRFH2(di);
// 获取所有文件夹
String[] folderStrings = rfh2.getFolderStrings();
// 或者你可以使用MQRFH2类的get***FieldValue()方法来获取单个名称/值。
/*
* 此时,"di"的光标指向消息有效负载的开头,我通常会执行:
*/
byte[] bData = new byte[mqMsg.getDataLength()];
mqMsg.readFully(bData);
英文:
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);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论