Author |
Message
|
dsteinmann |
Posted: Wed Nov 21, 2018 10:51 pm Post subject: Reconstruct MQ message from Monitoring Event |
|
|
Novice
Joined: 09 Dec 2015 Posts: 15
|
I configured Monitoring Event on a flow with MQ Input node and set the "include bitstream data in payload". I have another flow with an MQ Input node that reads those Monitoring Events from a Durable Subscription and writes the payload into a BLOB column in a database.
Now I would like to write a Java program that reads this BLOB and reconstruct an MQMessage from this BLOB. Unfortunately I don't see any way how to do this with the IBM MQ Java API.
I can do it interactively by writing the BLOB into a file and use RFHUTIL to read this file.
But I would like to do it from Java. Is it possible? |
|
Back to top |
|
 |
fjb_saper |
Posted: Thu Nov 22, 2018 1:55 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
Sure it is possible but it will be damn hard if you don't have the CCSID and format saved to the DB as well.  _________________ MQ & Broker admin |
|
Back to top |
|
 |
abhi_thri |
Posted: Thu Nov 22, 2018 2:03 am Post subject: |
|
|
 Knight
Joined: 17 Jul 2017 Posts: 516 Location: UK
|
Also what about the message headers (MQMD/RFH etc), are you saving those to the database as well? |
|
Back to top |
|
 |
dsteinmann |
Posted: Thu Nov 22, 2018 2:19 am Post subject: |
|
|
Novice
Joined: 09 Dec 2015 Posts: 15
|
Quote: |
Sure it is possible but it will be damn hard if you don't have the CCSID and format saved to the DB as well. |
The Monitoring Event contains the whole MQ message (including MQMD, RFH2). This is why for example RFHUTIL can read it without problem. And MQMD and RFH2 contain the format and CCSID.
As I said, I would like to the same that RFHUTIL does, but with Java. |
|
Back to top |
|
 |
fjb_saper |
Posted: Thu Nov 22, 2018 6:36 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
dsteinmann wrote: |
Quote: |
Sure it is possible but it will be damn hard if you don't have the CCSID and format saved to the DB as well. |
The Monitoring Event contains the whole MQ message (including MQMD, RFH2). This is why for example RFHUTIL can read it without problem. And MQMD and RFH2 contain the format and CCSID.
As I said, I would like to the same that RFHUTIL does, but with Java. |
There should be a way. Look at the Java base interfaces and specially the one treating the message as stream source or target...  _________________ MQ & Broker admin |
|
Back to top |
|
 |
dsteinmann |
Posted: Thu Nov 22, 2018 10:35 pm Post subject: |
|
|
Novice
Joined: 09 Dec 2015 Posts: 15
|
Quote: |
There should be a way. |
I know, it seems such a simple problem. I looked through the whole MQ Java API, but was not able to find such stream reading operations.
This is what I tried last and failed as well:
Code: |
InputStream in = getClass().getResourceAsStream("/test-mq-messge.bin");
byte[] msg = StreamUtils.copyToByteArray(in);
MQMessage mqMessage = new MQMessage();
mqMessage.seek(0);
mqMessage.write(msg);
assertEquals("daniel", mqMessage.userId);
|
I really would be glad if someone could point out how to do this with the MQ Java API. |
|
Back to top |
|
 |
fjb_saper |
Posted: Fri Nov 23, 2018 1:18 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
OK so look at the MQData interface in com.ibm.mq.headers, I believe you'll find it interesting...  _________________ MQ & Broker admin |
|
Back to top |
|
 |
dsteinmann |
Posted: Fri Nov 23, 2018 2:30 pm Post subject: |
|
|
Novice
Joined: 09 Dec 2015 Posts: 15
|
Yes, the MQData was a good starting point, thank you!
The following method allGood() processes successfully my message
But the not so nice thing is that I hard-coded the headers. It would fail if the message has no RFH2 header.
Therefore I tried nothingParsed(), but as the name says, the headers are not parsed and the body is still the full message including MQMD and RFH2 header.
Code: |
import java.io.DataInputStream;
import org.apache.commons.io.IOUtils;
import org.hamcrest.CoreMatchers;
import org.junit.*;
import com.ibm.mq.headers.*;
public class MqMsgTest {
@Test
public void allGood() throws Exception {
DataInputStream dis = new DataInputStream(getClass().getResourceAsStream("/mq-msg.bin"));
MQMD mqmd = new MQMD(dis);
Assert.assertEquals("daniel", mqmd.getUserIdentifier().trim());
MQRFH2 rfh2 = new MQRFH2(dis);
Assert.assertEquals("AMQ.5BE355A587C71A20", rfh2.getStringFieldValue("usr", "MockResponseQueue"));
String body = IOUtils.toString(dis, CCSID.getCodepage(rfh2.nextCharacterSet()));
Assert.assertThat(body, CoreMatchers.startsWith("<port:getPartyResponse "));
}
@Test
public void nothingParsed() throws Exception {
DataInputStream dis = new DataInputStream(getClass().getResourceAsStream("/mq-msg.bin"));
MQHeaderList headers = new MQHeaderList(dis, true);
String body = new String((byte[])headers.getBody(), "UTF-8");
Assert.assertThat(body, CoreMatchers.startsWith("<port:getPartyResponse "));
}
} |
Any idea what I am doing wrong with the MQHeaderList class?
Or is there another way to parse the headers dynamically? |
|
Back to top |
|
 |
