Ladislav Mrnka
Ladislav Mrnka

Reputation: 364369

Is it possible to change PutApplicationType for outgoing MQMessage?

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

Answers (4)

T.Rob
T.Rob

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

Roger
Roger

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:

  1. Identity Context:

    • UserId
    • AccountingToken
    • ApplicationId
  2. Origin Context:

    • PutApplType
    • PutApplName
    • PutDate
    • PutTime

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

Shashi
Shashi

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

Roger
Roger

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

Related Questions