Headers are not read in IBM MQ

152 Views Asked by At

Im trying to put a message with some headers to a topic and get them using the java client [1]. However, I am able to successfully put the message with headers, but unable to get the headers from the message. Here is the code I'm trying.

Put to Topic

MQMessage message = new MQMessage();
MQDLH mqdlh = new MQDLH();
mqdlh.setDestQName("DEV.QUEUE.1");
mqdlh.setIntValue("Reason", 10);

MQTM mqtm = new MQTM();
mqtm.setApplId("TestAppId");
mqtm.setProcessName("TestProcessName");

MQHeaderList headerList = new MQHeaderList();
headerList.add(mqdlh);
headerList.add(mqtm);
headerList.write(message);

MQPropertyDescriptor d = new MQPropertyDescriptor();
d.version = MQPD_USER_CONTEXT;
message.writeString("Your message payload");
topic.put(message);

Get from Topic

MQMessage msg = new MQMessage();
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQGMO_WAIT;
gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
topic.get(msg, gmo);

MQHeaderIterator iterator = new MQHeaderIterator(msg);

while (iterator.hasNext()) {
          MQHeader header = iterator.nextHeader();
          System.out.println(header);
}

The iterator always returns an empty result here. However, if I try to read headers one by one as follows, I'm able to successfully get them.

MQDLH dlh = new MQDLH();
dlh.read(msg);
System.out.println(new String(dlh.getDestQName()));
System.out.println((dlh.getValue("Reason")));

I'm unable to understand the issue here and any help regarding this is much appreciated. Is there any configuration that I should give to make this work?

Edit

Since I couldn't make above format work, I'm manually reading the headers and going through all the available types. Something like below.

switch (type) {
            case MQRFH2: {
                MQRFH2 mqrfh2 = new MQRFH2();
                try {
                    mqrfh2.read(msg);
                    headers.add(getBHeaderFromMQRFH2(runtime, mqrfh2));
                    break;
                } catch (MQDataException e) {
                    msg.seek(dataOffset);
                }
            }
            /*-fallthrough*/
            case MQDLH: {
                MQDLH dlh = new MQDLH();
                try {
                    // Only MQRFH2 headers is supported at the moment. Other headers are read here
                    // to move the cursor to the payload value.
                    dlh.read(msg);
                    break;
                } catch (MQDataException e) {
                    msg.seek(dataOffset);
                }
            }
            .......
            .......
            .......
}

This workaround is not perfect. But is there any other workaround available?

[1] https://mvnrepository.com/artifact/com.ibm.mq/com.ibm.mq.allclient/9.3.4.0

2

There are 2 best solutions below

5
chughts On

This is a comment in response to a request made in a comment, but it wouldn't fit it into a comment. It does not answer the original question, just a follow up.

You can use runmqsc to check and to update the PROPCTL option for a queue. You need to be an administrator, but you can run runmqsc remotely. You will need the redistributable client installed - https://developer.ibm.com/articles/mq-downloads/

If you are running MQ in a docker image locally on your machine, then you can run:

export MQSERVER=DEV.ADMIN.SVRCONN/TCP/localhost(1414)

runmqsc -c -u admin QM1

If your queue manager is running elsewhere then you will most likely need a ccdt to connect.

unset MQSERVER
export MQCCDTURL=<path-to-ccdt-file>
export MQSSLKEYR=<full-path-to-keydb-file> 

runmqsc -c -u <admin user id> -w 60 QM1

Once runmqsc is running you can issue MQSC commands. You can check the queue options by running

display queue(DEV.QUEUE.1)

If you see PROPCTL(NONE) then the headers will not be sent, unless

If the application calls MQCRTMH to create a message handle, it must query the message properties using MQINQMP. Name-value pairs that are not message properties remain in the MQRFH2, which is stripped of any message properties. If the application does not create a message handle, all the message properties are removed from the MQRFH2. Name-value pairs in the MQRFH2 headers remain in the message.

You can set PROPCTL by running

ALTER QLOCAL(DEV.QUEUE.1) PROPCTL(COMPAT)

COMPAT is the default setting. If its not set to COMPAT, then an admin has deliberately changed it.

2
Roger On

I am so confused why you are trying to do what you are doing.

Why in the world would you ever create a message with two embedded structures:

  • Dead Letter Header (MQDLH)
  • Trigger Monitor (MQTM)

That means your messages would look like:

{MQDLH}{MQTM}{message_payload}

Then, push that message to a topic. Why?? It is the strangest thing I ever seen.

And you add your workaround that has MQRFH2 followed by MQDLH embedded structures That means your messages would look like:

{MQRFH2}{MQTM}{message_payload}

In case you don't know, a JMS message is stored by MQ as an MQRFH2 message. So, if you simply put a JMS message to the topic, it will automatically have the embedded MQRFH2 structure. i.e. JMS message internally looks like this:

{MQRFH2}{message_payload}

Years ago, I gave up trying to get the MQHeaderIterator class to work because it was very poorly implemented.