fjb_saper |
Posted: Sat Nov 24, 2018 2:27 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
You are using a DataInputStream to create your header list...
Try doing it formally using a DataInput class
Also headers.getBody returns an Object. It is your assumption that the object is of type byte[] or can be cast to it... Furthermore it is your assumption that this byte[] is a representation of a string in UTF-8... I would go and look for the last header in the list and get the CCSID Field and Format Field to describe the actual data. Note the data might not be in UTF-8...  _________________ MQ & Broker admin |
|
Back to top |
|
 |
dsteinmann |
Posted: Sun Nov 25, 2018 6:06 am Post subject: |
|
|
Novice
Joined: 09 Dec 2015 Posts: 15
|
Quote: |
You are using a DataInputStream to create your header list... |
DataInput is an interface, which the class DataInputStream implements. Here a snippet from the JDK implementation:
Code: |
public class DataInputStream extends FilterInputStream implements DataInput |
And the DataInputStream class seems to work perfectly fine for the MQMD class (see my previous example).
Quote: |
I would go and look for the last header in the list and get the CCSID |
I would like to, but as I said in my problem description, the MQHeaderList does not parse the headers, so I can not access the CCSID information. |
|
Back to top |
|
 |
fjb_saper |
Posted: Sun Nov 25, 2018 7:01 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
dsteinmann wrote: |
Quote: |
You are using a DataInputStream to create your header list... |
DataInput is an interface, which the class DataInputStream implements. Here a snippet from the JDK implementation:
Code: |
public class DataInputStream extends FilterInputStream implements DataInput |
And the DataInputStream class seems to work perfectly fine for the MQMD class (see my previous example).
Quote: |
I would go and look for the last header in the list and get the CCSID |
I would like to, but as I said in my problem description, the MQHeaderList does not parse the headers, so I can not access the CCSID information. |
You have an inherent contradiction here.
On one hand you say the MQMD gets parsed fine, on the other hand you say that the headers do not get parsed...
so what happens if you do
Code: |
int headercount = myheaderslist.size(); |
 _________________ MQ & Broker admin |
|
Back to top |
|
 |
dsteinmann |
Posted: Sun Nov 25, 2018 1:02 pm Post subject: |
|
|
Novice
Joined: 09 Dec 2015 Posts: 15
|
Maybe you misunderstood me. Following works fine:
Code: |
DataInputStream dis = new DataInputStream(getClass().getResourceAsStream("/mq-msg.bin"));
MQMD mqmd = new MQMD(dis); |
But this fails; headers.size() returns 0:
Code: |
DataInputStream dis = new DataInputStream(getClass().getResourceAsStream("/mq-msg.bin"));
MQHeaderList headers = new MQHeaderList(dis, true); |
I do not understand why MQHeaderList can not parse the headers. |
|
Back to top |
|
 |
fjb_saper |
Posted: Sun Nov 25, 2018 9:15 pm Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
So your MQMD gets parsed fine.
Now assume you write the rest of the bitstream to an MQ Message. Can you then use the MQDATA obtained from that message to load the message?
I am thinking here that you might have some problems with the way the data has been stored. And maybe the header chaining or the data part is not quite right, possibly also an alignment problem? The RFH header is typically a 4 byte aligned header...
My guess is you'll have to look at the raw data to see what is wrong. Compare it to a bitstream saved from a correct MQMessage as MQData... This should show you where the differences are...  _________________ MQ & Broker admin |
|
Back to top |
|
 |
dsteinmann |
Posted: Sun Nov 25, 2018 11:42 pm Post subject: |
|
|
Novice
Joined: 09 Dec 2015 Posts: 15
|
Quote: |
So your MQMD gets parsed fine. |
Not only the MQMD, also the RFH2 as I wrote earlier:
Code: |
DataInputStream dis = new DataInputStream(getClass().getResourceAsStream("/mq-msg.bin"));
MQMD mqmd = new MQMD(dis);
Assert.assertEquals("daniel", mqmd.getUserIdentifier().trim());
MQRFH2 rfh2 = new MQRFH2(dis);
Assert.assertEquals("AMQ.5BE355A587C71A20", rfh2.getStringFieldValue("usr", "MockResponseQueue"));
String body = IOUtils.toString(dis, CCSID.getCodepage(rfh2.nextCharacterSet()));
Assert.assertThat(body, CoreMatchers.startsWith("<port:getPartyResponse ")); |
So my data must be ok.
I am just trying to find a flexible way to parse the data, and the MQHeaderList class seems to be exactly what I need. I just don't understand why MQHeaderList does not work. |
|
Back to top |
|
 |
|