Here's my reply to these interesting and useful comments from Mike.|
(Anyone is welcome to join in and add their own comments. Mike's team raise a few points on which other views are invited)
On 04/02/2013 11:52, Nigel Deakin wrote:
I received some feedback on the public draft from Mike Marzo. JCP member representing Goldman Sachs. I've forwarded it here (below) with permission and will reply shortly.No. JMS doesn't define how messages from a queue are distributed to multiple consumers, and similarly it doesn't define how messages from a shared subscription are distributed to multiple consumers.
Section 4.4.9. "Multiple sessions" explicitly says this for queues, and I think this should be extended to refer to shared subscriptions as well. (Note however that if something is not defined in the spec it is "undefined", irrespective of whether the spec actually says so!)
The javadoc for Session.unsubscribe() says "It is erroneous for a client to delete a durable subscription while there is an active
I think this explicitly answers your question: you can only delete a shared subscription when there are no active consumers.
(The javadoc for JMSContext.unsubscribe() mentions "active consumers". I'll change that to "active (not closed) consumers" and amend Session.unsubscribe() to match).
When I designed this feature I thought it would be difficult to implement in a JTA transaction. The problem isn't so much the need to wait for CompletionListener callbacks to complete but because the semantics of the commit require it to block until all incomplete sends have been completed, and the commit could be called from any thread. That's why the spec forbids its use in a Java EE web or EJB container.
I actually started a FAQ of questions like this:
This is answered in 22.214.171.124. "Use of the CompletionListener by the JMS provider" which states
A session will only invoke one CompletionListener callback method at a time. For a given MessageProducer or JMSContext, callbacks (both onCompletion and onException) will be performed in the same order as the corresponding calls to the asynchronous send method.
JMSContext has no such methods. The only method on JMSContext which creates a JMSContext takes the session mode as a parameter.
I presume you're referring to the methods on ConnectionFactory. The javadocs describe the semantics:
If you think this is unclear please do follow up with further questions.
11.1. "Goals of the simplified API" lists the goals of the simplified API. One of these was "To reduce the number of objects needed to send and receive messages, and in particular to combine the JMS Connection, Session and MessageProducer objects into a single object."
This was considered particularly appropriate for Java EE web or EJB applications, given that in such applications you're only allowed to create one session per connection anyway.
However for Java SE applications (and the Java EE application client container) we need to allow multiple JMSContext objects to share the same connection. I initially suggested having a method on ConnectionFactory which took an existing JMSContext as a parameter, but someone suggested moving the method to the JMSContext itself, and I agreed that this was simpler.
The two APIs are intended to offer the same messaging functionality, but they are not intended to offer the same API style. The whole point of the simplified API was to offer a better style.
The JMSProducer API is designed to avoid an explosion in send methods by allowing each option to be specified using a separate method. Essentially the JMSProducer is a temporary, throwaway object which simply holds parameters for the subsequent send (builder pattern).
MessageProducer has a different style, with all the send options being specified as parameters on the send method:
send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive)
I think the JMSProducer style is much more flexible.
Allowing completion listener to be specified as a parameter on the MessageProducer send method was an attempt to confirm with the existing API style of MessageProducer. This does have a drawback of requiring many send methods.
We could have certainly done that differently, with a method MessageProducer.setAsync, though that would be less consistent with the other methods on Session. Would you prefer that? Would anyone else like to comment?
Hmm. I would have thought that the required behaviour was fairly obvious: if the time to live is less than the delivery time then the message would expire before it was delivered. Does anyone else think this is unclear?
Note that even if the time to live was greater than the delivery time, if there are no consumers on the destination (or they are very slow) then the message would expire before it was delivered. Setting delivery delay does not override message expiration.
I think an exception is most appropriate when the JMS provider simply doesn't know what to do with the information provided. For example a negative time to live is meaningless, and so a provider would be at liberty to reject this as invalid. However I'm not sure that this is the case when the time to live is less than the delivery delay, since by expiring the message at the time specified the JMS provider would be doing exactly what it was asked to do.
Thank you for your comment.
The spec goes on to say
If (a) were adopted it would require the JMS provider to keep all messages in the server until their delivery time is reached, even if there were no durable or non-durable subscriptions in existence. This might even be needed for non-persistent messages. Adopting (b) does not require this and by not requiring a message to be held separately from a subscription is closer to the way in which JMS providers work now. Forcing a JMS provider to implement (a) might potentially add a significant burden simply to cater for an unimportant edge case.Since then I raised this with the expert group and proposed that the reasons for (b) still stand and we should confirm that option
There weren't strong views, and although one or two people suggested deliberately leaving this undefined, no-one was explicitly opposed to (b), so that's where thing stand currently.
More views on this would be welcome.
Java EE compatibility rules mean we can't introduce restrictions that would break existing applications, so all we can do is to define what characters a JMS provider must support, not those that they can't.
3.5.11. "JMSXDeliveryCount" says "When a client receives a message the mandatory JMS-defined message property JMSXDeliveryCount will be set to the number of times the message has been delivered. The first time a message is received it will be set to 1, so a value of 2 or more means the message has been redelivered."
This is pretty clear that "The first time a message is received it will be set to 1".
Whilst JMSXDeliveryCount, like JMSRedelivered, may sometimes give false positives (e.g. after a consumer failure, due to a provider not knowing whether a message was delivered or not) both values are related to deliveries to the client application, not the movement of messages from one part of the JMS provider to another.
Which JMS provider(s) have the behaviour you mention? Most of the major providers are represented on this expert group...
Can the specification be explicit the JMSXDeliveryCount should be incremented only if the message has been returned from a receive call?
Hmm. The specification uses the word "delivered" in hundreds of places, including in the spec for JMSRedelivered. In all cases the word "delivered" means delivered to the client application, not delivered from one part of the JMS provider to another.
I didn't think that needs to be spelled out...but if existing vendors have a different interpretation then perhaps we should.
Security- Kerberos authentication
Can you please log this as an issue at http://java.net/jira/browse/JMS_SPEC
What would this actually mean in terms of the JMS API? Please be as specific as possible.
Thanks for these!
[jms-spec users] [jsr343-experts] Re: JMS 2.0 PR: Feedback from Goldman Sachs