[JMS_SPEC-107] Extend connection consumer API to support shared durable and non-durable subscriptions Created: 06/Dec/12  Updated: 20/Mar/13  Resolved: 10/Dec/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 2.0PD
Fix Version/s: 2.0PD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-253 Extend connection consumer API to sup... Closed
Tags: pd20-added

 Description   

Now that JMS_SPEC-40 has added shared-durable and non-durable subscriptions to JMS, the connection consumer API needs to be extended to support them.

So in addition to the existing methods on Connection:

ConnectionConsumer createConnectionConsumer(
   Destination destination, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Queues or unshared non-durable topic subscriptions, clientId optional)

ConnectionConsumer createDurableConnectionConsumer(
   Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Unshared durable topic subscriptions, clientId required)

we also need

ConnectionConsumer createSharedConnectionConsumer(
   Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Shared non-durable topic subscriptions, clientId optional)

ConnectionConsumer createSharedDurableConnectionConsumer(
   Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Shared durable topic subscriptions, clientId optional)



 Comments   
Comment by Nigel Deakin [ 06/Dec/12 ]

Here are the proposed new methods on Connection:

	/**
	 * Creates a connection consumer for this connection (optional operation)
	 * on the specific topic using a shared non-durable subscription with
	 * the specified name.
	 * <p>
	 * This is an expert facility not used by ordinary JMS clients.
	 * <p>
	 * This method must not be used in a Java EE web or EJB application. Doing
	 * so may cause a {@code JMSException} to be thrown though this is not
	 * guaranteed.
	 * 
	 * @param topic
	 *            the topic to access
	 * @param subscriptionName
	 *            the name used to identify the shared non-durable subscription
	 * @param messageSelector
	 *            only messages with properties matching the message selector
	 *            expression are delivered. A value of null or an empty string
	 *            indicates that there is no message selector for the message
	 *            consumer.
	 * @param sessionPool
	 *            the server session pool to associate with this connection
	 *            consumer
	 * @param maxMessages
	 *            the maximum number of messages that can be assigned to a
	 *            server session at one time
	 * 
	 * @return the connection consumer
	 * 
	 * @exception InvalidDestinationException
	 *                if an invalid destination is specified.
	 * @exception InvalidSelectorException
	 *                if the message selector is invalid.
	 * @exception JMSException
	 *                if the {@code Connection} object fails to create a
	 *                connection consumer for one of the following reasons:
	 *                <ul>
	 *                <li>an internal error has occurred 
	 *                <li>invalid arguments for {@code sessionPool} and 
	 *                {@code messageSelector} or 
	 *                <li>this method has been called in a Java EE web or EJB
	 *                application (though it is not guaranteed that an exception
	 *                is thrown in this case)
	 *                </ul>
	 * 
	 * @since 2.0
	 * @see javax.jms.ConnectionConsumer
	 */
	ConnectionConsumer createSharedConnectionConsumer(Topic topic,
			String subscriptionName,
			String messageSelector, ServerSessionPool sessionPool,
			int maxMessages) throws JMSException;
	/**
	 * Creates a connection consumer for this connection (optional operation)
	 * on the specific topic using a shared durable subscription with
	 * the specified name.
	 * <p>
	 * This is an expert facility not used by ordinary JMS clients.
	 * <p>
	 * This method must not be used in a Java EE web or EJB application. Doing
	 * so may cause a {@code JMSException} to be thrown though this is not
	 * guaranteed.
	 * 
	 * @param topic
	 *            topic to access
	 * @param subscriptionName
	 *            the name used to identify the shared durable subscription 
	 * @param messageSelector
	 *            only messages with properties matching the message selector
	 *            expression are delivered. A value of null or an empty string
	 *            indicates that there is no message selector for the message
	 *            consumer.
	 * @param sessionPool
	 *            the server session pool to associate with this durable
	 *            connection consumer
	 * @param maxMessages
	 *            the maximum number of messages that can be assigned to a
	 *            server session at one time
	 * 
	 * @return the durable connection consumer
	 * 
	 * @exception InvalidDestinationException
	 *                if an invalid destination is specified.
	 * @exception InvalidSelectorException
	 *                if the message selector is invalid.
	 * @exception JMSException
	 *                if the {@code Connection} object fails to create a
	 *                connection consumer for one of the following reasons:
	 *                <ul>
	 *                <li>an internal error has occurred 
	 *                <li>invalid arguments
	 *                for {@code sessionPool} and {@code messageSelector} or 
	 *                <li>this method has been called in a Java EE web or EJB
	 *                application (though it is not guaranteed that an exception
	 *                is thrown in this case)
	 *                </ul>
	 * @since 2.0
	 * @see javax.jms.ConnectionConsumer
	 */
	ConnectionConsumer createSharedDurableConnectionConsumer(Topic topic, String subscriptionName, String messageSelector,
			ServerSessionPool sessionPool, int maxMessages) throws JMSException;




[JMS_SPEC-106] Methods on JMSContext that are disallowed if the context is injected should throw a IllegalStateException not a JMSException Created: 07/Nov/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 2.0PD
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-240 Implement modified exceptions on JMSC... Closed
Tags: pd20-added

 Description   

Section 11.3.5. "Restrictions on use of injected JMSContext objects" of the draft JMS 2.0 specification lists some methods which may not be used if the JMSContext is injected (container-managed). It specifies that these methods must throw a JMSRuntimeException if the JMSContext is injected.

A better exception to throw would be an IllegalStateRuntimeException since the error is caused by the JMSContext being "in the wrong state" (container-managed).



 Comments   
Comment by Nigel Deakin [ 14/Nov/12 ]

API docs and spec now updated.





[JMS_SPEC-105] Provide API to allow an app server or resource adapter to obtain a XAResource from a JMSContext Created: 30/Oct/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 2.0PD
Fix Version/s: 2.0PD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-233 Implement API to allow an app server ... Closed
Tags: pd20-added

 Description   

JMS 1.1 defined an optional API to allow an application server or resource adapter to obtain a XAResource object corresponding to a Session object. This is the "chapter 8" API, which defines the optional interfaces XAConnectionFactory, XAConnection, XASession and the method XASession#getXAResource().

However there is currently no equivalent API to allow an application server or resource adapter to obtain a XAResource object corresponding to a JMSContext object.

This means that an application server which uses the "chapter 8" API to integrate with a JMS provider (rather than using a resource adapter) cannot support JMSContext properly. The same applies for a generic resource adapter which uses the "chapter 8" API to integrate with any JMS provider.

There are two alternatives:

Option 1

This option follows the same approach as the existing "chapter 8" API

  • Add four new new createXAContext methods to XAConnectionFactory. These are similar to the four existing createContext methods on ConnectionFactory except that they return a XAJMSContext rather than a JMSContext
  • Define a new interface XAJMSContext. This is a subtype of JMSContext with one additional method, getXAResource, which returns a XAResource.

Option 2

  • Simply add a new method getXAResource to the JMSContext

In both cases implementation of the new interfaces and methods would be optional just like the rest of the existing "chapter 8" API is.

It is proposed that option 1 be adopted, but option 2 is mentioned as a possible alternative.

Note that even though the chapter 8 API is optional, and JMS 2.0 encourages the use of a the JCA API rather than the chapter 8 API for integration of a JMS provider and an application server, the chapter 8 API continues to be part of JMS and is valued by some vendors. If we did not implement this change then we would effectively be breaking this API by making it unusable with JMSContext objects.



 Comments   
Comment by clebertsuconic [ 30/Oct/12 ]

Another issue I constantly face over Transactions is... Most Transaction Managers will offer a recovery option, and currently there's no way to register the XAResource to be recovered. There's no public API that would allow that. it would be nice if we could address that. But I think this will probably go beyond the scope of JMS.

Comment by Nigel Deakin [ 30/Oct/12 ]

@clebert: Do you mean there is no standard way for a transaction manager performing recovery to obtain all the XAResource objects it needs to use for recovery? If so then this is more than a JMS issue.

Comment by nwright [ 12/Nov/12 ]

If I understand, it looks like we'd need a hook on the transaction manager API to actively tell it that we (a JMS resource) are a candidate for XA recovery. In which case this does go beyond the scope of JMS, who can we talk to from the JTA spec about this?

