Reputation: 364369
I have something like Message forwarder / router for MQ messages. I'm trying to forward messages based on some rules. This forwarding is simply done by receiving message from one queue, creating a new message (with same or modified content) and putting it to another queue. The existence of the forwarder should be as transparent as possible.
At the moment my problem is PutApplicationType
message property. It looks like I cannot change this property. I have both .NET and Java sample implementation and I'm trying to simply use:
MQMessage forwardedMessage = new MQMessage();
forwardedMessage.putApplicationType = CMQC.MQAT_UNIX;
It doesn't matter what value I try to use. .NET version always sends message with MQAT_DEFAULT
/ MQAT_WINDOWS_NT
and Java version always sends message with MQAT_JAVA
.
Is it possible to change this header? If not can it cause some issue to legacy systems if I don't change the value? Why is it not possible to change the value?
Btw. forwarding original message also doesn't work - my application will change PutApplicationType
property as well.
Edit: If I use native C API will I be able to control content of this property?
Upvotes: 2
Views: 1480
Reputation: 31852
There are two ways to do this, depending on how secure you wish to be. The first and more secure way is to pass the context from the original message. This method preserves the context without allowing the program to change anything. This is achieved using MQOO_SAVE_ALL_CONTEXT
on the open of the queue for getting messages and MQOO_PASS_ALL_CONTEXT
on the queue for putting messages.
The other option is to directly set the context. This is less secure because the application can set the fields to any arbitrary value. If the application consuming the message relies on the context for authorization, this allows the upstream application to bypass that authorization. There are a few options, depending on which set of context information the app needs access to.
Please see Controlling message context information in the Knowledge Center.
All of this is definitely applicable to the C implementation. I do not know how much of it is exposed in the .Net implementation. Perhaps Shashi will fill in that detail in a separate response.
Upvotes: 1
Reputation: 7506
This works for forwarding but it raises a lot of new questions related to parallel processing - can there be multiple messages processed in parallel from the same MQQueue instance?
Sure, I write applications that have threads running in parallel all the time. Make sure each thread has its own connection to the queue manager.
I guess it can hold only context for last received message.
True. (for that particular thread)
It also doesn't answer my main question if I can simply set PutApplicationType field - it is probably related to creating a new context as @T.Rob mentioned.
You should probably take an MQ course because you are not reading the manual pages that T.Rob has given you. If you read those pages (and subsections) then you would have learnt that there are 7 fields of the MQMD that you cannot just simply set and are controlled by the queue manager.
Queue Manager controls:
Identity Context:
Origin Context:
You can 'Set' or 'Pass' Identity Context or you can 'Set All' or 'Pass All' Origin Context. If you want to change PutApplType field (which is part of Origin Context) of MQMD then you MUST use 'Set All' Context and YOU MUST SET ALL 7 Context fields of the MQMD as the queue manager will not set them.
So let me be absolutely clear, if you use 'Set All' option, any of the 7 fields listed above that the application does NOT explicitly set will be null (including the PutDate/PutTime).
Upvotes: 1
Reputation: 15283
Yes, MQ .NET also supports all those context related properties.
Here is my version of .NET application that forwards message with the same application type set by the original sending application.
Using MQOO_SET_ALL_CONTEXT because I am putting the message in the same application
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();
Upvotes: 1
Reputation: 7506
As T.Rob, said you need to read the manaul (WMQ Using Java or WMQ Using .Net). Forwarding a message is not a simple task as you listed above. There are several options/parameters that need to be set correctly.
Here is a Java code snippet with all of the exception handling remove:
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);
Upvotes: 3