2

我有用于 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,我可以控制这个属性的内容吗?

4

4 回答 4

3

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

这是一个删除所有异常处理的 Java 代码片段:

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);
于 2012-07-09T18:38:00.730 回答
1

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

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

请参阅知识中心中的控制消息上下文信息

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

于 2012-07-09T14:48:18.647 回答
1

是的,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();
于 2012-07-10T10:04:33.887 回答
1

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

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

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

真的。(对于那个特定的线程)

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

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

队列管理器控件:

  1. 身份背景:

    • 用户身份
    • 会计令牌
    • 应用程序 ID
  2. 起源背景:

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

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

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

于 2012-07-10T15:21:22.653 回答