I've now drafted the spec and API updates for the following two changes:
A: Allow consumer.close to be called from within a message listener
B: Allowing a consumer to be closed from any thread, even if it isn't the thread of control
The changes can be viewed in the draft spec at
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf
and in the API doc for MessageConsumer.close at
http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/MessageConsumer.html#close%28%29
and are also pasted below.
This is quite an important change, so please do take a look and let me know if you have any comments.
Clarification about B
---------------------
I'd like to add a word of clarification about B, since I have got a bit confused in recent emails. My proposal is that
the current JMS 1.1 "relaxation" of the threading rules for closing a connection or session be applied also to closing a
consumer.
A casual reading of the existing JMS 1.1 section 4.4.6 led me to think that the existing "relaxation" only applied to
the case where the thread of control was delivering messages to a message listener.
However I've now realised that the 1.1 spec goes further than this and allows a session to be closed when another thread
is performing a synchronous receive (or any other operation on the session).
This is explicitly stated in JMS 1.1 section 4.4.1 "Closing a Session", which states that "Session close terminates all
message processing on the session. It must handle the shutdown of pending receives by the session’s consumers or a
running message listener....Session close is the only session method that may be invoked from a thread of control
separate from the one that is currently controlling the session."
The javadoc for session close (in 1.1) backs this up. It says that "this call will block until a receive call or message
listener in progress has completed. A blocked message consumer receive call returns null when this session is closed"
and that "This method is the only Session method that can be called concurrently."
So, on this basis, I have drafted spec and API updates for the consumer close case as follows:
Proposed Javadoc for MessageConsumer.close
------------------------------------------
This is what it currently states in JMS 1.1:
/** Closes the message consumer.
*
* <P>Since a provider may allocate some resources on behalf of a
* <CODE>MessageConsumer</CODE> outside the Java virtual machine, clients
* should close them when they
* are not needed. Relying on garbage collection to eventually reclaim
* these resources may not be timely enough.
*
* <P>This call blocks until a <CODE>receive</CODE> or message listener in
* progress has completed. A blocked message consumer <CODE>receive</CODE>
* call
* returns null when this message consumer is closed.
*
* @exception JMSException if the JMS provider fails to close the consumer
* due to some internal error.
*/
I propose to change this to the following in JMS 2.0:
/**
* Closes the message consumer.
* <p>
* Since a provider may allocate some resources on behalf of a
* {_at_code MessageConsumer} outside the Java virtual machine, clients should
* close them when they are not needed. Relying on garbage collection to
* eventually reclaim these resources may not be timely enough.
* <P>
* This call will block until a {_at_code receive} call in progress on this
* consumer has completed. A blocked {_at_code receive} call returns null when
* this message consumer is closed.
* <p>
* If this method is called whilst a message listener is in progress in
* another thread then it will block until the message listener has
* completed.
* <p>
* This method may be called from a message listener's {_at_code onMessage}
* method on its own consumer. After this method returns the
* {_at_code onMessage} method will be allowed to complete normally.
* <p>
* This method is the only {_at_code MessageConsumer} method that can be called
* concurrently.
*
* @exception JMSException
* if the JMS provider fails to close the consumer due to
* some internal error.
*/
Spec changes: new section 8.8. Closing a consumer
------------------------------------------------
8.8. Closing a consumer
The close methods on MessageConsumer, JMSConsumer, QueueReceiver and TopicSubscriber allow a consumer to be closed
separately from the session or connection used to create it.
Closing a consumer terminates the delivery of messages to the consumer.
close is the only method on a consumer that may be invoked from a thread of control separate from the one which is
currently controlling the session.
If close is called in one thread whilst another thread is calling receive on the same consumer then the call to close
must block until the receive call has completed. A blocked receive call returns null when the consumer is closed.
If close is called in one thread whilst a message listener for this consumer is in progress in another thread then the
call to close must block until the message listener has completed.
If close is called from a message listener's onMessage method on its own consumer then after this method returns the
onMessage method must be allowed to complete normally.
Closing a consumer has no effect on the acknowledgement of messages delivered to the application, or on any transaction
in progress. This is because message acknowledgement and transactions are functions of the session, not the consumer.
* If the session mode is AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE then any messages delivered to the application will be
automatically acknowledged as normal.
* If the session mode is CLIENT_ACKNOWLEDGE then any messages delivered to the application may be acknowledged by
calling acknowledge in the normal way. It makes no difference whether this occurs before or after the consumer is closed.
* If the session is transacted then the application may commit or rollback the transaction as normal. It makes no
difference whether this occurs before or after the consumer is closed.
Spec change: modified 6.2.5. Threading restrictions on a session
----------------------------------------------------------------
Change the 7th paragraph from:
Once a connection has been started, all its sessions with a registered message listener are dedicated to the thread of
control that delivers messages to them. It is erroneous for client code to use such a session from another thread of
control. The only exception to this is the use of the session or connection close method.
to:
Once a connection has been started, all its sessions with a registered message listener are dedicated to the thread of
control that delivers messages to them. It is erroneous for client code to use such a session from another thread of
control. The only exception to this is the use of the consumer, session or connection close method.
Spec change: modified 6.2.6. Threading restrictions on a JMSContext
-------------------------------------------------------------------
Change the 3rd paragraph from:
This restriction also does not apply to the JMSContext's close method (since closing the session from another thread is
permitted),
to:
This restriction also does not apply to the close method on JMSContext or JMSConsumer (since closing a session or
consumer from another thread is permitted).
Proposed Javadoc for JMSConsumer.close
--------------------------------------
This is almost identical to MessageConsumer.close() so I won't include it here.
Nigel