1
votes

After solving the first blocker I was able to move toward more complex scenario and I tried to roundtrip custom message properties from my .NET component sending JMS messages to message driven bean hosted in WebSphere Application Server v7 and the bean responding back to to .NET component. This communication is done over WebSphere MQ v7 but .NET uses WebSphere MQ Client v7.5 and amqmdnet.dll v7.5.0.0 (because it fixes some other issues I had with v7 client: for example this).

I'm not able to send simple boolean property from .NET component:

MQMessage message = new MQMessage();
message.SetBooleanProperty("TEST_BOOL", true);
queue.Put(message);

Receiving such message in message driven bean will fail with:

[8/3/12 17:37:20:087 CEST] 0000003b SibMessage    W   [:] CWSJY0003W: JMSCC0110: An exception '
                       Message : com.ibm.msg.client.jms.DetailedMessageFormatException: JMSCMQ1050: The MQRFH2 header has an incorrect format. Received a message with a badly formed MQRFH2 header. Ensure that any non-JMS applications building messages with MQRFH2 headers create well-formed MQRFH2 headers.
                         Class : class com.ibm.msg.client.jms.DetailedMessageFormatException
                         Stack : sun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeConstructorAccessorImpl.java:-2)
                               : sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:45)
                               : sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:39)
                               : java.lang.reflect.Constructor.newInstance(Constructor.java:515)
                               : com.ibm.msg.client.commonservices.j2se.NLSServices.createException(NLSServices.java:313)
                               : com.ibm.msg.client.commonservices.nls.NLSServices.createException(NLSServices.java:388)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQMessageBase._parseUsrFolder(WMQMessageBase.java:1984)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.constructProviderMessageFromRFH2(WMQReceiveMarshal.java:402)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.constructProviderMessageFromProperties(WMQReceiveMarshal.java:191)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.createProviderMessage(WMQReceiveMarshal.java:467)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.exportProviderMessage(WMQReceiveMarshal.java:627)
                               : com.ibm.msg.client.wmq.internal.WMQConsumerShadow.getMsg(WMQConsumerShadow.java:1318)
                               : com.ibm.msg.client.wmq.internal.WMQConsumerShadow.getMsg(WMQConsumerShadow.java:1208)
                               : com.ibm.msg.client.wmq.internal.WMQSyncConsumerShadow.receive(WMQSyncConsumerShadow.java:366)
                               : com.ibm.msg.client.wmq.internal.WMQSession.loadMessageReference(WMQSession.java:1318)
                               : com.ibm.msg.client.jms.internal.JmsSessionImpl.consume(JmsSessionImpl.java:2940)
                               : com.ibm.msg.client.jms.internal.JmsSessionImpl.run(JmsSessionImpl.java:2631)
                               : com.ibm.mq.jms.MQSession.run(MQSession.java:862)
                               : com.ibm.mq.connector.inbound.WorkImpl.run(WorkImpl.java:265)
                               : com.ibm.ejs.j2c.work.WorkProxy.run(WorkProxy.java:399)
                               : com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1604)
     Caused by [1] --> Message : com.ibm.msg.client.jms.DetailedMessageFormatException: JMSCMQ0008: WebSphere MQ classes for JMS attempts to use a data type not supported by a message or attempts to read data in the wrong type. Wrong data types used to read message property types. Check that the message received and the properties to be read are of the type expected.
                         Class : class com.ibm.msg.client.jms.DetailedMessageFormatException
                         Stack : sun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeConstructorAccessorImpl.java:-2)
                               : sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:45)
                               : sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:39)
                               : java.lang.reflect.Constructor.newInstance(Constructor.java:515)
                               : com.ibm.msg.client.commonservices.j2se.NLSServices.createException(NLSServices.java:313)
                               : com.ibm.msg.client.commonservices.nls.NLSServices.createException(NLSServices.java:388)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQMessageUtils.deformatTypedElement(WMQMessageUtils.java:306)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQMessageUtils.deformatElement(WMQMessageUtils.java:414)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQMessageBase._parseUsrFolder(WMQMessageBase.java:1963)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.constructProviderMessageFromRFH2(WMQReceiveMarshal.java:402)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.constructProviderMessageFromProperties(WMQReceiveMarshal.java:191)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.createProviderMessage(WMQReceiveMarshal.java:467)
                               : com.ibm.msg.client.wmq.common.internal.messages.WMQReceiveMarshal.exportProviderMessage(WMQReceiveMarshal.java:627)
                               : com.ibm.msg.client.wmq.internal.WMQConsumerShadow.getMsg(WMQConsumerShadow.java:1318)
                               : com.ibm.msg.client.wmq.internal.WMQConsumerShadow.getMsg(WMQConsumerShadow.java:1208)
                               : com.ibm.msg.client.wmq.internal.WMQSyncConsumerShadow.receive(WMQSyncConsumerShadow.java:366)
                               : com.ibm.msg.client.wmq.internal.WMQSession.loadMessageReference(WMQSession.java:1318)
                               : com.ibm.msg.client.jms.internal.JmsSessionImpl.consume(JmsSessionImpl.java:2940)
                               : com.ibm.msg.client.jms.internal.JmsSessionImpl.run(JmsSessionImpl.java:2631)
                               : com.ibm.mq.jms.MQSession.run(MQSession.java:862)
                               : com.ibm.mq.connector.inbound.WorkImpl.run(WorkImpl.java:265)
                               : com.ibm.ejs.j2c.work.WorkProxy.run(WorkProxy.java:399)
                               : com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1604)
