users@jms-spec.java.net

[jms-spec users] Re: Sending a previously-received Message and supporting JMSXUserID

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Thu, 12 Dec 2013 19:20:28 +0000

Robbie,

On 12/12/2013 17:01, robbie.gemmell_at_gmail.com wrote:
> Hi all,
>
> I wondered if anyone could shed some light on a question I have around
> handling of JMSXUserID (and JMSXAppID as well, I guess).
>
> The JMS-defined JMSXUserID property is optional, but if supported is of
> the 'set by Provider on Send' variety. The spec says that properties
> are read-only when a Message is received. What then is the appropriate
> action to take when supporting JMSXUserID and sending a
> previously-received Message?

Hmm. Interesting question. Here are my initial thoughts on this:

I would expect the JMS provider's send() implementation to set the JMSXUserID property on the message passed to send(),
prior to actually sending the message. If the message passed to send() is its own implementation then it can use
whatever method it likes to do this. This is just one part of the provider calling another part of the same provider and
so there is no requirement to do this using the JMS API. So even if the message properties are read-only the JMS
provider can easily by-pass this.

Different issues arise if the message passed to send() is a "foreign" implementation which was received using a
different JMS provider. In this case the JMS provider's send() implementation will need to call the JMS standard method
setStringProperty("JMSXUserID",userID).

As you say, if the message properties are read-only then this will throw a MessageNotWriteableException. (I think
requiring this even for JMSX properties that are set by the provider is a flaw in the spec, but never mind...)

So the JMS provider's send() implementation will need to work around this by taking a copy of any existing properties,
calling clearProperties(), restoring the saved properties and then calling setStringProperty("JMSXUserID",userID).

An alternative would be to be optimistic and simply call setStringProperty. If a MessageNotWriteableException was thrown
would it be necessary to take a copy of any existing properties, call clearProperties(), restore the saved properties
and then call setStringProperty() again.

I agree this doesn't sound very elegant, but none of this inelegance is exposed to the application. It's all internal to
the JMS provider.

>
> I have searched through the spec and looked at a few implementations to
> see what they do, but haven't as yet really been able to settle on an
> answer to my question. Is there a clarifying area of the spec that I
> have missed? Any other thoughts?
>
> I can see there are various somewhat ugly options, e.g:
>
> 1. Since the spec says properties are read-only in that situation,
> accept this also includes properties the spec defines a provider itself
> sets on send and let the send methods throw
> MessageNotWriteableException. Require that users clear and re-set all
> the properties of recieved Message objects before trying to send them
> if JMSXUserID support is enabled.

I don't see why "users" need to worry about this case at all. The JMS provider itself can (and should) do all the work.

> 2. Copy the Message within the send method to get something writable
> and set the property on that (or possibly just set the property
> directly on the underlying message being sent, e.g using a specific
> field of an underlying protocols native message format), allowing the
> value to be sent but not actually setting it on the Message object
> originally provided.

That wouldn't work because the spec says that "JMSX properties ‘set by provider on send’ are available to both the
producer and the consumers of the message."

This means that the JMS provider needs to set the JMSXUserID property on the exact same message object that was passed
to the send() method. After the send() method returns the application needs to be able to call getStringProperty() to
read the value.

> 3. Try to set the property, catch the MessageNotWriteableException,
> continue to send without the value (or potentially with the wrong value
> if it already existed).

If a MessageNotWriteableException is thrown the JMS provider's send method can handle this correctly, as described earlier.

>
> The JMS 2.0 reference implementation appears to do a combination of 1)
> and 2), though I admit I didn't actually test it in practice. If
> support for JMSXUserID is enabled (looks to be disabled by default) it
> seems like it would throw a MessageNotWriteableException from the send
> method, so long as the message was one of its own. If the Message was
> from a foreign provider, it seems like it would perform a conversion
> and then succeed in setting the property on the converted message and
> not even attempt setting it on the original.

I don't think the RI sets the JMSXUserID property anywhere, but I haven't looked very hard.

Nigel