I may have the wrong end of the stick however

Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-102] Make JMSConsumer.receivePayload methods consistent with Message.getBody Created: 26/Oct/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0PD
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-101 New methods Message.getBody(Class<T> ... Resolved
blocks MQ-228 Implement new name and behaviour for ... Closed
Tags: pd20-added

 Description   

JMS_SPEC_64 introduced a new interface JMSConsumer for JMS 2.0. This has methods receivePayload(Class<T> c), receivePayload(Class<T> c, long timeout) and receivePayloadNoWait(Class<T> c).

JMS_SPEC-101 will introduce a new method getBody(Class<T> c).

If JMS_SPEC-101 is agreed then the definition of receivePayload(Class<T> c), receivePayload(Class<T> c, long timeout) and receivePayloadNoWait(Class<T> c) should be amended to make it consistent with the definition of getBody(Class<T> c). Specifically, these methods should allow the specified class to be any type to which the message payload can be assigned. In addition, these methods should throw a MessageFormatException rather than a ClassCastException if the message payload cannot be assigned.

In addition, the name of these method should be changed to receiveBody(Class<T> c), receiveBody(Class<T> c, long timeout) and receiveBodyNoWait(Class<T> c) since the word "payload" is inconsistent with the term "body" which is used in JMS 1.1.



 Comments   
Comment by Nigel Deakin [ 26/Oct/12 ]

In addition, all references to "payload" which were introduced in the JMS 2.0 spec should be changed to "body". (The JMS 1.1 spec does not use the word "payload", but uses the word "body" consistently, including in the names of methods such as clearBody().

Comment by Nigel Deakin [ 30/Oct/12 ]

Please also consider whether to simply change the names of these methods to just "receive", since there would be no clash with the existing receive methods.

Comment by nwright [ 12/Nov/12 ]

I like JMSConsumer.receiveBodyX(Class<T> c).

RE changing these methods to just "receive": I do not think we should move to JMSConsumer.receiveX(Class<T> c) as this is potentially confusing - it looks to me as if the whole message including headers would be delivered with this method. Better to keep the 'Body' in the method name.

Comment by Nigel Deakin [ 16/Nov/12 ]

The API and specification have now been updated with these changes. The new method names are receiveBody(Class<T> c), receiveBody(Class<T> c, long timeout) and receiveBodyNoWait(Class<T> c). Please see the JMS 2.0 API docs for details.





[JMS_SPEC-101] New methods Message.getBody(Class<T> c) and isBodyAssignableTo(Class c) Created: 23/Oct/12  Updated: 20/Mar/13  Resolved: 08/Nov/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-226 Implement new method Message.getBody ... Closed
blocks JMS_SPEC-102 Make JMSConsumer.receivePayload metho... Closed
Tags: pd20-added

 Description   

This is a proposal to add a new method to javax.jms.Message which allows the message payload to be obtained without the need to cast the object to the appropriate subtype first. This can slightly simplify the code of a MessageListener's, onMessage method, where the object passed in is always declared to be a javax.jms.Message.

Here is the proposed API:

	/**
	 * Returns the messages's payload, which must be of the specified type. If
	 * the message has no payload then null is returned. This method may be used
	 * to obtain the payload of any type of message except for
	 * <tt>StreamMessage</tt>.
	 * 
	 * @param c
	 *            The class of the payload.<br/>
	 *            If the message is a <code>TextMessage</code> then this should
	 *            be set to <code>String.class</code>.<br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            should be set to <code>java.io.Serializable.class</code>. <br/>
	 *            If the message is a <code>MapMessage</code> then this should
	 *            be set to <code>java.util.Map.class</code>.<br/>
	 *            If the message is a <code>BytesMessage</code> then this should
	 *            be set to <code>byte[].class</code>.<br/>
	 *            If the message payload is not of the specified type a
	 *            <code>MessageFormatException</code> will be thrown
	 * 
	 * @return the messages's payload
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to get the payload due to some
	 *                internal error.
	 * @exception MessageFormatException
	 *                if the payload is not of the specified type or, if the
	 *                message is an ObjectMessage, if object deserialization
	 *                fails.
	 * @Exception MessageNotReadableException - if the message is a BytesMessage
	 *                and the message is in write-only mode.
	 */
	<T> T getPayload(Class<T> c) throws JMSException;

This means that instead of something like:

    public void onMessage(Message message) {
        String payload = ((TextMessage) message).getText();

we could have

    public void onMessage(Message message) {
        String payload2 = message.getPayload(String.class); 


 Comments   
Comment by Nigel Deakin [ 23/Oct/12 ]

Here's an updated proposal:

	/**
	 * Returns the messages's payload, which must be assignable to the specified
	 * type. If the message has no payload then null is returned. This method
	 * may be used to obtain the payload of any type of message except for
	 * <tt>StreamMessage</tt>.
	 * 
	 * @param c
	 *            The class of the payload.
	 *            <br/>
	 *            If the message is a <code>TextMessage</code> then this should
	 *            be set to <code>String.class</code> or any other class to
	 *            which a String is assignable.
	 *            <br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            should be set to <code>java.io.Serializable.class</code> or
	 *            any other class to which the payload is assignable.
	 *            <br/>
	 *            If the message is a <code>MapMessage</code> then this should
	 *            be set to <code>java.util.Map.class</code>.
	 *            <br/>
	 *            If the message is a <code>BytesMessage</code> then this should
	 *            be set to <code>byte[].class</code>.
	 * 
	 * @return the messages's payload
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to get the payload due to some
	 *                internal error.
	 * @exception MessageFormatException
	 *                if the message is a <code>StreamMessage</code>, or the
	 *                payload cannot be assigned to the specified type, or the
	 *                message is an <code>ObjectMessage</code> and object deserialization
	 *                fails.
	 * @exception MessageNotReadableException - if the message is a <code>BytesMessage</code>
	 *                and the message is in write-only mode.
	 */
	<T> T getPayload(Class<T> c) throws JMSException;
Comment by Nigel Deakin [ 26/Oct/12 ]

Following discussion on the expert group the name of this proposed method is changed from getPayload to getBody (for consistency with established JMS 1.1 terminology). Minor changes have also been made to the wording. Here's the latest draft API:

	/**
	 * Returns the message body as an object of the specified type. The message
	 * body must be capable of being assigned to the specified type. This means
	 * that the specified class or interface must be either the same as, or a
	 * superclass or superinterface of, the class of the message body. This
	 * method may be used to obtain the body of any type of message except for
	 * <tt>StreamMessage</tt>. If the message has no body then null is returned.
	 * 
	 * @param c
	 *            The type to which the message body should be assigned. <br/>
	 *            If the message is a <code>TextMessage</code> then this should
	 *            be set to <code>String.class</code> or another class to which
	 *            a String is assignable. <br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            should be set to <code>java.io.Serializable.class</code> or
	 *            another class to which the payload is assignable. <br/>
	 *            If the message is a <code>MapMessage</code> then this should
	 *            be set to <code>java.util.Map.class</code>. <br/>
	 *            If the message is a <code>BytesMessage</code> then this should
	 *            be set to <code>byte[].class</code>. The
	 *            <code>BytesMessage</code> must not be in write-only mode.
	 * 
	 * @return the message body
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to get the message body due to
	 *                some internal error.
	 * @exception MessageFormatException
	 *                if the message is a <code>StreamMessage</code>, or the
	 *                message body cannot be assigned to the specified type, or
	 *                the message is an <code>ObjectMessage</code> and object
	 *                deserialization fails.
	 * @exception MessageNotReadableException
	 *                if the message is a <code>BytesMessage</code> and the
	 *                message is in write-only mode.
	 */
	<T> T getBody(Class<T> c) throws JMSException;

In addition, there has been a proposal to provide an additional method isBodyAssignableTo which can be used to find out whether a subsequent call to getBody would throw a MessageFormatException. Here it is:

	/**
	 * Returns whether the message body is capable of being assigned to the
	 * specified type. If this method returns true then a subsequent call to the
	 * method <code>getBody</code> with the same type argument would not throw a
	 * MessageFormatException.
	 * <p>
	 * If the message is a <code>StreamMessage</code> then false is returned. If
	 * the message is a <code>ObjectMessage</code> and object deserialization
	 * fails then false is returned. If the message has no body then true is
	 * returned.
	 * 
	 * @param c
	 *            The specified type <br/>
	 *            If the message is a <code>TextMessage</code> then method will
	 *            only return true if this parameter is set to
	 *            <code>String.class</code> or another class to which a String
	 *            is assignable. <br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            method will only return true if this parameter is set to
	 *            <code>java.io.Serializable.class</code> or another class to
	 *            which the payload is assignable. <br/>
	 *            If the message is a <code>MapMessage</code> then this method
	 *            will only return true if this parameter is set to
	 *            <code>java.util.Map.class</code>. <br/>
	 *            If the message is a <code>BytesMessage</code> then this this
	 *            method will only return true if this parameter is set to
	 *            <code>byte[].class</code>.
	 * 
	 * @return whether the message body is capable of being assigned to the
	 *         specified type
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to return a value due to some
	 *                internal error.
	 * @exception MessageNotReadableException
	 *                if the message is a <code>BytesMessage</code> and the
	 *                message is in write-only mode.
	 */
	boolean isBodyAssignableTo(Class c) throws JMSException;
Comment by Nigel Deakin [ 26/Oct/12 ]

Change issue summary to refer to getBody instead of getPayload.

Comment by Nigel Deakin [ 08/Nov/12 ]

This is now approved and added to the public draft.





[JMS_SPEC-98] Fix findbugs warnings in JMSException, JMSRuntimeException, QueueRequestor, TopicRequestor Created: 14/Aug/12  Updated: 20/Mar/13  Resolved: 04/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The following JMS 1.1 classes give the following findbugs warnings:

javax/jms/JMSException.java:86: UG_SYNC_SET_UNSYNC_GET: 
javax.jms.JMSException.getLinkedException() is unsynchronized, 
javax.jms.JMSException.setLinkedException(Exception) is synchronized

javax/jms/QueueRequestor.java:62: URF_UNREAD_FIELD:
Unread field: javax.jms.QueueRequestor.queue

java/javax/jms/TopicRequestor.java:61: URF_UNREAD_FIELD: Unread field:
javax.jms.TopicRequestor.topic

It should be possible for fix all these without breaking backwards compatibility.

Also, the following new JMS 2.0 class givs the following findbugs warnings:

javax/jms/JMSRuntimeException.java:118: UG_SYNC_SET_UNSYNC_GET:
javax.jms.JMSRuntimeException.getLinkedException() is unsynchronized,
javax.jms.JMSRuntimeException.setLinkedException(Exception) is synchronized

This should be fixed.



 Comments   
Comment by Nigel Deakin [ 04/Sep/12 ]

Now fixed.





[JMS_SPEC-97] Define Java EE JMS Connection Factory Definition annotation and descriptor elements Created: 23/Jul/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The Java EE 7 Early Draft specifies that an application may define a JMS ConnectionFactory resource using either a JMSConnectionFactoryDefinition annotation on an application class or a <jms-connection-factory> element in the deployment descriptor.

Although this feature is specified in the Java EE platform spec, the JMS spec needs to define the following:

  • The list of standard properties that may be specified
  • The actual javax.jms.JMSConnectionFactoryDefinition annotation as part of the JMS API


 Comments   
Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-96] Define Java EE JMS Destination Definition annotation and descriptor elements Created: 23/Jul/12  Updated: 22/Mar/13  Resolved: 22/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The Java EE 7 Early Draft specifies that an application may define a JMS Destination resource using either a JMSDestinationDefinition annotation on an application class or a <jms-destination> element in the deployment descriptor.

Although this feature is specified in the Java EE platform spec, the JMS spec needs to define the following:

  • The list of standard properties that may be specified
  • The actual javax.jms.JMSDestinationDefinition annotation as part of the JMS API





[JMS_SPEC-94] Define what characters are valid in a durable (or shared subscription) name Created: 17/Apr/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The JMS 1.1 specification does not specify what characters are valid in a durable subscription name.

It is proposed that the JMS 2.0 specification defines a minimum set of characters which are valid in a durable or non-durable subscription name.

This is needed to allow portable applications to be created. It is also needed because EJB_SPEC-41 states that if a MDB is defined with subscriptionDurability set to Durable but subscriptionName is not set then the container will automatically set subscriptionName to a suitably unique global name of the MDB, and the container vendor needs to be sure that the name it generates will always be a legal subscription name.



 Comments   
Comment by Nigel Deakin [ 31/May/12 ]

In addition, the JMS 2.0 should specify the minimum length of durable subscription name that a JMS provider should support.

Comment by chris.barrow [ 06/Dec/12 ]

Issue JMS_SPEC-90 "Provide simpler mechanism to refer to queues and topics in a portable way" is related. Could we deal with that issue at the same time? It could easily be resolved by stipulating the same rules for queue and topic names as those proposed for durable subscription name (minimum set of characters and length that must be supported), as noted in a comment I added to that issue.

Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-93] Does changing the noLocal flag when connecting to a durable subscription cause the durable subscription to be deleted? Created: 30/Mar/12  Updated: 21/Sep/12  Resolved: 17/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks JMS_SPEC-40 Allow multiple consumers to be create... Resolved
Tags: pd20-added

 Description   

The JMS 1.1 specification, section 6.11.1 "Durable TopicSubscriber" states:

A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector, or NoLocal attribute. Changing a durable subscription is equivalent to deleting and recreating it.

However the javadoc here for the Session method createDurableSubscriber(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal) states that

A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector. Changing a durable subscriber is equivalent to unsubscribing (deleting) the old one and creating a new one.

The latter text uses an almost identical sentence but does not mention the effect of creating a durable subscriber with a different value of the noLocal flag.

This is contradictory and needs to be clarified. What is the effect if creating a durable subscriber with a different value of the noLocal flag than was used when the durable subscription was created?

I propose that we should interpret the javadoc as being correct and change the spec to match. The NoLocal flag determines whether messages sent using the connection that created the durable subscription should be added to it. Its significance ceases when the connection is closed. If the second call to createDurableSubscription uses a different connection then the value of noLocal that it specifies is completely independent of the previous value and does not render the durable subscription invalid. It is therefore not necessary to delete the durable subscription and create a new one.



 Comments   
Comment by Nigel Deakin [ 15/May/12 ]

When I logged this issue I think I was misunderstanding the meaning of the noLocal parameter. A clarified definition of this parameter is proposed in http://java.net/jira/browse/JMS_SPEC-65#action_339660 . This proposes we interpret noLocal as meaning "If noLocal is set to true, and the client identifier is set, then any messages published using this connection or any other with the same client identifier will not be added to the durable subscription."

In this case the value of noLocal remains a part of the definition of the durable subscription for the whole of its lifetime. This means that an attempt to activate the durable subscription using a different value of noLocal will invalidate the subscription, and so should cause the subscription to be deleted and recreated.

If the proposals in http://java.net/jira/browse/JMS_SPEC-65#action_339660 are approved then I propose that we resolve this issue by doing the opposite of what I first proposed, and to change the javadoc to match the specification.

Comment by Nigel Deakin [ 17/Sep/12 ]

Following the changes for JMS_SPEC-65, the API docs and spec have been clarified as follows:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, or, if the client identifier is set, a different noLocal value, then the durable subscription will be deleted and a new one created.

However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, or, if the client identifier is set, a different noLocal value, then a JMSException or JMSRuntimeException will be thrown.





[JMS_SPEC-82] Clarify definition of JMSExpiration, replacing GMT with UTC Created: 28/Feb/12  Updated: 21/Sep/12  Resolved: 19/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1, 2.0
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Minor
Reporter: mickhayes Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

N/A


Tags: pd20-added

 Description   

1.1 and the draft 2.0 make multiple references to (Greenwich Mean Time) GMT.
It would be an improvement to remove all reference to GMT in this standard, and replace with UTC instead.



 Comments   
Comment by mickhayes [ 28/Feb/12 ]

I should add that there is some overlap with JMS_SPEC-44, in that it covers GMT-mentioning parts.
Regards,
Mick Hayes.

Comment by Nigel Deakin [ 28/Feb/12 ]

Yes, the reference to GMT is somewhat anachronistic, though I note that the Java SE 7 javadocs are not very consistent in this matter (e.g. the method getTime() on java.util.Date refers to GMT, whereas the method currentTimeMillis() on java.lang.System refers to UTC). However I agree UTC is the way to go.

Adding tag for consideration for the public release.

It is worth adding that although the JMS 1.1 spec refers to "the GMT at the time of the send or publish" it doesn't specify how the time is represented as a long. I would expect implementation will use System.currentTimeMillis() )(which is the number of ms since a certain time in 1970) but there's nothing in the spec that requires this.

Comment by Nigel Deakin [ 19/Sep/12 ]

All references have now been changed from GMT to UTC. In addition the definition of the JMSExpiration message header field has been clarified.

In the JMS 1.1 specification, section 3.4.9 "JMSExpiration", a message's expiration time was defined as "the sum of the time-to-live value specified on the send method and the current GMT value".

However the JMSExpiration header field is a long value and the specification does not define how the expiration time is converted to a long.

This has now been clarified to state that it is "the difference, measured in milliseconds, between the expiration time and midnight, January 1, 1970 UTC." This definition is chosen to be consistent with the java.lang.System method currentTimeMillis.

The updated text can be seen in the JMS 2.0 public draft, section 3.4.9 "JMSExpiration" and in the API docs for the Message method getJMSExpiration.

Comment by Nigel Deakin [ 19/Sep/12 ]

Title changed from "Replace GMT with UTC" to "Clarify definition of JMSExpiration, replacing GMT with UTC"

Comment by Nigel Deakin [ 19/Sep/12 ]

This issue is now resolved in the JMS 2.0 public draft. Marking issue as resolved.





[JMS_SPEC-80] Error in example 9.3.3.2 "Reconnect to a topic using a durable subscription" Created: 21/Feb/12  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

Section 9.3.3.2 "Reconnect to a topic using a durable subscription" of the JMS 1.1 specification gives an example of how a client can reconnect to an existing durable subscription. It says:

there are some important restrictions to be aware of:

  • The client must be attached to the same Connection.
  • The Destination and subscription name must be the same.
  • If a message selector was specified, it must also be the same.
    If these conditions are not met, then the durable subscription is deleted, and a new subscription is created.

The first of these points is incorrect. The Connection need not be the same. However the client identifier must be the same as was used when creating the durable subscription originally.



 Comments   
Comment by Nigel Deakin [ 14/May/12 ]

In the JMS 1.1 specification, the whole of this section is

9.3.3.2. Reconnecting to a topic using a durable subscription

To re-connect to a topic that has an existing durable subscription, the client program can simply call session.CreateDurableSubscriber again, using the same parameters that it previously used. A client program may be intermittently connected. Using durable subscriptions allows messages to still be available to a client program that consumes from a topic, even though the client program was not continuously connected.

/* Reconnect to a durable subscription */
session.createDurableSubscriber(newsFeedTopic,"mySubscription");

This reconnects the client program to the topic, and any messages that arrived while the client was disconnected are delivered.

However, there are some important restrictions to be aware of:

• The client must be attached to the same Connection.
• The Destination and subscription name must be the same.
• If a message selector was specified, it must also be the same.

If these conditions are not met, then the durable subscription is deleted, and a new subscription is created.

Comment by Nigel Deakin [ 14/May/12 ]

I've now updated the draft spec with the following updated text, which corrects this error and also updates it to reflect the fact that a durable subscription may have more than one consumer, and to make a more accurate distinction between topic, durable subscription and consumer.

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Here is the new text:

9.3.3.2. Creating a consumer on an existing durable subscription

Once a durable subscription has been created it will continue to accumulate messages until the subscription is deleted using the Session method unsubscribe, even if the original consumer is closed leaving no consumer on the durable subscription.

A client application may create a consumer on an existing durable subscription by calling one of the Session methods createDurableConsumer or createDurableSubscriber, supplying the same parameters that were specified when the durable subscription was first created.

/* Create a consumer on an existing durable subscription */
session.createDurableConsumer(newsFeedTopic, "mySubscription");

If there were no consumers on the durable subscription prior to calling this method then any messages which were added to the subscription whilst it had no consumers will be delivered.

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

When creating a consumer on an existing durable subscription there are some important restrictions to be aware of:

• The Destination and subscription name must be the same as when the durable subscription was first created.

• If the connection's client identifier was set when the durable subscription was first created then the same client identifier must be set when subsequently creating a consumer on it.

• If a message selector was specified when the durable subscription was first created then the same message selector must be specified when subsequently creating a consumer on it.

The change log has been updated to add the following new section:

B.5.19 Correction: Reconnecting to a durable subscription (JMS_SPEC-80)

In the JMS 1.1 specification, section 9.3.3.2 "Reconnect to a topic using a durable subscription" stated that "the client must be attached to the same Connection". This was incorrect and has been corrected to state that the client must use a connection with the same client identifier.

In addition this section has been renamed 9.3.3.2 "Creating a consumer on an existing durable subscription" and rewritten to make it clearer.





[JMS_SPEC-78] JMS implementation of QueueRequestor and TopicRequestor doesn't throw correct exception when destination is null Created: 16/Feb/12  Updated: 20/Mar/13  Resolved: 04/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-197 JMS TCK test queueRequestorExceptionT... Closed
Tags: pd20-added

 Description   

The javadocs for the constructor methods QueueRequestor(session,queue) and TopicRequestor(session,topic) state that a InvalidDestinationException should be thrown if an invalid queue/topic is specified.

http://docs.oracle.com/javaee/6/api/javax/jms/QueueRequestor.html
http://docs.oracle.com/javaee/6/api/javax/jms/TopicRequestor.html

However if a value of null is supplied no exception is thrown, despite this not being valid.

These classes are supplied with JMS rather than by implementations, which is why this is being logged here rather than with any particular JMS provider.

If you look at the implementation:

    public
    QueueRequestor(QueueSession session, Queue queue) throws JMSException {
        this.session = session;
        this.queue   = queue;
        tempQueue    = session.createTemporaryQueue();
        sender       = session.createSender(queue);
        receiver     = session.createReceiver(tempQueue);
    }

you can see why it doesn't throw an exception. Calling createQueue(null) is valid as it creates an anonymous producer. However although this is valid in general it isn't valid here. An explicit check for null needs to be added which should cause a InvalidDestinationException to be thrown.



 Comments   
Comment by Nigel Deakin [ 04/Sep/12 ]

Now fixed.

Note that the implementation of these classes is actually part of the RI.





[JMS_SPEC-77] MapMessage.setBytes API discrepancy found in the javadocs Created: 16/Feb/12  Updated: 21/Sep/12  Resolved: 03/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Minor
Reporter: adf59 Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

N/A


Tags: pd20-added

 Description   

MapMessage API source question.

We notice a discrepancy between setBytes method when passing in empty string or null for name. Why does one method throw NullPointerException and why does the other throw IllegalArgumentException?. By the way the original JMS TCK 1.1 test code for this checks for IllegalArgumentException in both cases. This should be corrected in the JavaDoc.

Below is from the source of the latest javadocs.

MapMessage.java (snippet of code)

    /** Sets a byte array value with the specified name into the Map.
      *
      * @param name the name of the byte array
      * @param value the byte array value to set in the Map; the array
      *              is copied so that the value for <CODE>name</CODE> will
      *              not be altered by future modifications
      *
      * @exception JMSException if the JMS provider fails to write the message
      *                         due to some internal error.
      * @exception NullPointerException if the name is null, or if the name is
      *                          an empty string.
      * @exception MessageNotWriteableException if the message is in read-only
      *                                         mode.
      */

    void
    setBytes(String name, byte[] value)
                        throws JMSException;


    /** Sets a portion of the byte array value with the specified name into the
      * Map.
      *
      * @param name the name of the byte array
      * @param value the byte array value to set in the Map
      * @param offset the initial offset within the byte array
      * @param length the number of bytes to use
      *
      * @exception JMSException if the JMS provider fails to write the message
      *                         due to some internal error.
      * @exception IllegalArgumentException if the name is null or if the name is
      *                          an empty string.
      * @exception MessageNotWriteableException if the message is in read-only
      *                                         mode.
      */

    void
    setBytes(String name, byte[] value,
                 int offset, int length)
                        throws JMSException;


 Comments   
Comment by Nigel Deakin [ 22/Feb/12 ]

Tidied up formatting.

Comment by Nigel Deakin [ 22/Feb/12 ]

In JMS 1.1 there are twelve methods on MapMessage of the form setSomething(name, value).

Eleven of them specify that a IllegalArgumentException is thrown "if the name is null or if the name is an empty string."

One of them, setBytes(name, value), specifies that a java.lang.NullPointerException is thrown "if the name is null, or if the name is an empty string."

This looks like an error in the javadocs, and is confirmed by the TCK tests which (you report) expect a IllegalArgumentException in this latter case.

I'll recommend to the expert group that this be fixed in the Public Draft.

Comment by Nigel Deakin [ 03/Sep/12 ]

Now fixed in JMS 2.0 Public Draft





[JMS_SPEC-70] Define annotations for injecting MessagingContext objects Created: 03/Feb/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-64 Define simplified JMS API Resolved
blocks MQ-177 Implement injection of JMSContext obj... Closed
blocks JMS_SPEC-33 Improving the JMS API with API simpli... Resolved
Tags: pd20-added

 Description   

The simplified API (JMS_SPEC-64) defines a single object, javax.jms.MessagingContext, which provides methods for sending and receiving messages.

It is proposed that the JMS API define some standard annotations that can be used to inject MessagingContext objects into application code.

  • The injection point should allow the application define the two parameters needed to create a MessagingContext: JNDI name (of the connection factory) and sessionMode. Both should be optional with suitable defaults.
  • The implementation should ideally be implemented using CDI and have behaviour consistent with it. However this is not essential.
  • It must be possible to use injection in Java EE applications. It is desirable but not essential to be able to use injection in Java SE applications.
  • Injected MessagingContexts must have an appropriate scope and must be automatically closed when they fall out of scope.


 Comments   
Comment by Nigel Deakin [ 08/Feb/12 ]

Here is the proposed text to be added to the JMS spec:

This section relates to application classes which run in the Java EE web, EJB or application client containers and which support injection. Section EE.5 of the Java EE specification lists the application classes that support injection.

Applications may declare a field of type javax.jms.MessagingContext and annotate it with the javax.inject.Inject annotation:

@Inject
private MessagingContext context;

The container will inject a MessagingContext. It will have request scope and will be automatically closed when the request ends. However, unlike a normal CDI request-scoped object, a separate MessagingContext instance will be injected for every injection point.

The annotation javax.jms.JMSConnectionFactory may be used to specify the JNDI lookup name of the ConnectionFactory used to create the messaging context. For example:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
private MessagingContext context;

If no lookup name is specified or the JMSConnectionFactory annotation is omitted then the platform default JMS connection factory will be used.

The annotation javax.jms.JMSSessionMode may be used to specify the session mode of the messaging context:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
@JMSSessionMode(MessagingContext.AUTO_ACKNOWLEDGE)
private MessagingContext context;

The meaning and possible values of session mode are the same as for the ConnectionFactory method createMessagingContext(int sessionMode):

  • In the Java EE application client container, session mode may be set to any of MessagingContext.SESSION_TRANSACTED, MessagingContext.CLIENT_ACKNOWLEDGE, MessagingContext.AUTO_ACKNOWLEDGE or MessagingContext.DUPS_OK_ACKNOWLEDGE. If no session mode is specified or the JMSSessionMode annotation is omitted a session mode of MessagingContext.AUTO_ACKNOWLEDGE will be used.
  • In a Java EE web or EJB container, when there is an active JTA transaction in progress, session mode is ignored and the JMSSessionMode annotation is unnecessary.
  • In a Java EE web or EJB container, when there is no active JTA transaction in progress, session mode may be set to either of MessagingContext.AUTO_ACKNOWLEDGE or MessagingContext.DUPS_OK_ACKNOWLEDGE. If no session mode is specified or the JMSSessionMode annotation is omitted a session mode of MessagingContext.AUTO_ACKNOWLEDGE will be used.

For more information about the use of session mode when creating a messaging context, see section 10.3 of the JMS 2.0 Early Draft, "Behaviour of JMS sessions in the Java EE web or EJB container" and the API documentation for the ConnectionFactory method createMessagingContext(int sessionMode).

Comment by Nigel Deakin [ 08/Feb/12 ]

The proposed new annotations are as follows:

New annotation javax.jms.JMSConnectionFactory:

package javax.jms;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
 * This optional annotation may be used to specify the JNDI lookup name of a <code>javax.jms.ConnectionFactory</code>
 * to be used when injecting a <code>javax.jms.MessagingContext</code> object.
 */
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface JMSConnectionFactory {
    /**
     * (Optional) Specifies the JNDI lookup name of a <code>javax.jms.ConnectionFactory</code>
     * to be used when injecting a <code>javax.jms.MessagingContext</code> object.
     */
    String value() default "";
}

New annotation javax.jms.JMSSession:

package javax.jms;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
 * This optional annotation may be used to specify the session mode
 * to be used when injecting a <code>javax.jms.MessagingContext</code> object.
 * The meaning and possible values of session mode are the same as for the 
 * <code>ConnectionFactory</code> method <code>createMessagingContext(int sessionMode)</code>.
 * 
 * @see javax.jms.MessagingContext#createMessagingContext(int) 
 */
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface JMSSessionMode {
    /**
     * (Optional) Specifies the session mode used when injecting a <code>javax.jms.MessagingContext</code> object.
     */
    int value() default MessagingContext.AUTO_ACKNOWLEDGE;
}
Comment by Nigel Deakin [ 10/Feb/12 ]

I've now updated the API, javadocs and the draft spec in accordance with the proposals made above.

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The only changes are the two annotations javax.jms.JMSConnectionFactory and javax.jms.JMSSession.

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

See particularly the new section 13.3 "Injection of MessagingContext objects" and a full set of examples in section 11.4 "Examples using the simplified API". The change log for the simplified API, section B.5.12 has also been updated.

Comment by Nigel Deakin [ 17/Feb/12 ]

I've updated the API, javadocs and the draft spec in accordance with the following changes.

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

A new annotation has been added to allow the application to specify the user and password to be used when injecting a MessagingContext:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
@JMSPasswordCredential(userName="admin",password="mypassword")
private MessagingContext context;

A new annotation has been added to allow the application to configure whether the connection is automatically started when a consumer is created:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
@JMSSessionMode(MessagingContext.AUTO_ACKNOWLEDGE)
@JMSAutoStart(false)
private MessagingContext context;
Comment by Nigel Deakin [ 21/Sep/12 ]

This feature has been further revised: an up-to-date description may be found in section 11.3 "Injection of JMSContext objects" in the JMS 2.0 public draft.

11.3. Injection of JMSContext objects

Comment by Nigel Deakin [ 26/Oct/12 ]

This issue is now closed as a full definition of how JMSContext objects may be injected will be included in the JMS 2.0 public draft.





[JMS_SPEC-64] Define simplified JMS API Created: 08/Dec/11  Updated: 20/Mar/13  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-176 Implement simplified API for JMS 2.0 Closed
blocks JMS_SPEC-33 Improving the JMS API with API simpli... Resolved
blocks JMS_SPEC-70 Define annotations for injecting Mess... Resolved
Tags: pd20-added

 Description   

This is a request for a simplified JMS API. This would achieve the following goals:

  • To reduce the number of objects needed to send and receive messages, and in particular to combine the JMS 1.1 Connection, Session, MessageProducer and MessageConsumer objects as much as possible.
  • To take advantage of the fact that this is a new API to simplify method signatures and make other simplifications which cannot be made to the old API because it would break backwards compatibility.
  • To maintain a consistent style with the existing API where possible so that users of the old API feel it to be an evolution which that can learn quickly.
  • To support, and offer benefits to, both Java EE and Java SE applications.
  • To allow resource injection to be exploited in those environment which support it, whilst still offering significant improvements for those environments which do not.
  • To provide the option to send and receive message payloads to be sent and received directly without the need to use javax.jms.Message objects.
  • To remove as much as possible the need to catch JMSException on method calls
  • To be functionally complete. The old API will remain to provide backwards compatibility. However the new API is intended to be functionally as complete as the old JMS 1.1 API. Users should not need to switch back to the old API to perform an operation that is unavailable in the new API.


 Comments   
Comment by Nigel Deakin [ 08/Dec/11 ]

A proposed API is described in JMS20SimplifiedAPIv1.pdf with javadocs in jms-2.0-javadoc.jar

Comment by Nigel Deakin [ 03/Feb/12 ]

I've now updated the API, javadocs and the draft spec in accordance with the proposals made above.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

See particularly the new interfaces javax.jms.MessagingContext, javax.jms.SyncMessageConsumer and the new factory methods on javax.jms.Connection.createMessagigingContext

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

See particularly the new chapter 13 "Simplified JMS API" and the change log in section 11.5.16.

Note that these changes cover the simplified API only. They do not include any proposals for injection of JMS objects (which will be handled in a separate JIRA issue).

Comment by Nigel Deakin [ 17/Feb/12 ]

I've updated the API, javadocs and the draft spec in accordance with the following changes.

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Added new methods on MessagingContext to send the Map and byte[] payloads directly as MapMessage and BytesMessage.

Extended existing methods on SyncMessagingContext that receive message payloads directly to support MapMessage and BytesMessage

Added new method methods on MessagingContext: setAutoStart() and getAutoStart(). These allow the autostart behaviour (where the connection is automatically started when a consumer is created) to be disabled.

The spec has been clarified to define when MessagingContext.setClientID may be called and when it may not. The JMS 1.1 spec says that Connection.setClientID may only be called immediately after the conneciton is created and prior to doing anything else with the connection. Since the factory method to create a MessagingContext creates a connection and then uses it to create a session this means that calling MessagingContext.setClientID after this would never be valid. The spec has therefore been clarified to state that this is indeed valid.

Comment by Nigel Deakin [ 21/Mar/12 ]

Following discussions, I have changed the API for consuming messages asynchronously to require the use of a separate consumer. This means that applications cannot set a message listener directly on the MessagingContext. Instead they need to create a consumer object and set the message listener on that.

The new combined consumer object (for sync and async delivery) is called JMSConsumer
For reasons of consistency, MessagingContext has been renamed JMSContext

I've updated the API, javadocs and the draft spec with these changes

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

API and Javadoc changes

Changes to SyncMessageConsumer

  • Renamed to JMSConsumer
  • New method getMessageListener added
  • New method setmessageListener added
  • New method getBatchMessageListener added
  • New method setBatchMessageListener added

Changes to MessagingContext

  • Renamed to JMSContext
  • Existing method createSyncConsumer (3 methods) renamed to createConsumer
  • Existing method createSyncDurableConsumer (2 methods) renamed to createDurableConsumer
  • Existing method setmessageListener (5 methods) deleted
  • Existing method setBatchMessageListener (5 methods) deleted
  • Existing method createMessagingContext renamed to createContext

Changes to ConnectionFactory

  • Existing method {{createMessagingContext (4 methods) renamed to createContext

Spec changes

Section 11.2.4 "Consuming messages asynchronously" has been completely deleted.

Section 11.2.5 "Consuming messages synchronously" has been renamed 11.2.4 "Consuming messages" and updated to cover async message delivery as well.

Following the deletion of the section mentioned above, sections 11.2.6, 11.2.7, 11.2.8 and 11.2.9 become 11.2.5, 11.2.6, 11.2.7 and 11.2.8.

In section A.2 "Unresolved issues in the JMS 2.0 Early Draft", subsection A.2.1 "Simplified JMS API: Support for multiple consumers on a session" has been deleted since this issue has now been resolved.

References to MessagingContext have been changed to JMSContext throughout
References to SyncMessageConsumer have been changed to JMSConsumer throughout

Section 11.4. "Examples using the simplified API" has been updated to reflect these API changes.

Note that the spec does not attempt to record the changes between the Early Draft and this version, since this would be too complicated.

Comment by Nigel Deakin [ 21/Sep/12 ]

The API for sending messages has been completely revised to introduce a new interface JMSProducer. For a full description see section 11.2.4 "Sending messages" in the JMS 2.0 public draft.





[JMS_SPEC-44] New API to specify delivery delay Created: 08/Aug/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-166 Implement Delivery Delay Closed
blocks MQ-184 Topic subscription matching time/Queu... Closed
Tags: ed20-added

 Description   

This issue was raised by members of the JSR 343 Expert Group and is logged here to allow the issue to be discussed and tracked.

This is a proposal to allow a JMS client to specify a delivery delay when sending a message. If a delivery delay has been specified for a message then the message will not be delivered to any consumers until after the delivery delay has expired.

This feature has also been referred to as "delivery time", "timed messages" or "future messages".

The API for delivery delay is intended to be similar to that for the existing timeToLive property of a MessageProducer and the corresponding JMSExpiration header field of a Message.

There would be new methods on javax.jms.MessageProducer:

 
public void setDeliveryDelay(long deliveryDelay) throws javax.jms.JMSException;

This sets the minimum length of time in milliseconds from its dispatch time 
that a produced message should be retained by the messaging system before 
delivery to a consumer. 

If the delivery delay is greater then the time to live then the message 
will always be expired before delivery.
public long getDeliveryDelay()

Returns the minimum length of time in milliseconds from its dispatch time 
that a produced message should be retained by the messaging system before delivery to a consumer. 

There would be new methods on javax.jms.Message:

public long getJMSDeliveryTime() throws JMSException

Returns the message's delivery time. 

When a message is sent, the JMSDeliveryTime header field is left unassigned. 
After completion of the send or publish method, it holds the minimum delivery time time 
of the message. This is the sum of the delivery delay value specified by the client and 
the GMT at the time of the send or publish. 

When the delivery delay is specified as zero, JMSDeliveryTime is set to zero to indicate
that there is no delivery delay.

A provider must not deliver a message before the defined delivery time has been reached.
public void setJMSDeliveryTime(long deliveryTime) throws JMSException

Sets the message's delivery time.

JMS providers set this field when a message is sent. 
This method can be used to change the value for a message that has been received. 

Note that this public method is not intended for use by clients but is needed to allow providers to set this value on a message implemented by a different provider. There is a separate issue to clarify this behaviour: JMS_SPEC-34



 Comments   
Comment by Nigel Deakin [ 19/Dec/11 ]

Following the various comments, the proposed API is as follows:

New methods on MessageProducer

    /** Sets the default minimum length of time in milliseconds from its dispatch time
     * before a produced message becomes visible on the target destination and available
     * for delivery to consumers.  
     *
     * <P>deliveryDelay is set to zero by default.
     *
     * @param deliveryDelay the delivery delay in milliseconds.
     *
     * @exception JMSException if the JMS provider fails to set the delivery
     *                         delay due to some internal error.
     *
     * @see javax.jms.MessageProducer#getDeliveryDelay
     * @see javax.jms.Message#DEFAULT_DELIVERY_DELAY
     * 
     * @since 2.0
     */
  
   void setDeliveryDelay(long deliveryDelay) throws JMSException;      
   
   /** Gets the default minimum length of time in milliseconds from its dispatch time
    * before a produced message becomes visible on the target destination and available
    * for delivery to consumers.  
    *
    * @return the delivery delay in milliseconds.
    *
    * @exception JMSException if the JMS provider fails to get the delivery 
    *                         delay due to some internal error.
    *
    * @see javax.jms.MessageProducer#setDeliveryDelay
    * 
    * @since 2.0
    */ 

  long getDeliveryDelay() throws JMSException;   

New methods on MessagingContext:

/** Sets the default minimum length of time in milliseconds from its dispatch time
 * before a produced message becomes visible on the target destination and available
 * for delivery to consumers.  
 *
 * <P>deliveryDelay is set to zero by default.
 *
 * @param deliveryDelay the delivery delay in milliseconds.
 *
 * @exception JMSRuntimeException if the JMS provider fails to set the delivery
 *                         delay due to some internal error.
 *
 * @see javax.jms.MessagingContext#getDeliveryDelay
 * @see javax.jms.Message#DEFAULT_DELIVERY_DELAY
 */

void setDeliveryDelay(long deliveryDelay);      

/** Gets the default minimum length of time in milliseconds from its dispatch time
* before a produced message becomes visible on the target destination and available
* for delivery to consumers.  
*
* @return the delivery delay in milliseconds.
*
* @exception JMSRuntimeException if the JMS provider fails to get the delivery 
*                         delay due to some internal error.
*
* @see javax.jms.MessagingContext#setDeliveryDelay
*/ 

long getDeliveryDelay();   

New methods on Message:

    /** Gets the message's delivery time value.
     *  
     * <P>When a message is sent, the <CODE>JMSDeliveryTime</CODE> header field 
     * is left unassigned. After completion of the <CODE>send</CODE> or 
     * <CODE>publish</CODE> method, it holds the delivery time of the
     * message. This is the sum of the deliveryDelay value specified by the
     * client and the GMT at the time of the <CODE>send</CODE> or 
     * <CODE>publish</CODE>.
     *
     * <P>A message's delivery time is the earliest time when a provider may
     * make the message visible on the target destination and available for
     * delivery to consumers. 
     *
     * <P>Clients must not receive messages before the delivery time has been reached.
     * 
     * @return the message's delivery time, which is the sum of the deliveryDelay 
     * value specified by the client and the GMT at the time of the <CODE>send</CODE> or 
     * <CODE>publish</CODE>.
     *  
     * @exception JMSException if the JMS provider fails to get the message 
     *                         expiration due to some internal error.
     *
     * @see javax.jms.Message#setJMSDeliveryTime(long)
     * 
     * @since 2.0
     */ 
   long getJMSDeliveryTime() throws JMSException;


   /** Sets the message's delivery time value.
     *
     * <P>This method is for use by JMS providers only to set this field 
     * when a message is sent. This message cannot be used by clients 
     * to configure the delivery time of the message. This method is public
     * to allow one JMS provider to set this field when sending a message
     * whose implementation is not its own.
     *  
     * @param expiration the message's delivery time value
     *  
     * @exception JMSException if the JMS provider fails to set the delivery 
     *                         time due to some internal error.
     *
     * @see javax.jms.Message#getJMSDeliveryTime() 
     * 
     * @since 2.0
     */ 
   void setJMSDeliveryTime(long deliveryTime) throws JMSException;    

A new static constant on Message:

    /** The message producer's default delivery delay is zero.
     * @since 2.0
     */
    static final long DEFAULT_DELIVERY_DELAY = 0;  
Comment by Nigel Deakin [ 19/Dec/11 ]

I've now updated the javadocs and the draft spec with details of this new feature (these changes are additive, so those docs include other changes).

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar
(See two new methods on MessageProducer, two new methods on MessagingContext, and two new methods and a static constant on Message.

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf
(all changes are highlighted clearly with changebars. The changes for this issue are as follows:

A new section 3.4.13 "JMSDeliveryTime" which states:

When a message is sent, its delivery time is calculated as the sum of the delivery delay value specified on the send method and the current GMT value. On return from the send method, the message’s JMSDeliveryTime header field contains this value. When a message is received its JMSDeliveryTime header field contains this same value.

A message's delivery time is the earliest time when a provider may make the message visible on the target destination and available for delivery to consumers.

Clients must not receive messages before the delivery time has been reached.

A new section 4.13 "Delivery delay" which states:

A client can specify a delivery delay value in milliseconds for each message it sends. This value defines a message delivery time which is the sum of the message’s delivery delay and the GMT it is sent (for transacted sends, this is the time the client sends the message, not the time the transaction is committed).

A message's delivery time is the earliest time when a JMS provider may make the message visible on the target destination and available for delivery to consumers. The provider must not deliver messages before the delivery time has been reached.

For more information on message delivery delay, see Section 3.4.13 "JMSDeliveryTime".

Section 4.4.10.2 "Order of message sends" has been updated to state that messages with a later delivery time may be delivered after messages with an earlier delivery time.

Section 4.4.11 "Message Acknowledgement" has been updated to state that when a session's recover method is called the messages it now delivers may be different from those that were originally delivered due to the delivery of messages which could not previously be delivered as they had not reached their specified delivery time.

Section 4.6 "Message Producer" has been updated to mention that a client may now define a default delivery delay for messages sent by a producer.

Section 11.5.4 "Delivery delay" is the change log for this feature.

A deliberate decision was made to leave section 3.4.12 "Overriding message header fields" unchanged. This means that the spec will not permit an administrator to configure JMS to override the client specified values for JMSDeliveryTime.

Comment by Nigel Deakin [ 21/Sep/12 ]

Further updates have been made. For an up-to-date description of this feature, see section 4.12 "Delivery delay" of the JMS 2.0 public draft.

Just one issue remains: this is described in section A.3.1 in the JMS 2.0 early draft.





[JMS_SPEC-43] New API to send a message with async acknowledgement from server Created: 05/Aug/11  Updated: 26/Nov/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-174 Implement new API to send a message w... Closed
Duplicate
is duplicated by JMS_SPEC-12 Message producer confirms aka async m... Resolved
Tags: ed20-added

 Description   

This is a proposal for a new API which will send a message and return immediately without blocking until an acknowledgement has been received from the server. Instead, when the acknowledgement is received, an asynchronous callback will be invoked.

Here is a suggested API:

There would be a new method on javax.jms.MessageProducer:

public void setAcknowledgeListener(AcknowledgeListener listener);

This would change the behaviour of any subsequent call to any of the four send methods so that they would return without blocking until an acknowledgement has been received from the server. When the acknowledgement is received, the callback method on the AcknowledgeListener is received.

This feature will only be available for non-transacted sessions. if setAcknowledgeListener was called on a transacted session then a javax.jms.IllegalStateException would be thrown.

 
package javax.jms;
import javax.jms.Message;

public interface AcknowledgeListener {
	public void onAcknowledge(Message message);
}



 Comments   
Comment by timlfox [ 05/Aug/11 ]

Another, IMO, nicer way of doing this is to pass in some kind of CompletionHandler as an extra method in the send() method on the MessageProducer. When the message is acked, this would be called.

This technique allows an anonymous class (or lambda in Java 8) to implement the CompletionHandler which can act as a closure around some state associated with the send, which makes programming easier for the developer.

e.g

for (int i = 0; i < 100; i++) {
  producer.send(message, new CompletionHandler() {
    public void onComplete() { database.delete(i); }
  });
}

or in Java 8:

for (int i = 0; i < 100; i++) {
  producer.send(message, #{ database.delete(i) });
}

With your proposal this would be more complex - the developer would have to maintain a map of message against, whatever data was necessary to complete the request.

This technique is also more in fitting with the new asynchronous channels used in java.nio.channels

Comment by Nigel Deakin [ 05/Aug/11 ]

Good idea. Thanks for this and all your other comments.

Comment by Nigel Deakin [ 20/Sep/11 ]

Here is an alternative proposal based on Tim's comments above:

This is a proposal for a new API which will send a message and return immediately without blocking until an acknowledgement has been received from the server. Instead, when the acknowledgement is received, an asynchronous callback will be invoked.

There would be two new send methods on javax.jms.MessageProducer:

send(Message message, 
   javax.jms.AcknowledgeListener acknowledgeListener ) 
send(Message message, int deliveryMode, int priority, long timeToLive, 
   javax.jms.AcknowledgeListener acknowledgeListener) 

This would have the same behaviour as the corresponding existing send methods except that that they would return without blocking until an acknowledgement has been received from the server. When the acknowledgement is received, the callback method on the supplied AcknowledgeListener is invoked.

These methods allow a different callback object to be specified for each message that is sent. This allows applications to can pass in an anonymous class with message-specific state, which would not be possible if the same callback object were used for multiple messages.

This feature will only be available for non-transacted sessions. if these methods are called on a transacted session then a javax.jms.IllegalStateException would be thrown.

 
package javax.jms;
import javax.jms.Message;

public interface AcknowledgeListener {
	public void onAcknowledge(Message message);
}

Comment by Hiram Chirino [ 13/Dec/11 ]

A send may fail so the interface AcknowledgeListener should extend ExceptionListener.

Comment by Hiram Chirino [ 13/Dec/11 ]

Async acknowledgements would be handy for all potentially blocking JMS operations. I would be nice to have the same kind of support added to the commit and message.acknowledge methods.

Comment by Hiram Chirino [ 13/Dec/11 ]

Since JMS already uses the 'Acknowledge' term for consumer acking messages, perhaps AcknowledgeListener is not the best interface name. I'd rather see it renamed CompletionHandler as Tim suggested or Callback etc.

Comment by julienrenaut [ 14/Dec/11 ]

Hello all.

Some scenarios might benefit from having two different kind of callbacks. One to confirm a message has correctly arrived on the destination queue and another to confirm a message has been correctly delivered to it's recipient (picked up from destination queue).

I propose two different callback interfaces then.

MessageArrivalCallback.java
package javax.jms;
import javax.jms.Message;

public interface MessageArrivalCallback {
    void onArrival(Message message);
}
MessageDeliveryCallback.java
package javax.jms;
import javax.jms.Message;

public interface MessageDeliveryCallback {
    void onDelivery(Message message);
}

And the corresponding overloads of the send method.

send(Message message, MessageArrivalCallback arrivalCallback);

send(Message message, MessageDeliveryCallback deliveryCallback);

send(Message message, MessageArrivalCallback arrivalCallback, MessageDeliveryCallback deliveryCallback);

I don't know if this should be considered a different feature request or if it adds up to this one.

Comment by Nigel Deakin [ 15/Dec/11 ]

Following the various comments, the proposed API is as follows:

I've changed the name of the callback interface to CompletionListener. This allows us to use with other operations than sending a message. It also allows me to word this whole feature without using the word "acknowledge".

I've worded this whole feature in terms of the send operation being performed in a separate thread, including waiting for any "confirmation" from "a JMS server", though I've also tried to state that it is up to the provider exactly how work is divided between the calling thread and the separate thread. I've also clarified that this method can be used even in cases where an ack isn't sent back from the server.

I agree this feature might be extended to Session.commit() or Message.acknowledge() but have deferred that until we have made more progress with the initial use case.

New methods on MessageProducer:

    void
    send(Destination destination, 
	 Message message, 
	 int deliveryMode, 
	 int priority,
	 long timeToLive) throws JMSException;
    
    /** Sends a message using the <CODE>MessageProducer</CODE>'s 
    * default delivery mode, priority, and time to live, 
    * returning immediately and notifying the specified completion listener 
    * when the operation has completed.
    * <p>
    * This method allows the JMS provider to perform the actual sending of the message,
    * and the wait for any confirmation from a JMS server, to take place in a separate thread
    * without blocking the calling thread. When the sending of the message is complete,
    * and any confirmation has been received from a JMS server, the JMS provider calls
    * the <code>onCompletion(Message)</code> method of the specified completion listener. 
    * If an exception occurs in the separate thread 
    * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
    * <p>
    * JMS does not define what operations are performed in the calling thread and what operations, if any,
    * are performed in the separate thread. In particular the use of this method does not itself specify whether
    * the separate thread should obtain confirmation from a JMS server. 
    * <p>
    * The exceptions listed below may be thrown in either thread. 
    *
    * @param message the message to send 
    * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
    *  
    * @exception JMSException if the JMS provider fails to send the message 
    *                         due to some internal error.
    * @exception MessageFormatException if an invalid message is specified.
    * @exception InvalidDestinationException if a client uses
    *                         this method with a <CODE>MessageProducer</CODE> with
    *                         an invalid destination.
    * @exception java.lang.UnsupportedOperationException if a client uses this
    *                         method with a <CODE>MessageProducer</CODE> that did
    *                         not specify a destination at creation time.
    * 
    * @see javax.jms.Session#createProducer 
    * @see javax.jms.CompletionListener 
    *
    * @since 2.0 
    */
void send(Message message, CompletionListener completionListener) throws JMSException;
  
    /** Sends a message, specifying delivery mode, priority, and time to live, 
    * returning immediately and notifying the specified completion listener 
    * when the operation has completed.
    * <p>
    * This method allows the JMS provider to perform the actual sending of the message,
    * and the wait for any confirmation from a JMS server, to take place in a separate thread
    * without blocking the calling thread. When the sending of the message is complete,
    * and any confirmation has been received from a JMS server, the JMS provider calls
    * the <code>onCompletion(Message)</code> method of the specified completion listener. 
    * If an exception occurs in the separate thread 
    * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
    * <p>
    * JMS does not define what operations are performed in the calling thread and what operations, if any,
    * are performed in the separate thread. In particular the use of this method does not itself specify whether
    * the separate thread should obtain confirmation from a JMS server. 
    * <p>
    * The exceptions listed below may be thrown in either thread. 
    *
    * @param message the message to send
    * @param deliveryMode the delivery mode to use
    * @param priority the priority for this message
    * @param timeToLive the message's lifetime (in milliseconds)
    * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
    *  
    * @exception JMSException if the JMS provider fails to send the message 
    *                         due to some internal error.
    * @exception MessageFormatException if an invalid message is specified.
    * @exception InvalidDestinationException if a client uses
    *                         this method with a <CODE>MessageProducer</CODE> with
    *                         an invalid destination.
    * @exception java.lang.UnsupportedOperationException if a client uses this
    *                         method with a <CODE>MessageProducer</CODE> that did
    *                         not specify a destination at creation time.
    *
    * @see javax.jms.Session#createProducer
    * @see javax.jms.CompletionListener 
    * @since 2.0 
    */

  void 
  send(Message message, 
	 int deliveryMode, 
	 int priority,
	 long timeToLive, CompletionListener completionListener) throws JMSException;
  

New callback interface. I decided not to make it extend ExceptionListener because this requires the exception to be a JMSException, whereas when used with the methods on MessagingCOntext (see below) the exception may be a JMSRuntimeException.

public interface CompletionListener {

	/**
	 * Notifies the application that the message has been successfully sent
	 * 
	 * @param message the message that was sent.
	 */
	void onCompletion(Message message);

	/**
	 * Notifies user that the specified exception was thrown while attempting to send the message
	 * 
	 * @param exception the exception
	 */
	void onException(Exception exception);
}

New methods on MessagingContext:

    /** Sends a message to the specified destination, using
     * the <CODE>MessagingContext</CODE>'s default delivery mode, priority,
     * and time to live,
     * returning immediately and notifying the specified completion listener 
     * when the operation has completed.
     * <p>
     * This method allows the JMS provider to perform the actual sending of the message,
     * and the wait for any confirmation from a JMS server, to take place in a separate thread
     * without blocking the calling thread. When the sending of the message is complete,
     * and any confirmation has been received from a JMS server, the JMS provider calls
     * the <code>onCompletion(Message)</code> method of the specified completion listener. 
     * If an exception occurs in the separate thread 
     * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
     * <p>
     * JMS does not define what operations are performed in the calling thread and what operations, if any,
     * are performed in the separate thread. In particular the use of this method does not itself specify whether
     * the separate thread should obtain confirmation from a JMS server. 
     * <p>
     * The exceptions listed below may be thrown in either thread. 
     *
     * @param destination the destination to send this message to
     * @param message the message to send
     * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
     *  
     * @exception JMSRuntimeException if the JMS provider fails to send the message 
     *                         due to some internal error.
     * @exception MessageFormatRuntimeException if an invalid message is specified.
     * @exception InvalidDestinationRuntimeException if a client uses
     *                         this method with an invalid destination.
     * 
     * @see javax.jms.MessagingContext#setDeliveryMode
     * @see javax.jms.MessagingContext#setPriority
     * @see javax.jms.MessagingContext#setTimeToLive
     * @see javax.jms.CompletionListener
     *
     */
     void send(Destination destination, Message message,CompletionListener completionListener);
    /** Sends a message to the specified destination, 
     * specifying delivery mode, priority and time to live,
     * returning immediately and notifying the specified completion listener 
     * when the operation has completed.
     * <p>
     * This method allows the JMS provider to perform the actual sending of the message,
     * and the wait for any confirmation from a JMS server, to take place in a separate thread
     * without blocking the calling thread. When the sending of the message is complete,
     * and any confirmation has been received from a JMS server, the JMS provider calls
     * the <code>onCompletion(Message)</code> method of the specified completion listener. 
     * If an exception occurs in the separate thread 
     * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
     * <p>
     * JMS does not define what operations are performed in the calling thread and what operations, if any,
     * are performed in the separate thread. In particular the use of this method does not itself specify whether
     * the separate thread should obtain confirmation from a JMS server. 
     * <p>
     * The exceptions listed below may be thrown in either thread. 
     * 
     * @param destination the destination to send this message to
     * @param message the message to send
     * @param deliveryMode the delivery mode to use
     * @param priority the priority for this message
     * @param timeToLive the message's lifetime (in milliseconds)
     * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
     *  
     * @exception JMSRuntimeException if the JMS provider fails to send the message 
     *                         due to some internal error.
     * @exception MessageFormatRuntimeException if an invalid message is specified.
     * @exception InvalidDestinationRuntimeException if a client uses
     *                         this method with an invalid destination.
     *
     * @see javax.jms.CompletionListener
     */
     void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive,CompletionListener completionListener);	
Comment by Nigel Deakin [ 15/Dec/11 ]

I've now updated the javadocs and the draft spec with details of this new feature (these changes are additive, so those docs include other changes).

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar
(See two new methods on MessageProducer, two new methods on MessagingContext, and a new interface CompletionListener)

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf
(all changes are highlighted clearly with changebars, but the only place I've changed is Section 4.6 "MessageProducer" and section 11.5.2. "Sending messages asynchronously", which is just a change log)

Comment by Nigel Deakin [ 18/Jul/12 ]

Further changes have been made as follows.

The updated spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

The updated javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar
and can be browsed online at
http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/index.html

API changes

On the CompletionListener callback interface, the onException method has an additional parameter: the message object:

public interface CompletionListener {

  /**
   * Notifies the application that the message has been successfully sent
   * 
   * @param message the message that was sent.
   */
   void onCompletion(Message message);

  /**
   * Notifies user that the specified exception was thrown while attempting to send the specified message
   * 
   * @param message the message that was sent.
   * @param exception the exception
   * 
   */
   void onException(Message message, Exception exception);
}

Spec changes

Section 4.6 "MessageProducer" has been expanded and divided into two: subsection 4.6.1 "Synchronous send" and subsection 4.6.2 "Asynchronous send". Here is the text in 4.6.2 "Asynchronous send":

4.6.2 Asynchronous send

Clients may alternatively send a message using the following methods which permit the JMS provider to perform part of the work involved in sending the message in a separate thread. JMS refers to this as an "asynchronous send".

send(Destination destination, Message message, CompletionListener completionListener)
send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, 
   CompletionListener completionListener)
send(Message message,  CompletionListener completionListener)
send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)

When the message has been successfully sent the JMS provider invokes the callback method onCompletion on an application-specified CompletionListener object. Only when that callback has been invoked can the application be sure that the message has been successfully sent with the same degree of confidence as if a normal synchronous send had been performed. An application which requires this degree of confidence must therefore wait for the callback to be invoked before continuing.

The following information is intended to give an indication of how an asynchronous send would typically be implemented.

In some JMS providers, a normal synchronous send involves sending the message to a remote JMS server and then waiting for an acknowledgement to be received before returning. It is expected that such a provider would implement an asynchronous send by sending the message to the remote JMS server and then returning without waiting for an acknowledgement. When the acknowledgement is received, the JMS provider would notify the application by invoking the onCompletion method on the application-specified CompletionListener object. If for some reason the acknowledgement is not received the JMS provider would notify the application by invoking the CompletionListener's onException method.

In those cases where the JMS specification permits a lower level of reliability, a normal synchronous send might not wait for an acknowledgement. In that case it is expected that an asynchronous send would be similar to a synchronous send: the JMS provider would send the message to the remote JMS server and then return without waiting for an acknowledgement. However the JMS provider would still notify the application that the send had completed by invoking the onCompletion method on the application-specified CompletionListener object.

It is up to the JMS provider to decide exactly what is performed in the calling thread and what, if anything, is performed asynchronously, so long as it satisfies the requirements given in the following sections:

4.6.2.1. Quality of service

After the send operation is complete, which means that the message has been successfully sent with the same degree of confidence as if a normal synchronous send had been performed, the JMS provider must invoke the CompletionListener. The CompletionListener must not be invoked earlier than this.

4.6.2.2. Message order

If the same MessageProducer or JMSContext is used to send multiple messages then JMS message ordering requirements (see section 4.4.10 "Message order") must be satisfied. This applies even if a combination of synchronous and asynchronous sends has been performed. The application is not required to wait for an asynchronous send to complete before sending the next message.

4.6.2.3. Close, commit or rollback

If the session is transacted (uses a local transaction) then when the commit or rollback method is called the JMS provider must block until any incomplete send operations have been completed and all callbacks have returned before performing the commit or rollback.

If the close method is called on the MessageProducer}], {{Session}], {{Connection or JMSContext object then the JMS provider must block until any incomplete send operations have been completed and all callbacks have returned before closing the object and returning.

4.6.2.4. Restrictions on usage in Java EE

An asynchronous send is not permitted in a Java EE EJB or web container. If the application component violates this restriction the send method may throw a JMSException or JMSRuntimeException (depending on the method signature).

4.6.2.5. Message headers

JMS defines a number of message header fields and message properties which must be set by the "JMS provider on send". See section 3.4.11 "How message header values are set" and section 3.5.9 "JMS defined properties". If the send is asynchronous these fields and properties may be accessed on the sending client only after the CompletionListener has been invoked. If the CompletionListener's onException method is called then the state of these message header fields and properties is undefined. See also section 4.6.2.8 "Restrictions on the use of the Message object" below.

4.6.2.6. Restrictions on threading

Applications that perform an asynchronous send must confirm to the threading restrictions defined in section 4.4.6 "Conventions for using a session". This means that the session may be used by only one thread at a time.

Setting a CompletionListener does not cause the session to be dedicated to the thread of control which calls the CompletionListener. The application thread may therefore continue to use the session after performing an asynchronous send. However the CompletionListener's callback methods must not use the session if an application thread might be using the session at the same time.

4.6.2.7. Use of the CompletionListener by the JMS provider

A session will only invoke one CompletionListener callback method at a time. For a given MessageProducer or JMSContext, callbacks will be performed in the same order as the corresponding calls to the asynchronous send method.

A JMS provider must not invoke the CompletionListener from the thread that is calling the asynchronous send method.

An application which does not need to receive notifications when the send has completed or has failed may supply a null CompletionListener. This does not remove the requirement for the close, commit or rollback methods to block until any incomplete send operations have been completed.

4.6.2.8. Restrictions on the use of the Message object

Applications which perform an asynchronous send must take account of the restriction that a Message object is designed to be accessed by one logical thread of control at a time and does not support concurrent use. See section 2.8 "Multi-threading".

After the send method has returned, the application must not attempt to read the headers, properties or payload of the Message object until the CompletionListener's onCompletion or onException method has been called. This is because the JMS provider may be modifying the Message object in another thread during this time.

A JMSException may be thrown if the application attempts to access or modify the Message object after the send method has returned and before the CompletionListener has been invoked.

Javadoc changes

The javadoc comments for all send methods on MessageProducer and JMSContext which perform an asynchromous send have been updated to include the above text.

Comment by Nigel Deakin [ 21/Sep/12 ]

A number of clarifications have been added. For an up-to-date description of this feature, see section 4.6.2 "Asynchronous send" in the JMS 2.0 public draft.





[JMS_SPEC-40] Allow multiple consumers to be created on the same topic subscription Created: 05/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-93 Does changing the noLocal flag when c... Resolved
blocks MQ-175 support optional clientId when creati... Closed
blocks MQ-178 Implement new API to allow multiple c... Closed
blocks MQ-229 Implementing noLocal behavior for sha... Closed
Duplicate
is duplicated by JMS_SPEC-23 Allow and specify clustered durable s... Closed
Tags: pd20-added

 Description   

This proposal would allow multiple message consumers to be used to consume messages from the same durable or non-durable topic subscription. This would increase scalability by allowing messages from a topic to be processed by multiple consumers in a Java SE environment. Note that the existing JMS 1.1 API already allows this to be achieved for messages from a queue.

The multiple consumers might be in the same or different JVMs. Within the same JVM, the multiple consumers might use the same or different sessions and connection. Note, however, that the normal restrictions on the use of a session by multiple threads would continue to apply.

Durable subscriptions

For durable subscriptions, there would be no need to change the existing API. Applications would simply be allowed to create multiple consumers on the same durable subscription:

This affects the following JMS existing JMS 2.1 methods on Session (and its subtypes QueueSession, TopicSession, XASession, XAQueueSession and XATopicSession):

createDurableSubscriber(Topic topic, String name)
createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) 

It also affects the following JMS new JMS 2.0 methods on Session (and its subtypes QueueSession, TopicSession, XASession, XAQueueSession and XATopicSession) (added in JIRA issue 51 ):

createDurableConsumer(Topic topic, String name)
createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

And in the new JMS 2.0 simplified API, it also affects the following method on JMSContext:

createDurableConsumer(Topic topic, String name)
createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

All these methods currently have a restriction "Only one session at a time can have a TopicSubscriber for a particular durable subscription.". This restriction would be removed.

No change is proposed to the existing JMS requirement that only one connection may have a given clientID. This is defined in JMS 1.1 Section 4.4.3.2 "Client identifier", which states:

By definition, the client state identified by a client identifier can be 'in use' by only one client at a time. A JMS provider must prevent concurrently executing clients from using it.

This means that if a durable subscription is created by a connection with clientId set then it will not be possible to create a second consumer on it using a different connection.

However in JMS 2.0, clientId will become optional when creating a durable subscription (see JIRA issue 39). If a durable subscription is created by a connection with clientId unset then other connections may freely create further consumers on the same durable subscription.

This means that for two message consumers on different connections to share a durable subscription, clientId would need to be left unset.

In addition, the effect of using a different topic or message selector than was used when the subscription was first created needs to be amended. Currently this states (from the javadoc for Session.createDurableSubscriber):

A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector. Changing a durable subscriber is equivalent to unsubscribing (deleting) the old one and creating a new one.

This behaviour will continue, but only if there are no other active consumers on the durable subscription. If there is an active consumer on the durable subscription, and an attempt is made to create an additional consumer with a different topic or message selector, then a JMSException will be thrown (in the case of JMSContext a JMSRuntimeException will be thrown).

The semantics for the unsubscribe methods on Session and JMSContext would remain unchanged. The javadocs state that "It is erroneous for a client to delete a durable subscription while there is an active MessageConsumer or TopicSubscriber for the subscription". This will continue to be the case.

Non-durable subscriptions

For non-durable subscriptions, the JMS 1.1 specification specifies that if two non-durable TopicSubscribers are created on the same topic then two independent subscriptions are created: a copy of each message is sent to every consumer on that topic (with an appropriate message selector).

To allow two consumers to share the same subscription, so that they can share the load of processing messages from that subscription, then new API is required. To allow the consumers to specify that they wish to use the same non-durable subscription, they will need to specify the same sharedSubscriptionName.

The following new methods on Session (and its subtypes) are proposed:

MessageConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName);
MessageConsumer createSharedConsumer(
   Destination destination, String sharedSubscriptionName, String messageSelector)
MessageConsumer createSharedConsumer(
   Destination destination, String sharedSubscriptionName, String messageSelector, boolean NoLocal)

Note that if these methods were called simply createConsumer there would be a clash with the existing method createConsumer(Destination destination, String messageSelector). Note that these methods take a Topic, not a Destination.

In the new simplified API, the following new methods on JMSContext are proposed:

JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName)
JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName, String messageSelector)
JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName, String messageSelector, boolean noLocal)

