1
votes

I have a big issue with reading properties from received MQMessage (I'm using WebSphere MQ 7.5 Client). Accessing some properties with GetObjectProperty fires MQRC_PROPERTY_NOT_AVAILABLE error. I will try to explain the error on my logging code.

I have some logging facility in the application. This facility has also option to dump all processed MQ Messages. Dump contains message body, all standard message headers from MQMD and all additional JMS or user properties. The problem is caused when dumping properties because GetPropertyNames("%") returns names of properties which are "not present" in the message - calling GetObjectProeprty with such name results in MQException with reason code 2471 - MQRC_PROPERTY_NOT_AVAILABLE.

Here is simplified code of my method for dumping properties:

private static void DumpMessageProperties(MQMessage message, StringBuilder dumpBuilder) {
    IEnumerator names = message.GetPropertyNames("%");
    dumpBuilder.AppendLine("Properties:");
    while (names.MoveNext()) {
        string name = names.Current.ToString();
        dumpBuilder.AppendFormat("  {0}: ", name);

        try {
            object value = message.GetObjectProperty(name);

            if (value != null) {
                Type type = value.GetType();
                if (type != typeof(sbyte[])) {
                    if (type == typeof(string)) {
                        string strValue = value.ToString();
                        dumpBuilder.Append(String.Format("\"{0}\" [{1}]", strValue, type));
                    } else {
                        dumpBuilder.Append(String.Format("{0} [{1}]", value, type));
                    }
                } else {
                    dumpBuilder.Append(String.Format("{0}", DumpSByteArray((sbyte[])value)));
                }
            }
        } catch (MQException e) {
            dumpBuilder.AppendFormat("{0} ({1})", e.Message, e.ReasonCode.ToString());
        }

        dumpBuilder.AppendLine();
    }
}

I occasionally get MQRC_PROPERTY_NOT_AVAILABLE when dumping user properties of received or sent message. Example of failed dump on received message:

Properties:
  JMSReplyTo: "queue:///SomeQueue" [System.String]
  Encoding: MQRC_PROPERTY_NOT_AVAILABLE (2471)
  JMSDeliveryMode: 0 [System.Int32]
  CodedCharSetId: MQRC_PROPERTY_NOT_AVAILABLE (2471)
  JMSDestination: "queue:///SomeReplyQueue" [System.String]
  MessageVersion: "001" [System.String]
  mcd.Msd: "jms_text" [System.String]
  MessageName: "SomeMessageName" [System.String]

It looks like control fields from MQRFH2 header are somehow passed into the message. I thought the client will automatically handle MQRFH2 message format and translate it for me.

Example of failed dump on sent message:

Properties:
  JMSTimestamp: MQRC_PROPERTY_NOT_AVAILABLE (2471)
  mcd.Msd: 
  JMSDestination: MQRC_PROPERTY_NOT_AVAILABLE (2471)
  JMSReplyTo: MQRC_PROPERTY_NOT_AVAILABLE (2471)
  JMSDeliveryMode: 1 [System.Int32]

Why is this happening? I checked the documentation for the error but I still don't understand how to avoid the error and simply get those data or how to get rid of properties which should not be part of the message (RFH control fields like Encoding an CodeCharSetId).

This looks like MQMessage is in inconsistent state.

1
For sending messages I used XMS .NET. The reason being XMS sets a number of RFH2 properties. For receiving used the sample code you have posted above. But I am unable to see the error. GetPropertyNames is giving me only those that are in the message and GetObjectProperty does not throw 2471 for any of these property names. BTW I am using MQ v7.1. Can I see code snippet that puts messages? - Shashi
Unfortunately I don't have the code responsible for sending messages for the first case, I just have the logged error. I only know that sender is J2EE bean. I can create some example for the second (sent) dump. - Ladislav Mrnka

1 Answers

0
votes

I think you should read the properties from the MQRFH2 header alone. This is how I do it:

MQRFH2 rfh2 = null;

// Find and store message length
int msglen = replyMessage.getMessageLength();

MQHeaderList list = new MQHeaderList(replyMessage);
int indexOf = list.indexOf("MQRFH2");
if (indexOf >= 0) {
    rfh2 = (MQRFH2) list.get(indexOf);
    msglen = msglen - header.size();
}

// this will hold the message text
String msgText = replyMessage.readStringOfCharLength(msglen);

// this will hold all the properties in the end
Map<String, Object> headers = new TreeMap<String, Object>();

if (rfh2 != null) {
    try {
        for (Element folder : rfh2.getFolders()) {
            String prefix = folder.getName() + ".";
            for (Element element : folder.getChildren()) {
                headers.put(prefix + element.getName(), element.getValue());
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

Although this is Java, i'm sure there is a simmilar way to do it with .net.

Hope it can be helpful.