1

So, I have a message that I'm sending over an IBM mq queue and I would like to give it a customised MessageID. I've implemented DestinationResolver with the below properties in order to enable MQMD properties: queue.setBooleanProperty(WMQConstants.WMQ_MQMD_WRITE_ENABLED, true);

I'm able to set the JMS_IBM_MQMD_ApplIdentityData header but I'm struggling to set the JMS_IBM_MQMD_MsgId header.

This is the MessageID I'm trying to set: String messageID = "ID:TESTYTEST";

If I set JMS_IBM_MQMD_MsgId like this:

message.setAttribute("JMS_IBM_MQMD_MsgId", messageID.getBytes());

then I get the below error

org.apache.camel.component.jms.JmsBinding - Ignoring non primitive header: JMS_IBM_MQMD_MsgId of class: [B

However, if I set JMS_IBM_MQMD_MsgId like this: message.setAttribute("JMS_IBM_MQMD_MsgId", messageID);

then I get the below error com.ibm.msg.client.jms.DetailedMessageFormatException: JMSCC0051: The property 'JMS_IBM_MQMD_MsgId' should be set using type '[B', not 'java.lang.String'. JMS_IBM properties may only be set using a specific variable type. Correct application code to use the required variable type when setting this JMS_IBM property.

2 Answers 2

1

First of all - MessageId is array of 24 bytes. And that is your error. You are trying to push String in byte array - [B. Once you fix this error, you will still not be able to successfully set MessageId. As MQ will completely ignore any value set by message producer, and it will always override your MessageId with arbitary value.

Blame JMS API. It is little bit idiotic and it doesn't make distiction between end user interface and messaging driver programmer interface. There is more than one setter on javax.jms.Message which is not inteded to be used by everday Joe.

So what can you do about it? For start you can use different field: Message Type and CorrelationID headers are inteded to be used by end users. CorrelationID shares the same byte[24] design, and it is functionally identical to MessageID. Usually, CorrelationID is shared between couple different messages which are "correleated", thus the name. You can also add arbitary header to message.

But if you really really need to know MessageID of sent message - because of audit, correlation or something else - you can first send message, and the read MessageID field back. It will contain generated value.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi@JoshMc thanks so much for this. You're correct: I'm able to modify the code to set the MessageId to an array of 24 bytes but it won't make a difference because I'm still unable to set it. I'm already making use of the CorrelationID field and we have a requirement to specifically set the MessageID when sending out a message. Is it possible to set this property using IBM mq libraries perhaps?
No. Intention of MessageID is to track individual message, which would not be possible to do if user was able to override its value. You can use other user modifidable fields - as type, or you can add own property. For example: message.setStringProperty("MyID", hexEncodedBytesHere);
0

There are a few properties that you need to set in Apache Camel before you can set the JMS_IBM_MQMD_MsgId header. Since these headers are in byte[] format, JMS does not natively support values apart from primitive data types and String.

You can setup a DestinationResolver to add a few properties in the IBM MQ queue. Since these properties are not jms component properties, they have to be set via CustomDestinationResolver. Refer this link.

  public DestinationResolver mqmdWriteEnabledWmqDestinationResolver() {
    return new DestinationResolver() {
      @Override
      public Destination resolveDestinationName(
          Session session, String destinationName, boolean pubSubDomain) throws JMSException {
        MQSession wmqSession = (MQSession) session;
        MQQueue queue = (MQQueue) wmqSession.createQueue("queue:///" + destinationName);
        queue.setMQMDWriteEnabled(true);
        return queue;
      }
    };
  } 

setMQMDWriteEnabled will let you write MQMD headers like JMS_IBM_MQMD_MsgId, which do not match the JMS specifications.

However, do note that by default, destinationResolvers are autowired, so you may need to create a new default destination resolver if you are using camel with spring boot.

You can then generate the JMS_IBM_MQMD_MsgId as a byte[] of the message id. Refer to docs for the MessageId standards of IBM MQ.

Once you do that, this will be the configuration of your to endpoint:

.to(
    jms("queue:DEV.QUEUE.1")
          .connectionFactory(connectionFactory)
          .preserveMessageQos(true)
          .advanced()
          .destinationResolver(mqmdWriteEnabledWmqDestinationResolver)
          .allowAdditionalHeaders("JMS_IBM_MQMD_.*"))

allowAdditionalHeaders will allow non JMS headers to be sent to the destination.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.