Note that a given shared subscription does not exist if there are no consumers using it.



 Comments   
Comment by Nigel Deakin [ 19/Aug/11 ]

It should be noted that the JMS 1.1 specification currently states that this feature is not currently available.

4.4.15 Concurrent Message Delivery

...

Note that JMS itself does not provide the facilities for concurrently processing a topic’s message set (the messages delivered to a single consumer). A client could use a single consumer and implement all the multithreading logic needed to concurrently process the messages; however, it is not possible to do
this reliably, because JMS does not have the transaction facilities needed to handle the concurrent transactions this would require.

Comment by Nigel Deakin [ 30/Mar/12 ]

Description completely updated.

Comment by Nigel Deakin [ 30/Mar/12 ]

Added a dependency on JMS_SPEC-93, which concerns the effect of changing noLocal when activating a durable subscription.

Comment by Nigel Deakin [ 10/Apr/12 ]

Added clarification that the semantics of the unsubscribe methods on Session and JMSContext would remain unchanged.

Comment by Nigel Deakin [ 13/Apr/12 ]

Javadoc and spec updates (for durable subscriptions)

I've now updated the javadocs and the draft spec to incorporate these changes.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Changes to Javadocs

I've made the following changes to the javadoc for all the following methods on Session:

  • TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException;
  • TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;
  • MessageConsumer createDurableConsumer(Topic topic, String name) throws JMSException;
  • MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;

