【问题标题】:How to send user's boolean property from WMQ .NET client API to JMS?如何将用户的布尔属性从 WMQ .NET 客户端 API 发送到 JMS?
【发布时间】:2012-08-03 09:05:09
【问题描述】:

在解决the first blocker 之后,我能够转向更复杂的场景,我尝试将自定义消息属性从我的 .NET 组件发送到 WebSphere Application Server v7 中托管的消息驱动 bean 和响应回.NET 组件。这种通信是通过 WebSphere MQ v7 完成的,但 .NET 使用 WebSphere MQ Client v7.5 和 amqmdnet.dll v7.5.0.0(因为它修复了我在 v7 客户端中遇到的一些其他问题:例如 this)。

我无法从 .NET 组件发送简单的布尔属性:

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

在消息驱动 bean 中接收此类消息将失败:

[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.

【问题讨论】:

    标签: java .net jms websphere ibm-mq


    【解决方案1】:

    我使用RFHUtils 来获取我的 .NET 组件发送的消息。 usrRFH2 文件夹包含这个定义:

    TEST_BOOL(dt='boolean')=True
    

    如果我将值更改为 1 而不是 True 并使用 RFHUtils 发送消息,则可以正确处理。反编译的资源适配器(我使用的是JD-GUI)也表明它只需要01 布尔JMS 属性值。

    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
           ...
        }
    }
    

    .NET 的 amqmdnet.dll 库的反编译代码(我使用的是.NET Reflector)表明它在将布尔值传递给消息之前不会转换它们。它只是在值上使用ToString()

    internal class MQMarshalMessageForPut : MQBaseObject
    {
       ...
    
       private void SetContent(RFH2Folder element, object value)
       {
           ...
    
           if (value is bool)
           {
               element.SetContent(value.ToString(), 1);
           }
    
           ...
        }
    } 
    

    但是ToString on bool 类型返回TrueFalse

    从消息驱动 bean 返回到 .NET 应用程序的响应没有任何问题,因为 GetBoolProperty 已准备好使用 TrueFalse 字符串以及 01 值。

    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;
        }
    
    
        ...
    }
    

    我认为这是 IBM 的 amqmdnet.dll 库中的一个错误。

    【讨论】:

      【解决方案2】:

      这是一个错误,正确的行为应该允许应用程序使用布尔值的编程语言表示。在这种情况下,.NET 为“真/假”,JMS 为 1/0。 MQ 应该在两个应用程序之间转换布尔值。

      此问题现已修复。

      【讨论】:

        【解决方案3】:

        布尔值TrueFalse 有不同的定义。有些语言将 True 表示为 1,将 False 表示为 0,而有些语言将 False 定义为 0,将任何非零(包括 1 和 -1)定义为 True。有些像 Ruby 将 True 定义为 0。所以不能肯定地说 True 为 1,False 为 0。因此 MQ .NET 和 Java API 将布尔值设置为 TrueFalse 本身,接收应用程序可以按照他们的语言细节。

        但是在消息接收期间,MQ .NET 和 Java API 确实将 1 识别为 True 并且 0 识别为 false。这更像是一个可用性点。发送消息时不能应用相同的值,始终必须设置一致的值,不能有时设置为 1,有时设置为 True。

        【讨论】:

        • 是的。有不同的表示,因此您必须控制发送消息时使用的表示。例如,通过在SetBooleanProperty 中提供附加参数。您正在捍卫 .NET 应用程序无法将布尔属性发送到仅需要 01 的状态(这应该是 btw。默认表示,因为它比 TrueFalse 更常见)。
        猜你喜欢
        • 2015-04-06
        • 1970-01-01
        • 2011-03-20
        • 2015-04-04
        • 2020-09-05
        • 2018-10-27
        • 1970-01-01
        • 1970-01-01
        • 2020-04-18
        相关资源
        最近更新 更多