【问题标题】:Is it possible to change PutApplicationType for outgoing MQMessage?是否可以更改传出 MQMessage 的 PutApplicationType?
【发布时间】:2019-02-15 17:35:31
【问题描述】:

我有用于 MQ 消息的消息转发器/路由器之类的东西。我正在尝试根据一些规则转发消息。这种转发只是通过从一个队列接收消息、创建一条新消息(具有相同或修改的内容)并将其放入另一个队列来完成。转发器的存在应该尽可能透明。

目前我的问题是PutApplicationType 消息属性。看来我无法更改此属性。我有 .NET 和 Java 示例实现,我试图简单地使用:

MQMessage forwardedMessage = new MQMessage();
forwardedMessage.putApplicationType = CMQC.MQAT_UNIX;

我尝试使用什么值并不重要。 .NET 版本始终使用MQAT_DEFAULT / MQAT_WINDOWS_NT 发送消息,Java 版本始终使用MQAT_JAVA 发送消息。

是否可以更改此标题?如果不是,如果我不更改值,是否会对遗留系统造成一些问题?为什么无法更改值?

顺便说一句。转发原始消息也不起作用 - 我的应用程序也会更改 PutApplicationType 属性。

编辑:如果我使用原生 C API,我可以控制这个属性的内容吗?