and for the following methods on JMSContext:

  • JMSConsumer createDurableConsumer(Topic topic, String name);
  • JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal);

I've deleted

Only one session at a time can have a consumer for a particular durable subscription.

and replaced it with:

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

I've deleted

A client can change an existing durable subscription by calling [this method] with the same name and client identifier (if used), and a new topic and/or message selector. Changing a durable subscription is equivalent to unsubscribing (deleting) the old one and creating a new one.

and replaced it with:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, then the durable subscription will be deleted and a new one created. However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, then a JMSException will be thrown.

Changes to spec

Section 6.11.1 "Durable subscriptions", which contains similar text to the javadoc comments of the above methods, has been similarly changed:

I've deleted

Only one session at a time can have a consumer for a particular durable subscription.

and replaced it with:

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

I've deleted

A client can change an existing durable subscription by calling [this method] with the same name and client identifier (if used), and a new topic and/or message selector. Changing a durable subscription is equivalent to unsubscribing (deleting) the old one and creating a new one.

and replaced it with:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, then the durable subscription will be deleted and a new one created. However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, then a JMSException will be thrown.

A new section has been added to Appendix B "Change history" to describe this change.

Comment by Nigel Deakin [ 17/Apr/12 ]

Javadoc and spec updates (for non-durable subscriptions)

