我有类似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,我将能够控制此属性的内容吗?
答案 0 :(得分:3)
正如T.Rob所说,你需要阅读manaul(WMQ使用Java或WMQ使用.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);
答案 1 :(得分:1)
有两种方法可以做到这一点,具体取决于您希望的安全程度。第一种更安全的方法是从原始消息传递上下文。此方法保留上下文,而不允许程序更改任何内容。这是通过在队列打开时使用MQOO_SAVE_ALL_CONTEXT
来获取消息和在队列中使用MQOO_PASS_ALL_CONTEXT
来放置消息来实现的。
另一种选择是直接设置上下文。这不太安全,因为应用程序可以将字段设置为任意值。如果使用该消息的应用程序依赖于授权的上下文,则允许上游应用程序绕过该授权。有几个选项,具体取决于应用程序需要访问哪组上下文信息。
请参阅知识中心的Controlling message context information。
所有这些都绝对适用于C实现。我不知道它在.Net实现中暴露了多少。也许Shashi会在单独的回复中填写这些细节。
答案 2 :(得分: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();
答案 3 :(得分:1)
这适用于转发,但它引发了许多与并行处理相关的新问题 - 是否可以从同一个MQQueue实例并行处理多个消息?
当然,我编写的应用程序一直都是并行运行的。确保每个线程都有自己的与队列管理器的连接。
我猜它只能保留最后收到的消息的上下文。
真。 (对于那个特定的主题)
如果我可以简单地设置PutApplicationType字段,它也没有回答我的主要问题 - 它可能与创建@T.Rob提到的新上下文有关。
您应该参加MQ课程,因为您没有阅读T.Rob给您的手册页。如果您阅读这些页面(和子章节),那么您将了解到MQMD有7个字段,您不能简单地设置它们并由队列管理器控制。
队列管理器控件:
身份背景:
Origin Context:
您可以“设置”或“传递”身份上下文,也可以“设置全部”或“全部通过”原始上下文。如果要更改MQMD的PutApplType字段(它是Origin Context的一部分),那么必须使用'Set All'上下文,并且您必须设置MQMD的所有7个Context字段,因为队列管理器不会设置它们。
所以让我绝对清楚,如果你使用'Set All'选项,那么应用程序没有明确设置的上面列出的7个字段中的任何一个都将为null(包括PutDate / PutTime)。