【问题讨论】:

    标签: java .net ibm-mq


    【解决方案1】:

    正如 T.Rob 所说,您需要阅读手册(使用 Java 的 WMQ 或使用 .Net 的 WMQ)。转发消息不是您上面列出的简单任务。有几个选项/参数需要正确设置。

    这是一个 Java 代码 sn-p 删除了所有异常处理:

    int openInputOptions  = MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING + MQC.MQOO_INPUT_SHARED + MQC.MQOO_SAVE_ALL_CONTEXT;
    int openOutputOptions = MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING + MQC.MQOO_PASS_ALL_CONTEXT;
    
    MQQueue _inQ = _qMgr.accessQueue( inQueueName, openInputOptions, null, null, null );
    
    MQQueue _outQ = _qMgr.accessQueue( outputQueueName, openOutputOptions, null, null, null );
    
    MQGetMessageOptions getOptions = new MQGetMessageOptions();
    getOptions.options = MQC.MQGMO_NO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING;
    
    MQMessage mqMsg = new MQMessage();
    
    mqMsg.correlationId = MQC.MQCI_NONE;
    mqMsg.messageId = MQC.MQMI_NONE;
    
    _inQ.get(mqMsg, getOptions);
    
    MQPutMessageOptions pmo = new MQPutMessageOptions();
    pmo.options =  MQC.MQPMO_FAIL_IF_QUIESCING + MQC.MQPMO_PASS_ALL_CONTEXT;
    pmo.contextReference = _inQ;
    
    _outQ.put(mqMsg, pmo);
    

    【讨论】:

    • 谢谢!这适用于转发,但它引发了许多与并行处理相关的新问题 - 是否可以从同一个 MQQueue 实例并行处理多个消息?我猜它只能保存最后收到的消息的上下文。如果我可以简单地设置PutApplicationType 字段,它也不能回答我的主要问题——它可能与@T.Rob 提到的创建新上下文有关。我想在手册中阅读这一点 - 但 IBM 的知识库/手册非常糟糕,因为 .NET / Java 的样本数量非常少。
    • 好的,MQOO_SET_ALL_CONTEXTMQPMO_SET_ALL_CONTEXT 做到了。感谢您的示例 - 它引导我找到了解决方案。
    【解决方案2】:

    是的,MQ .NET 还支持所有这些与上下文相关的属性。

    这是我的 .NET 应用程序版本,它转发与原始发送应用程序设置的相同应用程序类型的消息。

    使用 MQOO_SET_ALL_CONTEXT 因为我将消息放在同一个应用程序中

                MQQueue recvQ = qm.AccessQueue("Q1", MQC.MQOO_INPUT_SHARED | MQC.MQOO_OUTPUT | MQC.MQOO_SET_ALL_CONTEXT | MQC.MQOO_SAVE_ALL_CONTEXT | MQC.MQOO_FAIL_IF_QUIESCING);
                MQQueue fwdQ = qm.AccessQueue("Q2", MQC.MQOO_OUTPUT | MQC.MQOO_PASS_ALL_CONTEXT | MQC.MQOO_FAIL_IF_QUIESCING);
    
                MQMessage putMsg = new MQMessage();
                putMsg.WriteString("Verify PutApplicationType");
                putMsg.Persistence = MQC.MQPER_NOT_PERSISTENT;
    
                putMsg.PutApplicationType = MQC.MQAT_UNIX;
                putMsg.PutApplicationName = "UnixApplication";
                putMsg.Format = MQC.MQFMT_STRING;
    
                MQPutMessageOptions pmo = new MQPutMessageOptions();
                pmo.Options = MQC.MQPMO_SET_ALL_CONTEXT;
                recvQ.Put(putMsg,pmo);
    
                MQGetMessageOptions gmo = new MQGetMessageOptions();
                gmo.WaitInterval = MQC.MQWI_UNLIMITED;
                gmo.Options = MQC.MQGMO_WAIT;
                MQMessage fwdMsg = new MQMessage();
                recvQ.Get(fwdMsg, gmo);
    
                MQPutMessageOptions pmoF = new MQPutMessageOptions();
                pmoF.Options = MQC.MQPMO_FAIL_IF_QUIESCING + MQC.MQPMO_PASS_ALL_CONTEXT;
                pmoF.ContextReference = recvQ;
                fwdQ.Put(fwdMsg, pmoF);
    
                recvQ.Close();
                fwdQ.Close();
    

    【讨论】:

    • 谢谢。在您发布答案前几分钟,我自己发现了它。我接受了@Roger 的回答,因为它引导我找到了解决方案。
    【解决方案3】:

    这适用于转发,但它引发了许多与并行处理相关的新问题 - 是否可以从同一个 MQQueue 实例并行处理多条消息?

    当然,我编写的应用程序始终具有并行运行的线程。确保每个线程都有自己与队列管理器的连接。

    我猜它只能保存最后收到的消息的上下文。

    没错。 (针对那个特定的线程)

    如果我可以简单地设置 PutApplicationType 字段,它也不能回答我的主要问题 - 它可能与 @T.Rob 提到的创建新上下文有关。

    您可能应该参加 MQ 课程,因为您没有阅读 T.Rob 给您的手册页。如果您阅读了这些页面(和小节),那么您会了解到 MQMD 有 7 个字段不能简单地设置并由队列管理器控制。

    队列管理器控件:

    1. 身份上下文:

      • 用户ID
      • AccountingToken
      • 应用程序 ID
    2. 起源上下文:

      • PutApplType
      • PutApplName
      • 放置日期
      • 放置时间

    您可以“设置”或“通过”身份上下文,也可以“设置全部”或“全部通过”原始上下文。如果您想更改 MQMD 的 PutApplType 字段(它是原始上下文的一部分),那么您必须使用“设置所有”上下文并且您必须设置 MQMD 的所有 7 个上下文字段,因为队列管理器不会设置它们。

    所以让我非常清楚,如果您使用“全部设置”选项,上面列出的 7 个应用程序未明确设置的字段中的任何一个都将为空(包括 PutDate/PutTime)。

    【讨论】:

    • 谢谢罗杰。我整天都在阅读这些页面,并且我已经了解了这两种上下文类型和未填写的 7 个字段(我也通过一些测试发现了这一点)。这使我的问题得到了完全的解答。 (顺便说一句,StackOverflow 的规则略有不同 - 发布第二个答案通常还不错,但更合适的是更新原始答案并添加详细信息)。
    【解决方案4】:

    有两种方法可以做到这一点,具体取决于您希望的安全程度。第一种也是更安全的方法是从原始消息中传递上下文。此方法保留上下文,而不允许程序更改任何内容。这是通过在队列打开时使用MQOO_SAVE_ALL_CONTEXT 来获取消息并在队列中使用MQOO_PASS_ALL_CONTEXT 来实现的。

    另一个选项是直接设置上下文。这不太安全,因为应用程序可以将字段设置为任意值。如果使用消息的应用程序依赖上下文进行授权,这允许上游应用程序绕过该授权。有几个选项,具体取决于应用需要访问哪组上下文信息。

    请在知识中心查看Controlling message context information

    所有这些都绝对适用于 C 实现。我不知道 .Net 实现中暴露了多少。也许Shashi 会在单独的回复中填写该详细信息。

    【讨论】:

    • 感谢您的回复。这看起来很有趣,但我在 Java 和 .NET 中的快速尝试再次没有奏效。我刚刚将MQOO_SAVE_ALL_CONTEXT 添加到accessQueue 调用以接收队列,将MQOO_PASS_ALL_CONTEXT 添加到accessQueue 调用以发送队列,我尝试转发收到的消息 - 应用程序再次覆盖了属性值。您能否阐明上下文如何影响发送新消息?假设我只想发送一条新消息 - 不转发现有消息,并且我想设置提到的属性的值。这也不起作用,这将是一个很好的起点。
    • 您是否按照链接文档中的说明进行了其他操作? “当您创建第二条消息时:使用 MQOO_PASS_IDENTITY_CONTEXT 选项打开队列(除了 MQOO_OUTPUT 选项);在 put-message 选项结构的 Context 字段中,提供您从中保存上下文信息的队列的句柄;在 put-message 选项结构的选项字段中,指定 MQPMO_PASS_IDENTITY_CONTEXT 选项。”要设置上下文,您必须授予QMgr 以及队列的权限,在 MQOO 中指定选项,并在 MQPMO 中指定设置上下文。
    猜你喜欢
    • 2019-06-25
    • 1970-01-01
    • 2012-05-30
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    • 2016-11-15
    相关资源
    最近更新 更多