I've now updated the javadocs and the draft spec to incorporate these changes.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Changes to Javadocs

I've added the following new methods on Session

  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName) throws JMSException;
  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector) throws JMSException;
  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal) throws JMSException;

and the following new methods on JMSContext

  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName);
  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector);
  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal);

Here's an example of the javadoc for one of the methods on Session:

	/**
	 * Creates a shared non-durable subscription with the specified name on the
	 * specified topic, and creates a <code>MessageConsumer</code> on that
	 * subscription, specifying a message selector and whether messages
	 * published by its own connection should be added to the subscription.
	 * <p>
	 * If a shared non-durable subscription already exists with the same name
	 * and the same topic and message selector then this method creates a
	 * <code>MessageConsumer</code> on the existing subscription.
	 * <p>
	 * A non-durable shared subscription is used by a client which needs to be
	 * able to share the work of receiving messages from a topic subscription
	 * amongst multiple consumers. A non-durable shared subscription may
	 * therefore have more than one consumer. Each message from the subscription
	 * will be delivered to only one of the consumers on that subscription. Such
	 * a subscription is not persisted and will be deleted (together with any 
	 * undelivered messages associated with it) when there are no consumers on it.
	 * <p>
	 * A consumer may be created on a non-durable shared subscription using the
	 * <code>createSharedConsumer</code> methods on <code>JMSContext</code>,
	 * <code>Session</code> or <code>TopicSession</code>.
	 * <p>
	 * If there is an active consumer on the non-durable shared subscription (or
	 * a consumed message from that subscription is still part of a pending
	 * transaction or is not yet acknowledged in the session), and an attempt is
	 * made to create an additional consumer, specifying the same name but a
	 * different topic or message selector, then a <code>JMSException</code>
	 * will be thrown.
	 * <p>
	 * The <code>noLocal</code> argument is for use when the session's connection is also
	 * being used to publish messages to the topic. If noLocal is set to true
	 * then messages published to the topic by its own connection will not be
	 * added to the non-durable shared subscription. The default value of this
	 * argument is false.
	 * <p>
	 * There is no restriction to prevent a shared non-durable subscription and
	 * a durable subscription having the same name. Such subscriptions would be
	 * completely separate.
	 * 
	 * @param topic
	 *            the <code>Topic</code> to subscribe to
	 * @param sharedSubscriptionName
	 *            the name used to identify the shared non-durable subscription
	 * @param messageSelector
	 *            only messages with properties matching the message selector
	 *            expression are added to the non-durable subscription. A value
	 *            of null or an empty string indicates that there is no message
	 *            selector for the non-durable subscription.
	 * @param noLocal
	 *            if true, messages published by its own connection will not be
	 *            added to the non-durable subscription.
	 * 
	 * @throws JMSException
	 *             if the session fails to create the non-durable subscription
	 *             and <code>MessageConsumer</code> due to some internal error.
	 * @throws InvalidDestinationException
	 *             if an invalid topic is specified.
	 * @throws InvalidSelectorException
	 *             if the message selector is invalid.
	 */
	MessageConsumer createSharedConsumer(
           Topic topic, String sharedSubscriptionName, 
           java.lang.String messageSelector, boolean noLocal) 
           throws JMSException;   