' was caught while processing a message for delivery to a message driven bean.
3

3 Answers

1
votes

I used RFHUtils to get the message sent by my .NET component. usr RFH2 folder contains this definition:

TEST_BOOL(dt='boolean')=True

If I change the value to 1 instead of True and send the message using RFHUtils, it is processed correctly. Decompiled resource adapter (I'm using JD-GUI) also showed that it expects only 0 and 1 values for boolean JMS properties.

static Object deformatTypedElement(int datatype, String value)
    throws JMSException
{
    Object result = null;
    switch (datatype) {
        ...
        case 1:
            if (value.equals("1")) {
                result = new Boolean(true);
            }
            else if (value.equals("0")) {
                result = new Boolean(false);
            }
            else {
                JMSException je = (JMSException)NLSServices.createException("JMSCMQ0008", null); // Line 306 - BOOM!
                throw je;
            }

            // There is also no break here but I think it is a problem of decompiler
       ...
    }
}

Decompiled code of amqmdnet.dll library for .NET (I'm using .NET Reflector) showed that it doesn't convert boolean values before passing them to the message. It simply uses ToString() on the value:

internal class MQMarshalMessageForPut : MQBaseObject
{
   ...

   private void SetContent(RFH2Folder element, object value)
   {
       ...

       if (value is bool)
       {
           element.SetContent(value.ToString(), 1);
       }

       ...
    }
} 

But ToString on bool type returns True or False!

The response from message driven bean back to .NET application works without any problem because GetBoolProperty is prepared to work with both True and False strings and 0 and 1 values.

private bool ParseBoolean(object obj) 
{
    ...

    if ((string.Compare(strA, "true", true) == 0) || (strA == "1"))
    {
        strA = bool.TrueString;
    }
    else if ((string.Compare(strA, "false", true) == 0) || (strA == "0"))
    {
        strA = bool.FalseString;
    }


    ...
}

I think this is a bug in IBM's amqmdnet.dll library.

1
votes

This is a bug, the correct behaviour should allow the applications to use the programming languages representation of a boolean value. In this case .NET being "true/false" and JMS being 1/0. MQ should convert the boolean value between the two applications.

this has now been fixed.

0
votes

There are different definitions for Boolean True and False. Some languages represent True as 1 and False as 0 where as some define False as 0 and any non-zero (including 1 and -1) as True. Some like Ruby define True as 0. So one can not definitely say True is 1 and False as 0. So MQ .NET and Java API set the Boolean value as True and False itself and receiving applications can interpret it as per their language specifics.

However during message receive, MQ .NET and Java API do recognize 1 as True and 0 false. This is more of a usability point. The same can't be applied while sending the message, always a consistent value must be set, can't set 1 sometimes and True sometimes.