Changes to draft spec:

The existing section 6.11 "TopicSubscriber" has been extended to cover shared non-durable subscriptions:

Updated introductory section 6.11 "TopicSubscriber":

A client consumes messages from a topic by creating a subscription on that topic, and creating a MessageConsumer or TopicSubscriber on that subscription.

In general, a subscription will receive a copy of every message sent to the topic. However if a message selector is specified then only those messages whose properties match the message selector will be added to the subscription.

In addition, if the noLocal flag was specified when a MessageConsumer or {{TopicSubscriber}}was created, then any messages sent using the same connection will not be added to the subscription.

Each copy of the message is treated as a completely separate message. Work done on one copy has no effect on any other; acknowledging one does not acknowledge any other; one message may be delivered immediately, while another waits for its consumer to process messages ahead of it.

Subscriptions may be durable or non-durable.

A non-durable subscription exists only so long as a MessageConsumer or TopicSubscriber object exists to consume messages from it. A non-durable subscription may be either unshared or shared.

An unshared non-durable subscription does not have a name and may have only a single MessageConsumer or TopicSubscriber object associated with it. It is created automatically when the MessageConsumer or TopicSubscriber object is created. It is not persisted and is deleted automatically when it is closed. See section 6.11.1 "Unshared non-durable subscriptions" below.

A shared non-durable subscription is identified by name, which may be used to associate several MessageConsumer or TopicSubscriber objects with it. It is created automatically when the first MessageConsumer or TopicSubscriber object is created. It is not persisted and is deleted automatically when the last MessageConsumer or TopicSubscriber object is closed. See section 6.11.2 "Shared non-durable subscriptions" below.

A durable subscription is identified by a name and an optional client identifier, which may be used to associate several MessageConsumer or TopicSubscriber objects with it. A durable subscription is created automatically when the first MessageConsumer or TopicSubscriber object is created. It is persisted and continues to exist until explicitly deleted, even if there are no MessageConsumer or TopicSubscriber objects consuming messages from it. See section 6.11.3 "Durable subscriptions" below.

New section 6.11.1. "Unshared non-durable subscriptions":

An unshared non-durable subscription is the simplest way to consume messages from a topic.

An unshared non-durable subscription is created, and a MessageConsumer created on that subscription, using one of the createConsumer methods on Session, JMSContext or TopicSession.

Alternatively an unshared non-durable subscription is created, and a TopicSubscription created on that subscription, using one of the createSubscriber methods on TopicSession.

An unshared non-durable subscription does not have a name. Each call to createConsumer or createSubscriber creates a new subscription.

An unshared non-durable subscription only exists for as long as the MessageConsumer or TopicSubscriber exists. This means that any messages sent to the topic will only be added to the subscription whilst the MessageConsumer or TopicSubscriber is active. The subscription is not persisted and will be deleted (together with any undelivered messages associated with it) when the consumer is closed.

If a message selector is specified then only messages with properties matching the message selector expression will be added to the subscription.

The noLocal argument may be used to specify that messages published to the topic by its own connection must not be added to the subscription.

Each unshared non-durable subscription has a single consumer. If the application needs to create multiple consumers on the same subscription then a shared non-durable subscription should be used instead. See section 6.11.2 "Shared non-durable subscriptions".

If the application needs to be able to receive messages that were sent to the topic even when there was no active consumer on it then a durable subscription should be used instead. See section 6.11.3 "Durable subscriptions".

New section 6.11.2. "Shared non-durable subscriptions":

A non-durable shared subscription is used by a client which needs to be able to share the work of receiving messages from a topic subscription amongst multiple consumers. A non-durable shared subscription may therefore have more than one consumer. Each message from the subscription will be delivered to only one of the consumers on that subscription.

A shared non-durable subscription is created, and a MessageConsumer created on that subscription, using one of the {[createSharedConsumer}} methods on Session, JMSContext or TopicSession. The same methods may be used to create a MessageConsumer on an existing shared non-durable subscription.

A shared non-durable subscription is identified by a name specified by the client.

A shared non-durable subscription only exists for as long as a MessageConsumer or TopicSubscriber exists on the subscription. This means that any messages sent to the topic will only be added to the subscription whilst a MessageConsumer or TopicSubscriber is active. The subscription is not persisted and will be deleted (together with any undelivered messages associated with it) when the last consumer on the subscription is closed.

If a message selector is specified then only messages with properties matching the message selector expression will be added to the subscription.

The noLocal argument may be used to specify that messages published to the topic by its own connection must not be added to the subscription.

If there is an active consumer on the non-durable shared subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name but a different topic or message selector, then a JMSException will be thrown.

There is no restriction to prevent a shared non-durable subscription and a durable subscription having the same name. Such subscriptions would be completely separate.

Comment by Nigel Deakin [ 13/Sep/12 ]

What does the noLocal mean when the subscription is shared? This question applies to both durable and non-durable subscriptions.

In very broad terms noLocal is a way of designating that if a connection creates a consumer on a subscription, then messages sent by that connection will not be added to the subscription.

For JMS 1.1 non-durable subscriptions this is easy to define, since you can only have one consumer on a subscription, and the moment its connection is closed, the subscription will be deleted.

For JMS 1.1 durable subscriptions this is slightly harder to define, since the connection that created the durable subscription could close and "come back later" to reactivate the same durable subscription. In that case, we define that any messages sent by a connection with the same client identifier as the connection which created the subscription will not be added to the subscription.

In JMS 2.0 we introduce three new features to topic subscriptions:

  • We allow a durable subscription to have multiple consumers (see this issue)
  • We allow the creation of named non-durable subscriptions which may have multiple consumers (see this issue)
  • We allow client identifier to be unset when creating a durable subscription (see JMS_SPEC-39)

What does this mean for noLocal? We need to consider the following cases:

1. Unshared durable subscription with client identifier set
2. Unshared durable subscription with client identifier unset
3. Shared durable subscription with client identifier set
4. Shared durable subscription with client identifier unset
5. Shared non-durable subscription with client identifier set
6. Shared durable non-subscription with client identifier unset

1. Unshared durable subscription with client identifier set

This case is already allowed in JMS 1.1 and the meaning of noLocal has been clarified in JMS_SPEC-65.

Any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

2. Unshared durable subscription with client identifier unset

This case is new in JMS 2.0 and the meaning of noLocal has already been defined in JMS_SPEC-65: this will not be allowed and will throw an exception.

3. Shared durable subscription with client identifier set

This case is new in JMS 2.0. Since two connections cannot have the same client identifier all consumers on the durable subscription must use the same connection. We can simply apply the rule given in (1).

Any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

4. Shared durable subscription with client identifier unset

This case is new in JMS 2.0. We can simply apply the rule given in (2) and not allow this.

5. Shared non-durable subscription with client identifier set

This case is new in JMS 2.0 and we don't have a rule yet which covers it.

We could simply apply the same rule as for durable subscriptions, given in (1) above. However it should be noted that unlike for durable subscriptions, the client identifier will not be part of the subscription name and so we may have multiple consumers with different client identifier. In that case why should we assign a special status to the client identifier that originally created the subscription?

An alternative is to adopt a rule based not on client identifier but on whether the connection has created a consumer on the subscription. In that case, once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This would then give equal status to all consumers. However it would be inconsistent with durable subscriptions.

6. Shared durable non-subscription with client identifier unset

If we adopted the same rule as for durable subscriptions we would simply not allow this. However if we adopted the alternative given in (5) above we could also apply it in this case.

Summary

For shared non-durable subscriptions we have two alternatives:

A. Adopt a rule similar to that for durable subscriptions, based on client id

If noLocal is set to true, and the client identifier is set, then any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

If the client identifier is unset then setting noLocal to true will cause a IllegalStateException to be thrown.

B. Adopt a rule based on whether a connection has created a consumer on the shared subscription

Any messages published by a connection which has created a consumer on the shared non-durable subscription will not be added to the subscription.

Comment by chris.barrow [ 13/Sep/12 ]

I would strongly urge against clientID having any bearing on non-durables.
I would vote for the alternative in 5 (i.e. B), except there is one little wrinkle that needs to be addressed: the part highlighted in the copy below:

An alternative is to adopt a rule based not on client identifier but on whether the connection has created a consumer on the subscription. In that case, once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This would then give equal status to all consumers. However it would be inconsistent with durable subscriptions.

Does the highlighted part means that if I send messages on the connection then shared consumers on the same subscription on the same or different connections would not receive them? I think that is the desirable behavior. My understanding of the intention of the noLocal parameter is that if you are sending a message then you already know about it (and have dealt with it) so you don't need to receive it. And in this case the receiving "you" should include all of the shared message consumers, since presumably they are cooperating to process the messages.

The only unfortunate thing about this is there is an ambiguity if a shared consumer is created with noLocal=false, then a second is created on the same connection with noLocal=true (or vice versa). Which one "wins"? If the intention is that noLocal=true implies a message sent on the same connection will not be received by any of the sharedConsumers (on the same or different connections), then noLocal=true would have to "win", effectively changing the behavior of the first consumer on-the-fly.

If we consider that the behavior for the above corner case is too unexpected, then there is another option (which we could perhaps call alternative "C"). This would be to apply strictly the same behavior as for createConsumer. That is, when a message is sent on a connection, it would be delivered to any one of the shared consumers on the subscription except ones created on that same connection with noLocal=false. But (as well as being potentially harder to implement) I think this is actually less useful behavior, for the reasons pointed out above (cooperating consumers). So my vote is still for B, provided we clearly define the behavior for this corner case.

BTW, it would be worth pointing out (for any of the options) that the message still gets sent to the destination (topic) even if it doesn't get delivered to the subscription.

Comment by clebertsuconic [ 13/Sep/12 ]

Two things: I may be late on that, but why do we need a createSharedConsumer? If you let specify createDurableSubscription without clientID you are basically creating or reattaching the subscription that already existed. You are just using a global parameter. (i.e. no clientID)

In regard to noLocal, I simply believe we should rule out noLocal & clientID=null, that will make things simpler and clearer. I can't foresee any usecase with clientID=null and noLocal=true anyways. (anything other than that would be an anti-pattern IMO)

Comment by chris.barrow [ 13/Sep/12 ]

There is a fundamental difference between durable and non-durable subscriptions, even in the shared consumer case: durables live for ever (until they are explicitly deleted) and they store messages even when there are no active consumers (rather like queues). Non-durables only survive as long as there is at least one active consumer, so there is no persistent message store.

Since clientID has no impact on the identity of a non-durable subscription, I strongly think it should have no influence on their behavior. The issue I pointed out above when two shared non-durable consumers are created on the same connection with different noLocal values would still remain even if we do insist that clientID be set for noLocal=true.

I guess you are worried about the inconsistency between the durable and non-durable cases. I do think you have a point there. Maybe we should reconsider the durable noLocal behavior to make it agnostic about clientID as well? The rule suggested for nondurables ("once a connection has created a consumer on the subscription its messages would no longer be added to the subscription.a") could perfectly well be applied to durables as well. There's no good reason I can see why the noLocal behavior should outlive the consumer (and the connection) in the durables case. After all, it is the subscription that is durable, not the consumer. And it is the consumer that has noLocal=true, not the subscription.

Comment by Nigel Deakin [ 17/Sep/12 ]

To answer Clebert: createSharedConsumer is for non-durable subscriptions. We need a new method because the existing createConsumer method doesn't have a subscriptionName parameter.

For durable subscriptions, I have accepted your suggestion that if the client identifier is not set and noLocal is true then an IllegalStateException should be thrown.

Comment by Nigel Deakin [ 17/Sep/12 ]

To Answer Chris's comment of 13/Sep/12 07:13 PM:

1. My option B was that if noLocal was true then once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This means they would not be delivered to any consumers. I think that was what you were asking for. As you say, if you have multiple consumers on the same subscription they are cooperating to process the messages so they should behave the same way.

2. You ask what would happen if "a shared consumer is created with noLocal=false, then a second is created on the same connection with noLocal=true (or vice versa). Which one wins?"

If the first session still had a consumer on the shared non-durable subscription, then if a second connection or session tried to create a consumer on the same subscription with a different topic, message selector or noLocal value then they are trying to change the nature of the subscription, so it should throw an exception.

Obviously if the first connection was closed before the second connection created the consumer then this would not be a problem, as the subscription would have been deleted when the first consumer was closed.

3. Your option (C) shouldn't then be needed

4. You suggest "it would be worth pointing out (for any of the options) that the message still gets sent to the destination (topic) even if it doesn't get delivered to the subscription."

Yes, definitely. More accurately, even if a message doesn't get added to one particular subscription on the topic, it will still be added to all other elegible subscriptions on the same topic.

To answer Chris's comment of 13/Sep/12 09:51 PM:

5. You write "There's no good reason I can see why the noLocal behavior should outlive the consumer (and the connection) in the durables case. After all, it is the subscription that is durable, not the consumer. And it is the consumer that has noLocal=true, not the subscription."

That's quite an important point. However one could argue that the noLocal flag is really just another kind of message selector on the subscription (based on the client id that sent the message), and so continues to exist irrespective of whether there were any consumers active.

However I think we ultimately have a slightly arbitrary decision here. noLocal is a distinctly obscure feature: it would be interested to know how much it gets used.

We should also consider an option D, which is when the new createSharedConsumer method is used to create a shared non-durable subscription (which is a new feature of JMS 2.0), there is no noLocal option at all.

Comment by Nigel Deakin [ 05/Nov/12 ]

Because shared non-durable subscriptions are so similar in concept to durable subscriptions I think we should aim to make the definition of noLocal for the two types of subscription as similar as possible. This means:

1. Changing the definition of a shared non-durable subscription so that the client identifier, if set, forms part of the name of the shared non-durable subscription (as is already the case with durable subscriptions).

2. Defining noLocal in exactly the same way for shared non-durable subscriptions as for durable subscriptions:

When a durable or shared non-durable subscription is created on a topic, the noLocal argument may be used to specify that messages published to the topic by its own connection or any other with the same client identifier will not be added to the durable subscription. If the client identifier is unset then setting noLocal to true will cause an exception to be thrown.

Since only one connection may have a given client identifier at a time, this means that the noLocal flag may only be used when there is a single connection consuming from a subscription. I believe this is a benefit as it it gives us a clear, simple definition, it maintains consistency with JMS 1.1, and avoiding the need to contrive complex and entirely hypothetical use cases in which noLocal is used in conjunction with multiple consumers.

Following consultation with the expert group and user alias I have now added this definition to the draft specification.

To see the new text in the spec, please download the latest draft here (log in to java.net first) and read section 6.11.2. "Shared non-durable subscriptions"

You can find the updated API documentation for Session.createSharedConsumer here and for JMSContext.createSharedConsumer here

I have added a special note to section A.3. "Unresolved issues in the JMS 2.0 Public Draft" to state that this is an issue which we aren't completely sure about, and that when this specification goes to public review we're particularly welcome comments on it.

Comment by Nigel Deakin [ 14/Nov/12 ]

Reopening this issue as this feature changes the behaviour of Session.createDurableSubscription in an incompatible way

Incompatibility 1.

According to JMS 1.1 section 6.11.1: "Only one session at a time can have a TopicSubscriber for a particular durable subscription.". The spec and API docs do not explicitly state that an attempt to create two {{TopicSubscriber}}s on the same durable subscription should throw an exception, but I think this is implied, at least for the case where different sessions are used.

In JMS 2.0 we are proposing to remove this restriction and allow multiple {{TopicSubscriber}}s(and {{MessageConsumer}}s) to be created on the same durable subscription.

Incompatibility 2.

According to JMS 1.1 section 6.11.1: "Sessions with durable subscribers must always provide the same client
identifier." The spec and API docs do not explicitly state that clientId must be set when calling createDurableSubscription, and that an exception must be thrown if it is not set, but again I think this is is implied.

In JMS 2.0 we are proposing to remove this restriction and allow clientId to be either set or unset when Session.createDurableSubscription is called. If clientId is set then the combination of clientId and subscription name will be used to identify the durable subscription. If clientId is not set then the subscription name will be used to identify the durable subscription.

Comment by Nigel Deakin [ 21/Nov/12 ]

I have updated the API for creating durable subscriptions to retain backwards compatibility with JMS 1.1 as follows:

The following methods have been reverted to the JMS 1.1 behaviour:

Methods on Session:

  • TopicSubscriber createDurableSubscriber(Topic topic, String name) (JMS 1.1)
  • TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 1.1)
  • MessageConsumer createDurableConsumer(Topic topic, String name) (JMS 2.0)
  • MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 2.0)

Methods on JMSContext:

  • JMSConsumer createDurableConsumer(Topic topic, String name)
  • JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will only allow a single consumer on a durable subscription
  • clientId MUST be set

I have also added the following new methods to support shared durable subscriptions:

Methods on Session:

  • MessageConsumer createSharedDurableConsumer(Topic topic, String name)
  • MessageConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

Methods on JMSContext:

  • JMSConsumer createSharedDurableConsumer(Topic topic, String name)
  • JMSConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will allow multiple consumers on a durable subscription
  • clientId may or may not be set

You can see the updated API docs here:
http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/index.html

I have also updated the spec to incorporate these changes:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Comment by Nigel Deakin [ 12/Feb/13 ]

The JMS 2.0 expert group has agreed that the noLocal parameter serves no useful purpose for shared subscriptions (both durable and non-durable) and should be removed.

Changes to Session:

Removed:

  • createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal)

Changed:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

To:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector)

Changes to JMSContext

Removed:

  • createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal)

Changed:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

To:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector)




[JMS_SPEC-33] Improving the JMS API with API simplifications, annotations and CDI Created: 21/Jul/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0PD, 2.0

Type: Improvement Priority: Critical
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-64 Define simplified JMS API Resolved
depends on JMS_SPEC-70 Define annotations for injecting Mess... Resolved
Tags: ed20-added

 Description   

We should provide a modern, easier-to-use API, probably using annotations and CDI. There seemed to be a variety of ideas of how we might do this, and we will need to explore these in detail. Whilst I think we mostly see this as a feature for Java EE containers, there seems to be interest in offering features to those using a Java SE environment as well.

(This issue is a placeholder for discussion on the JSR 343 EG. More information will be added later)



 Comments   
Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-31] change javadoc on session.createQueue and createTopic to make clearer the provider may create a physical destination Created: 15/Jul/11  Updated: 20/Mar/13  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: clebertsuconic Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

Most users have been asking us to add a flag to just create the server's side queue with some default values.

If I add the flag the configuration won't be spec compliant in some people's interpretation as the javadoc says the createQueue / createTopic is not for the physical creation itself.

I'm not sure what to make on the javadoc, the current version says this:

"Note that this method is not for creating the physical queue. The physical creation of queues is an administrative task and is not to be initiated by the JMS API. The one exception is the creation of temporary queues, which is accomplished with the createTemporaryQueue method."

My proposal is to change it to something permissive where the provider may or not create the physical queue. That would be a design choice.



 Comments   
Comment by clebertsuconic [ 15/Jul/11 ]

This is a simple change. We should simply remove the text about physical creation of the queues. I believe most experts will agree this is already currently allowed on the spec.

Comment by rdohna [ 18/Jul/11 ]

+1

But I think that it must be configurable to either throw an exception or to create a new destination. If you have hundreds of queues, I'd rather have an exception than go search around who created this strange new queue. So IMHO at least this behaviour should be required by the spec. Automatically generating destinations should be mentioned as one legal alternative, when so configured... even if it's the default.

Comment by Nigel Deakin [ 09/Mar/12 ]

This issue will be considered by the expert group for inclusion in the JMS 2.0 public draft. Tagging accordingly.

Comment by Nigel Deakin [ 23/Apr/12 ]

My feeling is that we should keep this method as it was originally intended, which is as a way to convert a provider-specific queue name to a javax.jms.Queue object which can be used in the JMS API, and not as a mechanism for creating the physical queue in the server.

However I do think we need to clarify that this method is NOT expected to throw a JMSException if the physical queue does not exist. I think this is pretty clear already but should be clarified: the 1.1 javadoc refers to "if the session fails to create a queue". Given that the javadoc states that this method does not create the physical queue then this error can only mean "fails to create a Queue object".

I know that some JMS providers (Apache ActiveMQ and Oracle GlassFish MQ) allow the queue to be created automatically in the server when the first message is sent to it (or perhaps when a producer or consumer is created). However they don't create the queue when createQueue is called, and do don't violate the statement "this method is not for creating the physical queue".

Here is the existing javadoc description for the createQueue method on Session:

      /** Creates a queue identity given a <CODE>Queue</CODE> name.
      *
      * <P>This facility is provided for the rare cases where clients need to
      * dynamically manipulate queue identity. It allows the creation of a
      * queue identity with a provider-specific name. Clients that depend
      * on this ability are not portable.
      *
      * <P>Note that this method is not for creating the physical queue.
      * The physical creation of queues is an administrative task and is not
      * to be initiated by the JMS API. The one exception is the
      * creation of temporary queues, which is accomplished with the
      * <CODE>createTemporaryQueue</CODE> method.
      *
      * @param queueName the name of this <CODE>Queue</CODE>
      *
      * @return a <CODE>Queue</CODE> with the given name
      *
      * @exception JMSException if the session fails to create a queue
      *                         due to some internal error.
      * @since 1.1
      */

    Queue createQueue(String queueName) throws JMSException;

I think this is basically correct, though the phrase "queue identity" is a bit mysterious. I've now reworded it as follows:

	/**
	 * Creates a <code>Queue</code> object which encapsulates a specified
	 * provider-specific queue name.
	 * <p>
	 * The use of provider-specific queue names in an application may render the
	 * application non-portable. Portable applications are recommended to not
	 * use this method but instead look up an administratively-defined
	 * <code>Queue</code> object using JNDI.
	 * <p>
	 * Note that this method simply creates an object that encapsulates the name
	 * of a queue. It does not create the physical queue in the JMS provider.
	 * JMS does not provide a method to create the physical queue, since this
	 * would be specific to a given JMS provider. Creating a physical queue is
	 * provider-specific and is typically an administrative task performed by an
	 * administrator, though some providers may create them automatically when
	 * needed. The one exception to this is the creation of a temporary queue,
	 * which is done using the <code>createTemporaryQueue</code> method.
	 * 
	 * @param queueName
	 *            A provider-specific queue name
	 * @return a Queue object which encapsulates the specified name
	 * 
	 * @throws JMSException
	 *             if a Queue object cannot be created due to some internal
	 *             error
	 */
	Queue createQueue(String queueName) throws JMSException;

I've made this change to the createQueue method on Session and, mutatis mutandis, to the createTopic method on Session and the createQueue and createTopic methods on JMSContext.

The new javadocs may be browsed here

I've also updated the change list in the draft spec to refer to this change. See section B.5.18 "Clarification: Session methods createQueue and createTopic".

The draft spec may be downloaded here (you need to log in to java.net first)

Comment by Nigel Deakin [ 21/Sep/12 ]

For the final wording see the API docs to accompany the JMS 2.0 public draft.





Generated at Sat Apr 29 12:55:33 UTC 2017 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.