[JMS_SPEC-4] Properties on Messages should follow builder pattern. Created: 11/May/11  Updated: 10/Apr/12  Resolved: 10/Apr/12

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

Type: New Feature Priority: Major
Reporter: John D. Ament Assignee: Unassigned
Resolution: Won't Fix Votes: 2
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Currently, methods such as javax.jms.Message.setBoolean return void. However, in recent years the builder pattern has grown in adoption, allowing developers to chain method calls by having the method return the object that the method was performed upon. If the property methods return these objects, then the code would look much cleaner.



 Comments   
Comment by abien [ 18/Jun/11 ]

I would change the syntax and use a withBoolean, instead of setBoolean in general. setters in Java do imply void return type.
The final call of the method build() could verify the consistency of all set values and message.

Comment by Nigel Deakin [ 28/Feb/12 ]

Are you referring to the methods for setting message properties, such as setBooleanProperty(String name, boolean value)?

I'll raise this with the expert group. Tagging for review prior to the public draft.

This is an issue of API style, but my inclination is to avoid changing this long-established API.

It might be argued that if a method such as setBooleanProperty(String name, boolean value) was to return a value, it should return the previous value of the property, just like the equivalent methods on java.util.Map and java.util.Property.

Nigel

Comment by Nigel Deakin [ 10/Apr/12 ]

Although the builder pattern is an established design pattern, the JMS API was defined a long time ago and adding new methods at this stage would simply be undesirable bloat.

I am therefore closing this issue as "won't fix".





[JMS_SPEC-46] Define standard API to create and configure a ConnectionFactory Created: 11/Aug/11  Updated: 27/Mar/12  Resolved: 27/Mar/12

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Won't Fix Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

This is a proposal to extend the JMS specification to define a standard way of instantiating and configuring connection factory objects.

Background

A connection factory is an example of an administered object. The JMS 1.1 specification establishes the convention whereby administered objects (connection factories and destinations) are not created in application code. Instead they are created by an administrator using tools specific to the JMS provider and stored in JNDI. The application code then looks up the connection factory or destination from JNDI and uses them in accordance with the JMS API.

The purpose of this is clearly stated in the specification: it is to allow everything that is non-standard and specific to a particular JMS provider to be kept out of the code itself. (See Relevant sections of the JMS 1.1 Specification below).

In the case of connection factories, this means that the application doesn't have to contain any information about how to connect to the JMS provider. For example, if the JMS provider is running on some remote server, the application doesn't contain any information about the location of the server or the protocol used to connect to it. All this information is defined when the connection factory is created by an administrator, separate from the application itself.

However the JMS specification says nothing about how the connection factory itself is created or configured, other than saying that it is done by "provider-specific facilities". All it says is that:

  • it must implement javax.jms.ConnectionFactory,
  • it must implement javax.naming.Referenceable and java.io.Serializable, so it can be stored in all JNDI naming contexts (section 4.2)
  • it is recommended that implementations "follow the JavaBeans design patterns"
  • it allows client identifier to be set (section 4.3.2)

However the specification does not define:

  • how a connection factory is instantiated
  • how the location of the server is defined
  • how client identifier is set
  • how other properties are set

Now although this omission from the JMS 1.1 specification is no doubt deliberate, it does cause some difficulties:

  • it is not possible to develop standard tools for creating connection factories (and binding them in JNDI) which work with multiple JMS providers
  • in a Java EE environment, there is no standard way of configuring the JMS requirements of a particular application
  • it is inconsistent with way in which a JDBC DataSource objects is defined, both in a Java SE and a Java EE environment. This is discussed more in How JDBC DataSource objects are configured.

Proposals

It is proposed that the way that a ConnectionFactory is created and configured be partially standardised in a manner similar to JDBC DataSource objects, as follows:

  • A ConnectionFactory implementation is a JavaBean, and may be instantiated by executing the no-arg constructor of its implementation class. For example:
ConnectionFactory cf = Class.forName("com.sun.messaging.ConnectionFactory") 
  • The JMS specification will define a set of properties which may be used to identify and describe a ConnectionFactory implementation.
Property name Type Description
description String description of this connection factory
user String user name (may be overridden when createConnection is called)
password String password corresponding to user name may be overridden when createConnection is called)
networkProtocol String network protocol used to communicate with the JMS provider
serverName String server name of the JMS provider
portNumber String port number of the JMS provider
networkProtocols String[] array of network protocols used to communicate with the JMS provider
serverNames String[] array of server names of the JMS provider
portNumbers String[] array of port numbers of the JMS provider
url String Opaque string which defines how to connect to the JMS provider
clientId String JMS client identifier
  • ConnectionFactory properties follow the convention specified for properties of JavaBeans components in the JavaBeans 1.01 Specification. ConnectionFactory implementations may augment this set with implementation-specific properties. If new properties are added, they must be given names that do not conflict with the
    standard property names.
  • ConnectionFactory implementations must provide "getter" and "setter" methods for each property they support. These properties typically are intended to be initialized before the object is bound in JNDI for subsequent use by an application.
  • ConnectionFactory properties are not intended to be directly accessible by JMS clients. This design is reinforced by defining the access methods on the implementation class rather than on the public DataSource interface used by applications. Furthermore, the object that the client manipulates can be a wrapper that only
    implements the ConnectionFactory interface. The setter and getter methods for the properties need not be exposed to the client.
  • Management tools that need to manipulate the properties of a ConnectionFactory implementation can access those properties using introspection.

Note that this gives three alternative ways to define how the connection factory should communicate with the server:

  • an opaque URL string
  • a tuple of (networkProtocol, serverName, portNumber), where networkProtocol may be omitted
  • an array of such tuples, represented here as three separate arrays

A JMS provider may support all, some or none of these alternatives.

  • If both URL and one of the other forms are supported and both are supplied, the URL is used.
  • If the single tuple (networkProtocol, serverName, portNumber) is supported, then a single-element array of tuples will also be supported

(Much of the wording above is based on section 9.4.1 DataSource properties of the JDBC 4.0 specification.)

Please also see the following additional information which has been added as separate notes below:

  • How JDBC DataSource objects are configured
  • Relevant sections of the JMS 1.1 Specification


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

How JDBC DataSource objects are configured

This section describes how, although JDBC DataSource objects are similar in concept to JMS ConnectionFactory objects, the JDBC and Java EE specifications define in much more detail how DataSource objects are created and configured than the JMS specification defines for ConnectionFactory objects.

A JMS ConnectionFactory is a factory for creating connections to a JMS provider, using the createConnection method. In JDBC, a javax.jdbc.DataSource fulfils a similar role as a factory for creating connections to a JDBC database, using the getConnection method.

Section 9.4.2 recommends that javax.jdbc.DataSource objects are stored in JNDI to allow database-specific configuration to be kept separate from the application. This much is similar to JMS.

However the JNDI specification differs from JMS in providing a lot of guidance on how to create a DataSource. Section 9.4.1 contains a whole list of standard data source properties which may be supported:

  • databaseName
  • dataSourceName
  • description
  • networkProtocol
  • password
  • portNumber
  • roleName
  • serverName
  • user

Although the specification suggests that not all DataSource implementations support all properties, it does define names for these most common properties, and specifies that when supported, they must be configurable using standard JavaBeans "setters and getters".

In addition, a DataSource may be instantiated by invoking its no-arg constructor. This isn't stated explicitly in the spec (if the DataSource were a JavaBean then a no-arg constructor would be mandatory, but the spec only states that its properties follow the conventions specified for properties of JavaBeans, not that a DataSource is itself a JavaBean) but in practice the convention that it can is well-established.

This means that a DataSource may be instantiated, given the name of the implementation class as a String, using code of the following form:

DataSource ds = Class.forName("oracle.jdbc.pool.OracleDataSource") 

Meanwhile, the Java EE 6 specification defines a DataSourceDefinition annotation and a corresponding <data-source> element which defines the following properties of a DataSource:

  • className (required)
  • name (required)
  • databaseName
  • description
  • initialPoolSize
  • isolationLevel
  • loginTimeout
  • maxIdleTime
  • maxPoolSize
  • maxStatements
  • minPoolSize
  • password
  • portNumber
  • properties
  • serverName
  • transactional
  • url
  • user

This is a longer list than is defined in JDBC, partly because the JDBC spec is older, but also because it also includes pooling properties. Perhaps of the most interest is the url property, which may be provided as an alternative to serverName and port.

Comment by Nigel Deakin [ 11/Aug/11 ]

Relevant sections of the JMS 1.1 Specification

The relevant sections of the JMS specification are given below:

Section 2.3 Administration

It is expected that JMS providers will differ significantly in their underlying messaging technology. It is also expected there will be major differences in how a provider’s system is installed and administered.

If JMS clients are to be portable, they must be isolated from these proprietary aspects of a provider. This is done by defining JMS administered objects that are created and customized by a provider's administrator and later used by clients. The client uses them through JMS interfaces that are portable. The administrator creates them using provider-specific facilities.

There are two types of JMS administered objects:

• ConnectionFactory - This is the object a client uses to create a connection with a provider.
• Destination - This is the object a client uses to specify the destination of messages it is sending and the source of messages it receives.

Administered objects are placed in a JNDI namespace by an administrator. A JMS client typically notes in its documentation the JMS administered objects it requires and how the JNDI names of these objects should be provided to it.

Section 4.2 Administered Objects

JMS administered objects are objects containing JMS configuration information that are created by a JMS administrator and later used by JMS clients. They make it practical to administer JMS applications in the enterprise.

Although the interfaces for administered objects do not explicitly depend on JNDI, JMS establishes the convention that JMS clients find them by looking them up in a namespace using JNDI.

An administrator can place an administered object anywhere in a namespace. JMS does not define a naming policy.

This strategy of partitioning JMS and administration provides several benefits:

• It hides provider-specific configuration details from JMS clients.
• It abstracts JMS administrative information into Java objects that are easily organized and administered from a common management console.
• Since there will be JNDI providers for all popular naming services, this means JMS providers can deliver one implementation of administered objects that will run everywhere.

An administered object should not hold on to any remote resources. Its lookup should not use remote resources other than those used by JNDI itself.

Clients should think of administered objects as local Java objects. Looking them up should not have any hidden side effects or use surprising amounts of local resources.

JMS defines two administered objects, Destination and ConnectionFactory.

It is expected that JMS providers will provide the tools an administrator needs to create and configure administered objects in a JNDI namespace. JMS provider implementations of administered objects should be both javax.naming.Referenceable and java.io.Serializable so that they can be stored in all JNDI naming contexts. In addition, it is recommended that these implementations follow the JavaBeans design patterns.

Section 1.4.6 Java Naming and Directory InterfaceTM (JNDI) API

JMS clients look up configured JMS objects using the JNDI API. JMS administrators use provider-specific facilities for creating and configuring these objects.

This division of work maximizes the portability of clients by delegating provider-specific work to the administrator. It also leads to more administrable applications because clients do not need to embed administrative values in
their code.

Section 4.3.2 Client Identifier

The preferred way to assign a client’s client identifier is for it to be configured in a client-specific ConnectionFactory and transparently assigned to the connection it creates.

Comment by Nigel Deakin [ 27/Mar/12 ]

I am withdrawing this proposal in favour of a simpler alternative. To avoid confusion I have logged this as a separate issue, JMS_SPEC-89





[JMS_SPEC-38] Allow JMS clients to specify whether a message is compressed in transit Created: 05/Aug/11  Updated: 06/Jan/12  Resolved: 06/Jan/12

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

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


 Description   

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

This is a request to allow JMS clients to define whether a message is compressed in transit, perhaps on a per-message basis or more globally.

JMS providers are currently free to decide for themselves whether to compress a message, and many do, so the question here is whether it is desirable to allow clients to control this via the API rather than via provider configuration features.



 Comments   
Comment by colincrist [ 12/Sep/11 ]

I'd say this is an administrative configuration in the provider and out of the scope of the API. Allowing each endpoint to choose makes administering a large install a headache as you need a code change to enable compression.

Better for the provider to be configured centrally to make a client compress based on username/clientID/queue/topic/wildcard

Comment by Nigel Deakin [ 06/Jan/12 ]

I don't think there's a need for this. Many providers already offer message compression. The JMS spec deliberately doesn't define the wire format of a message and so providers are free to compress messages in transit if they wish to.

In my view, message compression is best configured using global settings in the provider rather than on a per-message basis. This is because whether message compression is needed for a given message depends on the performance characteristics of the provider itself: there is a trade-off between the extra time needed to compress and decompress a large message and the time saved in sending a smaller message down the wire. This trade-off will vary from provider to provider, and so allowing the application code to directly configure whether a message is compressed would reduce its portability.

A further reason for keeping message compression as a provider-specific configuration option rather than as part of the JMS API is that it allows providers to decide for themselves what configuration options they want to provider. Some providers may not support message compression at all. Others may offer a global switch to allow message compression to be switched on or off. Others may allow message compression to be defined on a per-destination basis. Other may allow the administrator to define a size threshold above which messages will be compressed. Finally, some providers may allow the administrator to configure what compression algorithm is used. I feel this is an area where it is beneficial to allow providers to differ and offer whatever features that they believe provide best performance.

Comment by Nigel Deakin [ 06/Jan/12 ]

We've discussed this on the JSR 343 expert group and the original proposer and decided not to proceed with this proposal. I'm therefore closing this issue with a resolution of "won't fix"





[JMS_SPEC-23] Allow and specify clustered durable subscribers Created: 04/Jul/11  Updated: 09/Mar/12  Resolved: 09/Mar/12

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

Type: Improvement Priority: Major
Reporter: F.Degenaar Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JMS_SPEC-40 Allow multiple consumers to be create... Resolved

 Description   

The current specification arguably disallows clustering durable subscibers by the following wording: "Only one session at a time can have a TopicSubscriber for a particular durable subscription."

At least one JMS provider (WebSphereMQ) allows multiple TopicSubscribers to the same durable subscription. The subscribers themselves basically act like receivers for a queue.

This feature helps avoiding a single point of failure.



 Comments   
Comment by Nigel Deakin [ 09/Mar/12 ]

Thank you for raising this. This is a good idea which others have proposed as well and is being considered by the expert group for inclusion in the JMS 2.0 early draft. There's a separate (subsequent) JIRA issue which contains the current proposals: JMS_SPEC-40.

I'm going to close this issue as it is a duplicate of that one. Please feel free to comment on that other issue, which will be updated as it is considered in more detail.





[JMS_SPEC-35] Remove the use of unchecked exceptions from the JMS API as far as possible Created: 29/Jul/11  Updated: 06/Jan/12  Resolved: 06/Jan/12

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

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


 Description   

In JMS 1.1, almost every method in the JMS API throws a javax.jms.JMSException, which is a checked exception and so needs to be caught and handled by the application.

In practice the developer rarely knows what to do in such circumstances, and provides some generic exception handling that is not specific to JMSException. The result is to clutter the application code with boilerplate exception handling which adds little value.

In addition, the fact that so many API methods throw this checked exception makes it more difficult to construct frameworks on top of the JMS API.

It is therefore proposed that the JSR 343 Expert Group consider whether they should change the JMS API to throw unchecked rather than checked exceptions as much as possible. One simple way of achieving this would be to change javax.jms.JMSException to extend java.lang.RuntimeException instead of java.lang.Exception.

Existing applications which explicitly catch JMSException would not need to be changed.



 Comments   
Comment by rdohna [ 30/Aug/11 ]

fixed typos

Comment by Nigel Deakin [ 20/Oct/11 ]

The Java Tutorial contains the following useful discussion of when an exception should be checked or unchecked.
http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

This includes the advice:

If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

Given that in most cases a client cannot recover from a JMSException (which is why they tend to log the exception and rethrow it), making it an unchecked exception seems appropriate in this case.

Comment by Nigel Deakin [ 20/Oct/11 ]

I've received this comment:

try {
   a{};
} catch (RuntimeException rte){
   b{};
} catch (MyException e) {
   c();
}

In JMS 1.1, if a JMSException in throw in a(), then c() will be called. However if JMSException is changed as proposed above, b() will be called. Also, the above code will not compile because c() is unreachable.

This means that we cannot guarantee that this change will never require code changes.

Comment by Nigel Deakin [ 06/Jan/12 ]

Unfortunately, as noted in the previous comment, to simply make JMSException a subtype of RuntimeException would be an incompatible change as defined in the Java EE compatibility requirements:
http://java.net/projects/javaee-spec/pages/CompatibilityRequirements
This means that this change is not allowed.

There is no reason why new exception classes cannot be defined which are subtypes of RuntimeException and which are thrown by any new methods that are added to JMS. This has been done in the proposed simplified JMS API: http://java.net/jira/browse/JMS_SPEC-64

Comment by Nigel Deakin [ 06/Jan/12 ]

Since this proposal cannot be implemented (for existing methods) without breaking Java EE compatibility requirements, it will be closed with a resolution of "won't fix".





[JMS_SPEC-19] Support for Multi-Part Messages Created: 24/May/11  Updated: 10/May/13  Resolved: 10/May/13

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

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

Tags: pd20-forreview-vague

 Description   

Has it ever considered by the EG to add support to multi-part messages?



 Comments   
Comment by Nigel Deakin [ 09/Mar/12 ]

Can you please provide more information about what you are suggesting? This is too vague a description to be able to review.

Nigel

Comment by fribeiro [ 10/May/13 ]

You may want to go ahead and close the issue.

Comment by Nigel Deakin [ 10/May/13 ]

Closed as requested by submitter, and because there isn't enough information to review this issue.





[JMS_SPEC-17] Durable subscription iterator Created: 24/May/11  Updated: 09/Mar/12  Resolved: 09/Mar/12

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

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

Issue Links:
Duplicate
duplicates JMS_SPEC-18 Standard set of server JMX MBeans Open
duplicates JMS_SPEC-59 Basic metadata/management via JMS Open

 Description   

As a monitoring client I would like to list all the durable subscriptions the login is permissioned to see., i.e. the clientID, durableName and any selector.



 Comments   
Comment by Nigel Deakin [ 09/Mar/12 ]

I'm merging this proposal with two more general proposals:

JMS_SPEC-59 - which covers general non-JMX metadata queries
JMS_SPEC-18 - which covers general JMX facilities

I'm going to close this issue as a duplicate of those. Feel free to contribute comments to those issues.





[JMS_SPEC-16] Depth of messages for a durable subscription Created: 24/May/11  Updated: 09/Mar/12  Resolved: 09/Mar/12

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: colincrist Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JMS_SPEC-18 Standard set of server JMX MBeans Open
duplicates JMS_SPEC-59 Basic metadata/management via JMS Open

 Description   

As a client I would like to get the current approximate number of pending messages for a durable subscription. All existing providers give this information via a custom API or JMX at present.



 Comments   
Comment by fribeiro [ 24/May/11 ]

My first comment on JMS_SPEC-15 also applies here.

Comment by Nigel Deakin [ 09/Mar/12 ]

I'm merging this proposal with two more general proposals:

JMS_SPEC-59 - which covers general non-JMX metadata queries
JMS_SPEC-18 - which covers general JMX facilities

I'm going to close this issue as a duplicate of those. Feel free to contribute comments to those issues.





[JMS_SPEC-10] Support for Cloud Services Created: 18/May/11  Updated: 10/May/13  Resolved: 02/Mar/12

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

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


 Description   

In addition to the vendors of on-premises software, we should hear from vendors of cloud services (like StormMQ) about any changes to the API that they think would make it easier to implement it.



 Comments   
Comment by abien [ 18/Jun/11 ]

What is the point of your suggestion? Just vendor involvement?

Comment by fribeiro [ 02/Jan/12 ]

Yes, I think it would be hear from them, as well as from the on-premises vendors already on board.

Comment by Nigel Deakin [ 02/Mar/12 ]

The JSR 343 expert group is open to suggestions for new features which will assist could services. Feel free to contact specific organisations and encourage them to get involved.

Since this isn't a specific requirement, I'm going to close this issue. However specific proposals remain welcome. If you'd simply like to discuss an issue, please raise it on the user alias.

Nigel

Comment by fribeiro [ 10/May/13 ]

You may want to go ahead and close the issue.





[JMS_SPEC-8] Add Reference to URI Scheme Created: 17/May/11  Updated: 10/May/13  Resolved: 10/May/13

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: fribeiro Assignee: Unassigned
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

The IETF has published an "official" URI scheme for JMS that should probably be referred to by the next release of the spec.



 Comments   
Comment by fribeiro [ 17/May/11 ]

http://www.rfc-editor.org/rfc/rfc6167.txt

Comment by Nigel Deakin [ 12/Mar/12 ]

I'm not sure this is needed, or even appropriate given that this is a completely separate specification. However this will be raised with the expert group for possible inclusion in the JMS 2.0 public draft.

Comment by fribeiro [ 10/May/13 ]

You may want to go ahead and close the issue.

Comment by Nigel Deakin [ 10/May/13 ]

Closed at request of submitter.





[JMS_SPEC-6] Add Reference to SOAP Binding Created: 17/May/11  Updated: 10/May/13  Resolved: 10/May/13

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: fribeiro Assignee: Unassigned
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

The W3C has developed an "official" SOAP binding for JMS that should probably be referred to by the next release of the spec.



 Comments   
Comment by John D. Ament [ 17/May/11 ]

Can you link to this SOAP binding?

Comment by fribeiro [ 17/May/11 ]

http://www.w3.org/TR/soapjms/

Comment by Nigel Deakin [ 02/Mar/12 ]

What would you like to see added to the JMS spec? It's not obvious that any change is needed; the document referred to is dependent on JMS, not the other way round.

I'll raise this with the expert group (which includes representatives of the organisations that proposed that document).

Comment by fribeiro [ 10/May/13 ]

You may want to go ahead and close the issue.

Comment by Nigel Deakin [ 10/May/13 ]

Closed at request of submitter. Marking as "won't fix".





[JMS_SPEC-61] Selector on JMS body Created: 17/Nov/11  Updated: 08/Jan/13  Resolved: 10/Apr/12

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

Type: New Feature Priority: Major
Reporter: koen.serneels Assignee: Unassigned
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

It would be a very nice feature to apply selectors on the message body.
Possibly using regexp, or XPath in case of TextMessages.
The same for key/value pairs of MapMessage.



 Comments   
Comment by rdohna [ 21/Nov/11 ]

There may be use-cases, but I doubt that this is a good path to follow. It would add a lot of complexity to the spec, and the performance will probably be terrible, as providers can create something similar to an index on all properties, but not on the payload. And the message would have to be unpacked by every filter around, while it's not so easy to see if there could be messages that slip through all of your selectors... or be matched by more than one!

Take it from a different perspective: You suggest regex and/or XPath. What if the content is JSON, or POJOs, or Byte-Arrays, or streamed messages, or ... You'd open up a can of worms where every use-case would require a change to the spec. So you'd have to find a generic form - some kind of filter SAM type seems a good option here. I put such filters exclusively into a content based router, i.e. it does not invoke the business code directly, but forwards the messages to several more specific destinations. This keeps the routing logic in one place where it's easier to make sure that there is no gap or overlap in your logic; and every message would have to be unpacked exactly two times, not up to n times with n selectors.

Comment by Nigel Deakin [ 09/Dec/11 ]

As the previous comment said, we need to be wary of introducing features which are impossible for the JMS provider to implement efficiently. Message properties were invented to allow the provider to handle selectors on a limited amount of information without the need to unmarshall/uncompress/index the entire message payload.

I'll raise it with the expert group after the early draft to see what views there are, especially from the representatives of JMS vendors. If you have any particular priorities please state them (and give as much justification as you can).

Nigel

Comment by Nigel Deakin [ 10/Apr/12 ]

Following a discussion with the JSR 343 expert group, I am rejecting this proposal as it would be contrary to the way in which JMS is designed. Currently message selectors can be used to filter messages on the basis of application-defined message properties. JMS supports message properties expressly to avoid the need for the message selector mechanism to examine the message body, which might be inefficient.

Closing this issue with a resolution of "Won't fix"

Comment by axel_podehl [ 08/Jan/13 ]

I agree with closing this issue.

The implementation of regexp or XPath filtering should be implemented by JMS providers, but can't be defined by the JMS standard. There are too many ways to define these filters and each regex or Xpath package used would have slight differences in syntax.

Also, there's nothing preventing JMS providers to extend the notion of a JMS selector.
In addition to supporting the standard JMS selector, a JMS provider can extend the notion of this selector.

For example to apply the JMS selectors also on the properties of a MapMessages, there's an open source package: http://jamsel.sourceforge.net/

In another product, you can use these types of JMS selector strings:

::regex::.trader=peter.
::xpath::/trade[trader='peter']
::request::fromTime=2002-12-31T14:15:16.123456





[JMS_SPEC-56] Enhance the EJB specification to support the delivery of messages in batches to MDBs Created: 08/Nov/11  Updated: 01/May/12  Resolved: 01/May/12

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

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

Issue Links:
Dependency
depends on JMS_SPEC-36 Allow messages to be delivered asynch... Open
depends on EJB_SPEC-44 Enhance the EJB specification to supp... Resolved
Tags: eg, jms20-jsr345

 Description   

This is a request for changes to the EJB specification to support the asynchronous delivery of messages to a message-driven bean in batches.

This new feature is described in JMS_SPEC-36. To support this there will be a new listener interface javax.jms.BatchMessageListener, which provides the method onMessages(Message[] messages).

Where batch delivery is not required, the existing javax.jms.MessageListener interface and its method onMessage(Message message) will continue to be used as before.

The following changes to the EJB specification are suggested (references are to the EJB 3.1 specification)

Section 5.4.2 "The Required Message Listener Interface"


Change: "The message-driven bean class's implementation of the javax.jms.MessageListenerinterface distinguishes the message-driven bean as a JMS message-driven bean."

To: "The message-driven bean class's implementation of the javax.jms.MessageListener or javax.jms.BatchMessageListener interface distinguishes the message-driven bean as a JMS message-driven bean."

An additional node should be added to state that a JMS message-driven bean may implement either of these interfaces or both.

5.6.2 "Message-Driven Bean Class"


Change: "In the case of JMS, this is the javax.jms.MessageListener interface."

To: "In the case of JMS, this is either the javax.jms.MessageListener or javax.jms.BatchMessageListener interface."

13.6.3.2 "REQUIRED£


In all four places change: "onMessage method"

to: "onMessage or onMessages method"

21.3.5 "JMS 1.1 Requirements"


Change name of section to: "JMS 2.0 Requirements"

Change: "An implementation requiring the full EJB 3.1 API must include the JMS 1.1 extension"

To: "An implementation requiring the full EJB 3.2 API must include JMS 2.0"

In the fourth paragraph,

Change: "Enterprise beans must not call the javax.jms.MessageConsumer.setMessageListener or javax.jms.MessageConsumer.getMessageListener method."

To: "Enterprise beans must not call the javax.jms.MessageConsumer.setMessageListener, javax.jms.MessageConsumer.setBatchMessageListener, javax.jms.MessageConsumer.getMessageListener or javax.jms.MessageConsumer.getBatchMessageListener methods."

5.4.14 "Activation Configuration Properties"


This section introduces a list of activation configuration properties for JMS message-driven beans. An additional section should be inserted which describes the additional properties needed for batch delivery:

Insert new section: 5.4.<n> "Batch delivery" as follows:

If the JMS Message-driven bean implements the javax.jms.BatchMessageListener interface then the following activation configuration properties may be used to configure batch delivery:

  • batchSize: If set to greater than zero, messages will be delivered by calling the onMessages(Message[] messages) method. The bean class must implement javax.jms.BatchMessageListener. Messages will be delivered in batches of up to batchSize messages. The actual batch size used may be any value between one and the specified batchSize. It is invalid to specify a value greater than zero if the bean class does not implement javax.jms.BatchMessageListener.
  • batchTimeout: If batch delivery is used, this specifies the maximum number of milliseconds that the JMS provider may defer message delivery for in order to assemble a batch of messages that is as large as possible but no larger than the batch size.


 Comments   
Comment by Nigel Deakin [ 23/Nov/11 ]

This issue has now been forwarded to the EJB 3.2 expert group as EJB_SPEC-44. Please make further comments there, not here.

Comment by Nigel Deakin [ 01/May/12 ]

Following the decision to defer JMS_SPEC-36 (Allow messages to be delivered asynchronously in batches) I am going to close this issue. If changes are needed to the MDB specification in the future a new issue will be logged.

Comment by Nigel Deakin [ 01/May/12 ]

Closing as "Won'tFix" because that's the nearest resolution I can see to "withdrawn".





[JMS_SPEC-140] Assumptions over Destination name within TCK Created: 05/Nov/13  Updated: 05/Nov/13  Resolved: 05/Nov/13

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

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

When running the tck



 Description   

The Session object for example has createQueue() and createTopic() methods - both taking a string 'name' that provider-specific. The Queue and Topic objects both have methods that can get this name.

The TCK includes a check that gets this and confirms that what is passed in on create is the same as what is got. Not unreasonable; however the TCK has made an assumption of the format of the string used to set. This might not be valid.



 Comments   
Comment by Nigel Deakin [ 05/Nov/13 ]

Sounds a fair comment, particularly if this is a new test in JMS 2.0.

Sorry to be bureaucratic, but if you think the TCK is incorrect can you please take this up directly with the organisation which supplied you with the TCK? You should have the necessary contact details at Java partner Engineering (part of Oracle). You don't need to log these in JIRA first. Email me directly if you need help finding the right contact. nigel.deakin@oracle.com

Comment by mbwhite [ 05/Nov/13 ]

Thanks for the comment - wanted to raise that to see if it sounded reasonable. In this case the TCK supplies something like "QueueNameOne" - and a provider may just say sorry that isn't valid for various reasons.. It could then have to treat it as 'shorthand' or abbreviation. Therefore the string returned could be different but in valid 'providerSyntax'...

No you're right to be bureaucratic - this should be a TCK issue.

Comment by mbwhite [ 05/Nov/13 ]

As commented by Nigel this should raised as TCK issue.





[JMS_SPEC-99] Define annotations for Java EE 7 resource configuration Created: 22/Aug/12  Updated: 10/Sep/12  Resolved: 10/Sep/12

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

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


 Description   

In the Java EE 7 specification:

Section EE.5.17.4 "JMS Connection Factory Resource Definition" states that "A JMS ConnectionFactory resource may also be defined using the JMSConnectionFactoryDefinition annotation

Section EE.5.17.5 "JMS Destination Definition" states that "A JMS Destination resource may also be defined using the JMSDestinationDefinition annotation".

These annotations need to be defined in the javax.jms package as part of JMS 2.0.



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

This is a duplicate of JMS_SPEC-96 and JMS_SPEC-97





[JMS_SPEC-103] A JMS 2.0 resource adapter needs to be able to include cluster name in a generated subscription name Created: 29/Oct/12  Updated: 14/Nov/12  Resolved: 14/Nov/12

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

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

Issue Links:
Dependency
depends on JMS_SPEC-73 Define how messages from a topic are ... Open
blocks MQ-230 Enhance JMSRA to include cluster name... Closed
Tags: pd20-forreview-minor

 Description   

The draft JMS 2.0 specification, chapter 12.1. "ActivationSpec properties" states that:

If a durable subscription is specified but subscriptionName is not specified then the resource adapter will set the name of the durable subscription to be a name which is unique to the deployed MDB.

The intention of this feature is to allow the resource adapter to automatically generate a subscription name automatically which will be different for each deployed MDB but the same for each instance in the cluster. This instances of the same deployed MDB across the whole cluster to share the work of processing messages from the same subscription.

However if the same JMS provider is being used by two different application server clusters, and the two clusters are using the same MDB name, then this would cause the two clusters to share the same subscription which is undesirable.

To avoid this, the subscription name generated by the resource adapter should be composed of (1) a name which uniquely identifies the deployed MDB within thin the cluster as well as (2) a name which uniquely identifies the application server cluster.

The JMS specification needs to be extended to cover (2)



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

This will also require a change to the EJB 3.2 specification which contains a similar definition of what the container does it the subscriptionName property is not set.

Implementing this will require a change to the Java EE specification to make the name of the cluster available.

Comment by Nigel Deakin [ 29/Oct/12 ]

This is an extension of issue JMS_SPEC-73

Comment by Nigel Deakin [ 14/Nov/12 ]

I'm closing this issue as a duplicate of JMS_SPEC-73 because that issue is still open and it is best to keep this as a single open issue.





[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-165] Error in javadoc for Connection#stop and JMSContext#stop Created: 08/Jan/15  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1, 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

The JMS 1.1 javadocs for Connection#stop contains the following text:

This call blocks until receives and/or message listeners in progress have completed.

The same text is found in the JMS 2.0 javadocs for Connection#stop and for JMSContext#stop.

This text is incorrect because it suggests that the call to stop is required to block until all calls to receive have returned. There is no mention of this requirement in the specification itself and it is contradicted by the text that follows it in the javadocs for Connection#stop:

A call to stop must not return until delivery of messages has paused. This means that a client can rely on the fact that none of its message listeners will be called and that all threads of control waiting for receive calls to return will not return with a message until the connection is restarted. The receive timers for a stopped connection continue to advance, so receives may time out while the connection is stopped.

This means that:

  • a call to stop does not force all pending receives to return prematurely.
  • a call to stop is not required to block until all pending receives reach their timeout period (especially as that might be infinite)
  • after the call to stop has returned, pending receives will continue to block until they either (1) reach their timeout and return null or (2) the connection is restarted and a message becomes available, whichever occurs first.

It is suggested that, to keep things simple, we don't try to completely rewrite this but simply delete the incorrect sentence. Note that the requirement to block until message listeners have returned is already covered by the sentence:

If message listeners are running when stop is invoked, the stop call must wait until all of them have returned before it may return. While these message listeners are completing, they must have the full services of the connection available to them.



 Comments   
Comment by Nigel Deakin [ 08/Jan/15 ]

Proposed change to Javadocs for Connection#stop

Existing text:

This call blocks until receives and/or message listeners in progress have completed.

Proposed text:

[Delete this text]

Proposed change to Javadocs for JMSContext#stop

Existing text:

This call blocks until receives and/or message listeners in progress have completed.

Proposed text:

[Delete this text]

Comment by Nigel Deakin [ 09/Jan/15 ]

Updated source for javax.jms.Connection can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/Connection.java?rev=314
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/Connection.java?rev1=313&rev2=314

Updated source for javax.jms.JMSContext can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/JMSContext.java?rev=314
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/JMSContext.java?rev1=313&rev2=314

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-163] Javadoc for JMSContext#setClientID contains obsolete MessageContext reference Created: 01/Dec/14  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

The javadoc for JMSContext#setClientID contains an obsolete mention of MessageContext. This should be changed to JMSContext



 Comments   
Comment by Nigel Deakin [ 01/Dec/14 ]

Changes to javadoc for JMSContext#setClientID

Existing text:

Alternatively, a client can set the client identifier for the MessageContext's connection
using a provider-specific value.

Replacement text:

Alternatively, a client can set the client identifier for the JMSContext's connection
using a provider-specific value.

Comment by Nigel Deakin [ 07/Jan/15 ]

Updated source for javax.jms.JMSContext can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/JMSContext.java?rev=310
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/JMSContext.java?rev1=309&rev2=310

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-155] JMS 2.0 introduced incompatible changes to createSession(bool,int) Created: 16/Jul/14  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

The background

Prior to JMS 2.0, a number of requirements for the behaviour of the JMS API in Java EE applications were defined in the Java EE 6 platform specification and in the EJB 3.1 specification, but were not mentioned in the JMS specification or javadocs. This was confusing for users. To remedy this, JMS 2.0 was extended to incorporate these requirements.

Those extensions to JMS 2.0 were intended to be a rearrangement and clarification of existing requirements and were not intended to introduce changes which were incompatible with Java EE 6 and EJB 3.1 or which would require changes to existing applications.

However it appears that JMS 2.0 may have introduced a number incompatible changes related to the behaviour of the ConnectionFactory method createSession(boolean transacted, int acknowledgeMode) in a Java EE web or EJB application in the case where there is no active JTA transaction in progress and the application has specified the parameter values (true, SESSION_TRANSACTED) or (false,CLIENT_ACKNOWLEDGE).

In the EJB 3.1 specification, section 13.3.5 states

"The Bean Provider should not use the JMS acknowledge method either within a transaction or within an unspecified transaction context. Message acknowledgment in an unspecified transaction context is handled by the container."

The term "unspecified transaction context" is explained in EJB 3.1 section 13.6.5. Although it does not say so explicitly, it is understood to mean those cases where there is there is no active container-managed transaction in progress or where bean-managed transactions are specified but there is no active UserTransaction in progress.

When this requirement was incorporated into the JMS specification, it became the following text in JMS 2.0 section 12.3:

"When an application creates a Session or JMSContext in a Java EE web or EJB container, and there is no active JTA transaction in progress, then the session that is created will be non-transacted and will be automatically-acknowledged. The use of local transactions or client acknowledgement is still not permitted. Parameters may be specified when creating the Session or JMSContext to specify whether the acknowledgement mode should be AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE. If any other session parameter values are specified they will be ignored and an acknowledgement mode of AUTO_ACKNOWLEDGE used."

The problem

Although the JMS 2.0 specification clearly conveys the intent of the EJB 3.1 specification, the requirement given in the EJB specification was loosely worded:

  • EJB 3.1 uses the phrase "should not use the JMS acknowledge method" rather than "must not use the JMS acknowledge method"
  • EJB 3.1 uses the phrase "Message acknowledgment...is handled by the container" without explicitly stating what would happen if the application tries to use client-acknowledgement or local transactions.

It therefore appears (with hindsight) that JMS 2.0 has introduced some additional requirements which are additional to EJB 3.1. In particular it has introduced the requirement that if the application specifies the session parameters as (true, SESSION_TRANSACTED) or (false, CLIENT_ACKNOWLEDGE) then they will be ignored and an acknowledgement mode of AUTO_ACKNOWLEDGE used.

The "Backwards compatibility requirements for Java EE specifications" can be found at
https://java.net/projects/javaee-spec/pages/CompatibilityRequirements

It could be argued that this change does not violate these compatibility requirements. The compatibility requirements state that "Where behavior was undefined or optional in the previous version of the specification then it is permissible to define more explicit behavior in a later version.", which would appear to allow this change (treating EJB 3.1 as the "previous version").

The compatibility requirements also require that "applications that change to using the new version of the specification do not see changes to behaviour that were mandated by the previous version of the specification.". Again, it could be argued that JMS 2.0 did not change behaviour that was mandated by the previous version of the specification" (again (treating EJB 3.1 as the "previous version").

However it has been discovered that at least one JMS vendor has interpreted the EJB 3.1 specification as allowing both client-acknowledgement and local transactions to be used in a Java EE web or EJB application in the case where there is no active JTA transaction.

Given that the EJB 3.1 specification is loosely worded, and that there were no CTS tests to require otherwise, it would appear that this was valid. Therefore, introducing the requirements added in JMS 2.0 would change the behaviour of existing applications, which is contrary to the intent of the backwards compatibility requirements for Java EE specifications.

The proposal

To avoid forcing JMS vendors to change the the behaviour of existing applications, it is proposed to revise section 12.3 of the JMS 2.0 specification, and the corresponding javadocs, as follows:

  • to recommend (rather than require) that applications do not call createSession with the parameters (true, SESSION_TRANSACTED) or (false,CLIENT_ACKNOWLEDGE) when in a Java EE EJB or web application and there is no active JTA transaction, and warn that applications which specify these parameter values may not be portable,
  • to allow JMS providers to choose the behaviour they provide if the application specifies the parameters (true, SESSION_TRANSACTED) when in a Java EE EJB or web application and there is no active JTA transaction from the following options:
    • the JMS provider is recommended but not required to ignore the specified parameters and instead provide a non-transacted, auto-acknowledged session.

    • the JMS provider may alternatively provide a local transacted session.
  • to allow JMS providers to choose the behaviour they provide if the application specifies the parameters (false,CLIENT_ACKNOWLEDGE) when in a Java EE EJB or web application and there is no active JTA transaction from the following options:
    • the JMS provider is recommended but not required to ignore the specified parameters and instead provide a non-transacted, auto-acknowledged session.

    • the JMS provider may alternatively provide a non-transacted session with client acknowledgement.

Change related new methods to stay consistent

Although the issue of backwards compatibility applies only to the following existing methods:

  • Connection method createSession(boolean transacted, int acknowledgeMode)
  • QueueConnection method createQueueSession(boolean transacted, int acknowledgeMode)
  • TopicConnection method createTopicSession(boolean transacted, int acknowledgeMode)

it is proposed that for consistency the same changes are also made to the following methods added in JMS 2.0:

  • Connection method createSession(int sessionMode)
  • ConnectionFactory method createContext(int sessionMode).


 Comments   
Comment by Nigel Deakin [ 03/Dec/14 ]

(Superseded by updated proposals below)

Proposed changes to JMS specification section 12.3 "Behaviour of JMS sessions in the Java EE web or EJB container"

Existing text:

When an application creates a Session or JMSContext in a Java EE web
or EJB container, and there is no active JTA transaction in progress,
then the session that is created will be non-transacted and will be
automatically-acknowledged. The use of local transactions or client
acknowledgement is still not permitted. Parameters may be specified
when creating the Session or JMSContext to specify whether the
acknowledgement mode should be AUTO_ACKNOWLEDGE or
DUPS_OK_ACKNOWLEDGE. If any other session parameter values are
specified they will be ignored and an acknowledgement mode of
AUTO_ACKNOWLEDGE used.

The use of local transactions or client acknowledgement is not
permitted in a Java EE web or EJB container even if there is no active
JTA transaction because this would require applications to be written
differently depending on whether there was a JTA transaction or not.

The JMS API provides the following methods to create a session which
allow the session to be defined using either the two parameters
transacted and acknowledgeMode or by the single parameter
sessionMode. If these methods are called in a Java EE web or EJB
container then these parameters will be overridden as described above.

[4 methods]

It is recommended that applications that run in the Java EE web or EJB
container create a session using the following method which does not
specify a parameter:

[1 method]

The JMS API provides the following methods to create a JMSContext
which allow the session to be defined using the single parameter
sessionMode. If these methods are called in a Java EE web or EJB
container then this parameter will be overridden as described above.

[2 methods]

The following method to create a JMSContext from an existing
JMSContext is not permitted in a Java EE web or EJB container because
it would create a second session on an existing connection, which is
not permitted in a java EE web or EJB container.]

[1 method]

It is recommended that applications that run in the Java EE web or EJB
container creates a JMSContext using one of the following methods
which do not specify a sessionMode:

[2 methods]

Replacement text:

When an application creates a Session or JMSContext in a Java EE web
or EJB container, and there is no active JTA transaction in progress,
then:

  • If the session parameters specify that the session should be
    non-transacted with an acknowledgement mode of AUTO_ACKNOWLEDGE or
    DUPS_OK_ACKNOWLEDGE then the session will be non-transacted and messages
    will be acknowledged according to the specified acknowledgement mode.
  • If the session parameters specify that the session should be
    non-transacted with an acknowledgement mode of CLIENT_ACKNOWLEDGE then the
    JMS provider is recommended to ignore the specified parameters and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a non-transacted session with client
    acknowledgement.
  • If the session parameters specify that the session should be transacted,
    then the JMS provider is recommended to ignore the specified parameters and
    instead provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a local transacted session.
  • Applications running in a Java EE web or EJB container are recommended to
    specify no session parameters or to specify that the session be
    non-transacted with an acknowledgement mode of AUTO_ACKNOWLEDGE or
    DUPS_OK_ACKNOWLEDGE.
  • It is not recommended that applications specify client acknowledgement
    or a local transaction since applications may not be portable. Furthermore
    if the JMS provider does support the use of client acknowledgement
    and local transactions when there is no JTA transaction, the application
    would need to be written differently dependent on whether there was a JTA
    transaction or not.
Comment by Nigel Deakin [ 03/Dec/14 ]

Proposed changes to Javadocs for Connection.html#createSession(boolean, int):

Existing text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • The argument transacted is ignored. The session will always be
    non-transacted, using one of the two acknowledgement modes
    AUTO_ACKNOWLEDGE and DUPS_OK_ACKNOWLEDGE.
  • The argument acknowledgeMode is used to specify how messages
    received by this session will be acknowledged. The only permitted
    values in this case are Session.AUTO_ACKNOWLEDGE and
    Session.DUPS_OK_ACKNOWLEDGE. The value Session.CLIENT_ACKNOWLEDGE
    may not be used. For a definition of the meaning of these
    acknowledgement modes see the links below.

Replacement text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • If transacted is set to false and acknowledgeMode is set to
    JMSContext.AUTO_ACKNOWLEDGE or JMSContext.DUPS_OK_ACKNOWLEDGE then the
    session will be non-transacted and messages will be acknowledged according
    to the value of acknowledgeMode.
  • If transacted is set to false and acknowledgeMode is set to
    JMSContext.CLIENT_ACKNOWLEDGE then the JMS provider is recommended to
    ignore the specified parameters and instead provide a non-transacted,
    auto-acknowledged session. However the JMS provider may alternatively
    provide a non-transacted session with client acknowledgement.
  • If transacted is set to true, then the JMS provider is recommended to
    ignore the specified parameters and instead provide a non-transacted,
    auto-acknowledged session. However the JMS provider may alternatively
    provide a local transacted session.
  • Applications are recommended to set transacted to false and
    acknowledgeMode to JMSContext.AUTO_ACKNOWLEDGE or
    JMSContext.DUPS_OK_ACKNOWLEDGE since since applications which set
    transacted to false and set acknowledgeMode to
    JMSContext.CLIENT_ACKNOWLEDGE, or which set transacted to true, may not be
    portable.

Existing text:

Parameters:

transacted - indicates whether the session will use a local transaction.
If this method is called in the Java EE web or EJB container then this
argument is ignored.

acknowledgeMode - indicates how messages received by the session will be
acknowledged.

  • If this method is called in a Java SE environment or in the Java EE
    application client container, the permitted values are
    Session.CLIENT_ACKNOWLEDGE, Session.AUTO_ACKNOWLEDGE and
    Session.DUPS_OK_ACKNOWLEDGE.
  • If this method is called in the Java EE web or EJB container when
    there is an active JTA transaction in progress then this argument is
    ignored.
  • If this method is called in the Java EE web or EJB container when
    there is no active JTA transaction in progress, the permitted values
    are Session.AUTO_ACKNOWLEDGE and Session.DUPS_OK_ACKNOWLEDGE. In this
    case Session.CLIENT_ACKNOWLEDGE is not permitted.

Replacement text:

Parameters:

transacted - indicates whether the session will use a local transaction,
except in the cases described above when this value is ignored.

acknowledgeMode - when transacted is false, indicates how messages received
by the session will be acknowledged, except in the cases described above
when this value is ignored.

Comment by Nigel Deakin [ 03/Dec/14 ]

Proposed changes to Javadocs for Connection.html#createSession(int):

Existing text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • The argument acknowledgeMode must be set to either of
    Session.AUTO_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE. The session will
    be non-transacted and messages received by this session will be
    acknowledged automatically according to the value of acknowledgeMode. For
    a definition of the meaning of these acknowledgement modes see the links
    below. The values Session.SESSION_TRANSACTED and Session.CLIENT_ACKNOWLEDGE
    may not be used.

Replacement text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • If sessionMode is set to Session.AUTO_ACKNOWLEDGE or
    Session.DUPS_OK_ACKNOWLEDGE then the session will be
    non-transacted and messages will be acknowledged according to the value
    of sessionMode.
  • If sessionMode is set to Session.CLIENT_ACKNOWLEDGE then the JMS
    provider is recommended to ignore the specified parameter and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a non-transacted session with
    client acknowledgement.
  • If sessionMode is set to Session.SESSION_TRANSACTED, then the JMS
    provider is recommended to ignore the specified parameter and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a local transacted session.
  • Applications are recommended to use only the values
    Session.AUTO_ACKNOWLEDGE and Session.DUPS_OK_ACKNOWLEDGE
    since applications which use Session.CLIENT_ACKNOWLEDGE or
    Session.SESSION_TRANSACTED may not be portable.

Existing text:

Parameters:

sessionMode - indicates which of four possible session modes will be used.

  • If this method is called in a Java SE environment or in the Java EE
    application client container, the permitted values are
    Session.SESSION_TRANSACTED, Session.CLIENT_ACKNOWLEDGE,
    Session.AUTO_ACKNOWLEDGE and Session.DUPS_OK_ACKNOWLEDGE.
  • If this method is called in the Java EE web or EJB container when there
    is an active JTA transaction in progress then this argument is ignored.
  • If this method is called in the Java EE web or EJB container when there
    is no active JTA transaction in progress, the permitted values are
    Session.AUTO_ACKNOWLEDGE and Session.DUPS_OK_ACKNOWLEDGE. In this case
    the values Session.TRANSACTED and Session.CLIENT_ACKNOWLEDGE are not permitted.

Replacement text:

Parameters:

sessionMode - specifies the session mode that will be used, except in the
cases described above when this value is ignored. Legal values are
JMSContext.SESSION_TRANSACTED, JMSContext.CLIENT_ACKNOWLEDGE,
JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE.

Comment by Nigel Deakin [ 03/Dec/14 ]

(This proposal has now been dropped. See updated proposals below)

Proposed changes to Javadocs for ConnectionFactory.html.createContext(int):

Existing text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • The argument acknowledgeMode must be set to either of
    JMSContext.AUTO_ACKNOWLEDGE or JMSContext.DUPS_OK_ACKNOWLEDGE. The
    session will be non-transacted and messages received by this session
    will be acknowledged automatically according to the value of
    acknowledgeMode. For a definition of the meaning of these
    acknowledgement modes see the links below. The values
    JMSContext.SESSION_TRANSACTED and JMSContext.CLIENT_ACKNOWLEDGE may
    not be used.

Replacement text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • If sessionMode is set to JMSContext.AUTO_ACKNOWLEDGE or
    JMSContext.DUPS_OK_ACKNOWLEDGE then the session will be
    non-transacted and messages will be acknowledged according to the value
    of sessionMode.
  • If sessionMode is set to JMSContext.CLIENT_ACKNOWLEDGE then the JMS
    provider is recommended to ignore the specified parameter and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a non-transacted session with
    client acknowledgement.
  • If sessionMode is set to JMSContext.SESSION_TRANSACTED, then the JMS
    provider is recommended to ignore the specified parameter and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a local transacted session.
  • Applications are recommended to use only the values
    JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE
    since applications which use JMSContext.CLIENT_ACKNOWLEDGE or
    JMSContext.SESSION_TRANSACTED may not be portable.

Existing text:

Parameters:

sessionMode - indicates which of four possible session modes will be used.

  • If this method is called in a Java SE environment or in the Java EE
    application client container, the permitted values are
    JMSContext.SESSION_TRANSACTED, JMSContext.CLIENT_ACKNOWLEDGE,
    JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE.
  • If this method is called in the Java EE web or EJB container when there
    is an active JTA transaction in progress then this argument is ignored.
  • If this method is called in the Java EE web or EJB container when there
    is no active JTA transaction in progress, the permitted values are
    JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE. In this case
    the values JMSContext.TRANSACTED and JMSContext.CLIENT_ACKNOWLEDGE are not
    permitted.

Replacement text:

Parameters:

sessionMode - specifies the session mode that will be used, except in the
cases described above when this value is ignored. Legal values are
JMSContext.SESSION_TRANSACTED, JMSContext.CLIENT_ACKNOWLEDGE,
JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE.

Comment by Nigel Deakin [ 03/Dec/14 ]

(This proposal has now been dropped. See updated proposals below)

Proposed changes to Javadocs for ConnectionFactory.html.createContext(String, String, int):

Existing text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • The argument acknowledgeMode must be set to either of
    JMSContext.AUTO_ACKNOWLEDGE or JMSContext.DUPS_OK_ACKNOWLEDGE. The session
    will be non-transacted and messages received by this session will be
    acknowledged automatically according to the value of acknowledgeMode.
    For a definition of the meaning of these acknowledgement modes see the
    links below. The values JMSContext.SESSION_TRANSACTED and
    JMSContext.CLIENT_ACKNOWLEDGE may not be used.

Replacement text:

In the Java EE web or EJB container, when there is no active JTA
transaction in progress:

  • If sessionMode is set to JMSContext.AUTO_ACKNOWLEDGE or
    JMSContext.DUPS_OK_ACKNOWLEDGE then the session will be
    non-transacted and messages will be acknowledged according to the value
    of sessionMode.
  • If sessionMode is set to JMSContext.CLIENT_ACKNOWLEDGE then the JMS
    provider is recommended to ignore the specified parameter and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a non-transacted session with
    client acknowledgement.
  • If sessionMode is set to JMSContext.SESSION_TRANSACTED, then the JMS
    provider is recommended to ignore the specified parameter and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a local transacted session.
  • Applications are recommended to use only the values
    JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE
    since applications which use JMSContext.CLIENT_ACKNOWLEDGE or
    JMSContext.SESSION_TRANSACTED may not be portable.

Existing text:

Parameters:

userName - the caller's user name

password - the caller's password

sessionMode - indicates which of four possible session modes will be used.

  • If this method is called in a Java SE environment or in the Java EE
    application client container, the permitted values are
    JMSContext.SESSION_TRANSACTED, JMSContext.CLIENT_ACKNOWLEDGE,
    JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE.
  • If this method is called in the Java EE web or EJB container when there
    is an active JTA transaction in progress then this argument is ignored.
  • If this method is called in the Java EE web or EJB container when there
    is no active JTA transaction in progress, the permitted values are
    JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE. In this
    case the values JMSContext.TRANSACTED and JMSContext.CLIENT_ACKNOWLEDGE
    are not permitted.

Replacement text:

Parameters:

userName - the caller's user name

password - the caller's password

sessionMode - specifies the session mode that will be used, except in the
cases described above when this value is ignored. Legal values are
JMSContext.SESSION_TRANSACTED, JMSContext.CLIENT_ACKNOWLEDGE,
JMSContext.AUTO_ACKNOWLEDGE and JMSContext.DUPS_OK_ACKNOWLEDGE.

Comment by Nigel Deakin [ 17/Dec/14 ]

Updated proposal

Here is an updated proposal which would update the specification and javadocs for the classic API (createSession methods) only but make no changes to the simplified API (createContext methods) on the grounds these new methods do not break backward compatibility and so don't need to be changed.

The following javadoc changes would still be needed:

The changed originally proposed to JMS specification section 12.3 "Behaviour of JMS sessions in the Java EE web or EJB container" would be replaced by the following:

Existing text

12.3 "Behaviour of JMS sessions in the Java EE web or EJB container"

The behaviour of a JMS session in respect of transactions and message
acknowledgement is different for applications which run in a Java EE
web or EJB container than it is for applications which run in a normal
Java SE environment or in the Java EE application client container.

These differences also apply to JMSContext objects, since these
incorporate a JMS session.

When an application creates a Session or JMSContext in a Java EE web
or EJB container, and there is an active JTA transaction in progress,
then the session that is created will participate in the JTA
transaction and will be committed or rolled back when the JTA
transaction is committed or rolled back. Any session parameters that
are specified when creating the Session or JMSContext are ignored. The
use of local transactions or client acknowledgement is not permitted.

This applies irrespective of whether the JTA transaction is demarcated
automatically by the container or programmatically using methods on
javax.transaction.UserTransaction.

The term “session parameters” here refers to the arguments that may be
passed into a call to the createSession or createContext methods to
specify whether the session should use a local transaction and, if the
session is non-transacted, what the acknowledgement mode should be.

When an application creates a Session or JMSContext in a Java EE web
or EJB container, and there is no active JTA transaction in progress,
then the session that is created will be non-transacted and will be
automatically-acknowledged. The use of local transactions or client
acknowledgement is still not permitted. Parameters may be specified
when creating the Session or JMSContext to specify whether the
acknowledgement mode should be AUTO_ACKNOWLEDGE or
DUPS_OK_ACKNOWLEDGE. If any other session parameter values are
specified they will be ignored and an acknowledgement mode of
AUTO_ACKNOWLEDGE used.

The use of local transactions or client acknowledgement is not
permitted in a Java EE web or EJB container even if there is no active
JTA transaction because this would require applications to be written
differently depending on whether there was a JTA transaction or not.

The JMS API provides the following methods to create a session which
allow the session to be defined using either the two parameters
transacted and acknowledgeMode or by the single parameter sessionMode.
If these methods are called in a Java EE web or EJB container then
these parameters will be overridden as described above.

(4 methods)

It is recommended that applications that run in the Java EE web or EJB
container create a session using the following method which does not
specify a parameter:

(1 method)

The JMS API provides the following methods to create a JMSContext
which allow the session to be defined using the single parameter
sessionMode. If these methods are called in a Java EE web or EJB
container then this parameter will be overridden as described above.

(2 methods)

The following method to create a JMSContext from an existing
JMSContext is not permitted in a Java EE web or EJB container because
it would create a second session on an existing connection, which is
not permitted in a java EE web or EJB container.]

(1 method)

It is recommended that applications that run in the Java EE web or EJB
container creates a JMSContext using one of the following methods
which do not specify a sessionMode:

(2 methods)

Replacement text

The behaviour of JMS Session and JMSContext objects in respect of
transactions and message acknowledgement is different for applications
which run in a Java EE web or EJB container than it is for applications
which run in a normal Java SE environment or in the Java EE application
client container.

When an application creates a Session or JMSContext in a Java EE web
or EJB container, and there is an active JTA transaction in progress,
then the session that is created will participate in the JTA
transaction and will be committed or rolled back when the JTA
transaction is committed or rolled back. Any session parameters that
are specified when creating the Session or JMSContext are ignored. The
use of local transactions or client acknowledgement is not permitted.

This applies irrespective of whether the JTA transaction is demarcated
automatically by the container or programmatically using methods on
javax.transaction.UserTransaction.

The term “session parameters” here refers to the arguments that may be
passed into a call to the createSession or createContext methods to
specify whether the session should use a local transaction and, if the
session is non-transacted, what the acknowledgement mode should be.

When an application uses one of the createSession methods to create
a Session, and there is no active JTA transaction in progress,
then:

  • If the session parameters specify that the session should be
    non-transacted with an acknowledgement mode of AUTO_ACKNOWLEDGE or
    DUPS_OK_ACKNOWLEDGE then the session will be non-transacted and messages
    will be acknowledged according to the specified acknowledgement mode.
  • If the session parameters specify that the session should be
    non-transacted with an acknowledgement mode of CLIENT_ACKNOWLEDGE then the
    JMS provider is recommended to ignore the specified parameters and instead
    provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a non-transacted session with client
    acknowledgement.
  • If the session parameters specify that the session should be transacted,
    then the JMS provider is recommended to ignore the specified parameters and
    instead provide a non-transacted, auto-acknowledged session. However the JMS
    provider may alternatively provide a local transacted session.
  • Applications running in a Java EE web or EJB container are recommended to
    specify no session parameters or to specify that the session be
    non-transacted with an acknowledgement mode of AUTO_ACKNOWLEDGE or
    DUPS_OK_ACKNOWLEDGE.
  • It is not recommended that applications specify client acknowledgement
    or a local transaction since applications may not be portable. Furthermore
    if the JMS provider does support the use of client acknowledgement
    and local transactions when there is no JTA transaction, the application
    would need to be written differently dependent on whether there was a JTA
    transaction or not.

When an application uses one of the createContext methods to create
a JMSContext, and there is no active JTA transaction in progress,
then:

  • If the specified session mode is AUTO_ACKNOWLEDGE or
    DUPS_OK_ACKNOWLEDGE then the session will be non-transacted and messages
    will be acknowledged according to the specified acknowledgement mode.
  • If the specified session mode is CLIENT_ACKNOWLEDGE or SESSION_TRANSACTED
    then it will be ignored and a session mode of AUTO_ACKNOWLEDGE used.
  • Applications running in a Java EE web or EJB container are recommended to
    specify no session parameters or to specify that the session be
    non-transacted with an acknowledgement mode of AUTO_ACKNOWLEDGE or
    DUPS_OK_ACKNOWLEDGE.
  • The use of local transactions or client acknowledgement is not
    permitted in a Java EE web or EJB container even if there is no active
    JTA transaction because this would require applications to be written
    differently depending on whether there was a JTA transaction or not.
Comment by Nigel Deakin [ 09/Jan/15 ]

Draft spec now updated.
PDF (with change bar) at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf?rev=315.
Latest PDF at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf

Updated source for javax.jms.Connection can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/Connection.java?rev=315
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/Connection.java?rev1=314&rev2=315

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-157] JMS 2.0 introduced an incompatible restriction on creating two sessions per connection in Java EE Created: 02/Sep/14  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

The background

Prior to JMS 2.0, a number of requirements for the behaviour of the JMS API in Java EE applications were defined in the Java EE 6 platform specification, but were not mentioned in the JMS specification or javadocs. This was confusing for users. To remedy this, JMS 2.0 was extended to incorporate these requirements.

Those extensions to JMS 2.0 were intended to be a rearrangement and clarification of existing requirements and were not intended to introduce changes which were incompatible with Java EE 6 or which would require changes to existing applications.

However it appears that JMS 2.0 has inadvertently introduced an incompatible change related to the use of the Connection method createSession in a Java EE web or EJB application when a session already exists for that connection.

The problem

In the Java EE 6 specification, section EE 6.7 "Java Message Service (JMS) 1.1 Requirements" states that

Application components in the web and EJB containers must not attempt to create more than one active (not closed) Session object per connection. An attempt to use the Connection object’s createSession method when an active Session object exists for that connection should be prohibited by the container. The container may throw a JMSException if the application component violates this restriction. Application client containers must support the creation of multiple sessions for each connection.

This wording states that applications "must" not attempt to create more than one session per connection in the Java EE web or EJB containers. However it only says that the container "should" prohibit this, and that it "may" throw an exception. In accordance with the generally-accepted interpretations of the words "should" and "may", this means that it is optional whether or not the createSession method throws an exception.

When this requirement was incorporated into the JMS 2.0 specification, it became the following text in JMS 2.0 section 12.2.

Applications running in the Java EE web and EJB containers must not attempt to create more than one active (not closed) Session object per connection.

If an application attempts to use the Connection object’s createSession method when an active Session object exists for that connection then a JMSException should be thrown.

If an application attempts to use the JMSContext object’s createContext method then a JMSRuntimeException should be thrown, since the first JMSContext already contains a connection and session and this method would create a second session on the same connection.

This wording continues to use the word "should" which keeps it optional whether or not the createSession method (or createContext method) throws an exception.

In addition to this change, the javadoc for these methods was also updated. Unfortunately the wording used was inconsistent with that in section 12.2.

The javadoc for createSession states that:

Applications running in the Java EE web and EJB containers must not attempt to create more than one active (not closed) Session object per connection. If this method is called in a Java EE web or EJB container when an active Session object already exists for this connection then a JMSException will be thrown.

The words "will be thrown" make it obligatory for the createSession method to throw an exception. This introduces an additional restriction which was not in Java EE 6 (and is not in JMS 2.0 section 12.2) and inadvertently introduces an incompatible change which may cause existing applications to fail.

The corresponding javadoc for createContext contains a similar wording:

This method must not be used by applications running in the Java EE web or EJB containers because doing so would violate the restriction that such an application must not attempt to create more than one active (not closed) Session object per connection. If this method is called in a Java EE web or EJB container then a JMSRuntimeException will be thrown.

This method is new in JMS 2.0 so there is no compatibility issue. Nevertheless the words "will be thrown" make it obligatory for the createContext method to throw an exception, which is inconsistent with the wording in JMS 2.0 section 12.2 which implies that throwing an exception is optional.



 Comments   
Comment by Nigel Deakin [ 02/Dec/14 ]

Proposed changes (superseded by updated proposals below)

JMS specification section 12.2 "Restrictions on the use of JMS API in the Java EE web or EJB container": No changes are proposed.

JMS specification section 12.3 "Behaviour of JMS sessions in the Java EE web or EJB container". Existing text:

The following method to create a JMSContext from an existing JMSContext is
not permitted in a Java EE web or EJB container because it would create a
second session on an existing connection, which is not permitted in a Java EE
web or EJB container.

Replacement text:

The JMS API defines the following method to create a JMSContext from an
existing JMSContext. Applications must not call this method in a Java EE
web or EJB container. See section 12.2 "Restrictions on the use of JMS API
in the Java EE web or EJB container".

JMS specification section 2.8.2. "Key features of the simplified API": Existing text

Applications running in the Java EE web and EJB containers are not permitted
to create more than one active session on a connection...

Modified text: (changed words thus)

Applications running in the Java EE web and EJB containers must not
create more than one active session on a connection...

It is proposed that the javadoc for the Connection object’s three createSession methods be changed to make it consistent with the Java EE 6 specification and with JMS 2.0 section 12.2.

Javadoc for Connection.html#createSession(): Existing text

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If this
method is called in a Java EE web or EJB container when an active Session object
already exists for this connection then a JMSException will be thrown.

Replacement text: (changed word thus)

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If this
method is called in a Java EE web or EJB container when an active Session object
already exists for this connection then a JMSException may be thrown.

Javadoc for Connection.html#createSession(int): Existing text

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If this
method is called in a Java EE web or EJB container when an active Session object
already exists for this connection then a JMSException will be thrown.

Replacement text: (changed word thus)

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If this
method is called in a Java EE web or EJB container when an active Session object
already exists for this connection then a JMSException may be thrown.

Javadoc for Connection.html#createSession(boolean, int): Existing text

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If this
method is called in a Java EE web or EJB container when an active Session object
already exists for this connection then a JMSException will be thrown.

Replacement text: (changed word thus)

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If this
method is called in a Java EE web or EJB container when an active Session object
already exists for this connection then a JMSException may be thrown.

It is also proposed to make the same change to the JMSContext object’s createContext method to to make it consistent with JMS 2.0 section 12.2.

Javadoc for JMSContext.html: Existing text

Applications running in the Java EE web and EJB containers are not permitted to
create more than one active session on a connection so combining them in a single
object takes advantage of this restriction to offer a simpler API.

However applications running in a Java SE environment or in the Java EE application
client container are permitted to create multiple active sessions on the same connection.

Replacement text: (changed words thus)

Applications running in the Java EE web and EJB containers must not
create more than one active session on a connection so combining them in a single
object takes advantage of this restriction to offer a simpler API.

However applications running in a Java SE environment or in the Java EE application
client container may create multiple active sessions on the same connection.

Javadoc for JMSContext.html#createContext(int): Existing text

This method must not be used by applications running in the Java EE web or EJB containers
because doing so would violate the restriction that such an application must not attempt
to create more than one active (not closed) Session object per connection. If this method
is called in a Java EE web or EJB container then a JMSRuntimeException will be thrown.

Replacement text: (changed word thus)

This method must not be used by applications running in the Java EE web or EJB containers
because doing so would violate the restriction that such an application must not attempt
to create more than one active (not closed) Session object per connection. If this method
is called in a Java EE web or EJB container then a JMSRuntimeException may be thrown.

Comment by Nigel Deakin [ 18/Dec/14 ]

Here is an updated proposal for this issue. As with the previous proposal, this would relax from must to should the requirement for the three createSession methods to throw an exception if the application tries to create two sessions for the same connection in a Java EE web or EJB application. This change is necessary to maintain the less strict wording in the Java EE 6 specification and avoid introducing an incompatible change to createSession(boolean, int).

However this proposal leaves unchanged the requirement for the simplified API to throw an exception in the same circumstances. This requirement is already in the javadocs (and enforced by CTS). However the text in section 12.2 of the specification is inconsistent so I am proposing to change it to match the javadocs.

In both cases, the spec will continue to say that the application must not do these things, since this is the wording used in Java EE 6. Note that this is an obligation on the application, and not on the JMS implementation.

JMS specification section 12.2 "Restrictions on the use of JMS API in the Java EE web or EJB container"

Existing text:

Applications running in the Java EE web and EJB containers must not attempt
to create more than one active (not closed) Session object per connection.

  • If an application attempts to use the Connection object’s createSession
    method when an active Session object exists for that connection then a
    JMSException should be thrown.
  • If an application attempts to use the JMSContext object’s createContext
    method then a JMSRuntimeException should be thrown, since the first
    JMSContext already contains a connection and session and this method would
    create a second session on the same connection.

Replacement text (changed words thus)

Applications running in the Java EE web and EJB containers must not attempt
to create more than one active (not closed) Session object per connection.

  • If an application attempts to use the Connection object’s createSession
    method when an active Session object exists for that connection then a
    JMSException should be thrown.
  • If an application attempts to use the JMSContext object’s createContext
    method then a JMSRuntimeException must be thrown, since the first
    JMSContext already contains a connection and session and this method would
    create a second session on the same connection.

JMS specification section 2.8.2. "Key features of the simplified API"

Existing text

Applications running in the Java EE web and EJB containers are not permitted
to create more than one active session on a connection...

Modified text: (changed words thus)

Applications running in the Java EE web and EJB containers must not
create more than one active session on a connection...

Javadoc for Connection.html#createSession()

Existing text

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If
this method is called in a Java EE web or EJB container when an active Session
object already exists for this connection then a JMSException will be thrown.

Replacement text:

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If
this method is called in a Java EE web or EJB container when an active Session
object already exists for this connection then a JMSException may be thrown.

Javadoc for Connection.html#createSession(int)

Existing text

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If
this method is called in a Java EE web or EJB container when an active Session
object already exists for this connection then a JMSException will be thrown.

Replacement text:

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If
this method is called in a Java EE web or EJB container when an active Session
object already exists for this connection then a JMSException may be thrown.

Javadoc for Connection.html#createSession(boolean, int)

Existing text

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If
this method is called in a Java EE web or EJB container when an active Session
object already exists for this connection then a JMSException will be thrown.

Replacement text:

Applications running in the Java EE web and EJB containers must not attempt to
create more than one active (not closed) Session object per connection. If
this method is called in a Java EE web or EJB container when an active Session
object already exists for this connection then a JMSException may be thrown.

Comment by Nigel Deakin [ 09/Jan/15 ]

Draft spec now updated.
PDF (with change bar) at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf?rev=313.
Latest PDF at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf

Updated source for javax.jms.Connection can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/Connection.java?rev=313
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/Connection.java?rev1=312&rev2=313

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-158] JMS 2.0 introduced incompatible changes to Connection.stop and close and Session.close Created: 22/Sep/14  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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

Issue Links:
Dependency
blocks JMS_SPEC-159 Allow stop and close to be called fro... Open
Tags: jms20-errata

 Description   

Background: JMS 1.1

The JMS 1.1 specification stated that the stop method on Connection, and the close methods on Connection, Session and MessageConsumer must not return until any message listeners have returned.

This had the unfortunate consequence of requiring that if these methods were called from a message listener on its own Connection, Session or MessageConsumer then deadlock would occur and these methods would never return.

This error in JMS 1.1 was well-known to developers of JMS 1.1 implementations. Some vendors decided (many years ago) that it was unacceptable to cause customer applications to block for ever and so took the decision to ignore the requirement that these methods block for ever when called from a message listener on its own Connection, Session or MessageConsumer.

Changes in JMS 2.0

The JMS 2.0 specification (JMS_SPEC-48) addressed this error by amending the required behaviour to avoid the possibility of deadlock. It did so in two different ways.

  • In the case of the stop method on Connection, and the close methods on Connection and Session, the requirement to block for ever when these methods were called from a message listener (on its own Connection or Session) was replaced by the requirement to throw a javax.jms.IllegalStateException.
  • However in the case of the close method on MessageConsumer, the requirement to block for ever when this method was called from a message listener (on its own MessageConsumer) was removed by allowing the close method to return normally.

The problem

The change introduced in JMS 2.0 replaces the requirement to block for ever with the requirement to throw an exception. The expert group considered that this was not an incompatible change since the old behaviour was clearly unacceptable and no application would rely on it.

However this change does force an incompatible change on those JMS vendors which, many years ago, took the unilateral decision to ignore the erroneous requirement in JMS 1.1. The new requirements of JMS 2.0 means that existing applications which called stop and close from within a message listener, and which previously worked just fine, will now encounter an exception and fail.

Although, strictly speaking, JMS vendors that ignored the original JMS 1.1 requirement were violating the specification, this was not an unreasonable thing to do given that JMS 1.1 was clearly erroneous and that no further versions of JMS were developed until JMS 2.0 over a decade later.

This means that, even though the change in JMS 2.0 was technically valid, in practice it has introduced an incompatible change for some JMS vendors which would force them to break existing applications.

The solution

It is proposed an errata be added to JMS 2.0 to state that the requirement to throw an exception is optional. JMS vendors would be allowed to decide whether these methods should throw an exception or return normally. This would allow vendors which have long allowed these methods to return normally to continue to do so, and avoid breaking existing applications.

Existing JMS 2.0 implementations would not need to change.

Since this would mean that some vendors would throw an exception and some would not, applications which relied on these methods being called from a message listener would not be portable, and the specification would need to warn of this.

(In the longer term, this lack of portability could be resolved by removing the option to throw an exception. That is the subject of a separate issue JMS_SPEC-159).



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

(These proposals are now superseded by these updated proposals)

Proposed changes

Changes to A.1.19 Clarification: use of stop or close from a message listener (JMS_SPEC-48)

Existing text

If a MessageListener’s onMessage method calls stop or close on its own
Connection, close on its own Session, or stop or close on its own JMSContext,
then the the JMS provider must throw a javax.jms.IllegalStateException.

Replacement text

In the simplified API, if a MessageListener’s onMessage method calls stop or
close on its own JMSContext, then the the JMS provider must throw a
javax.jms.IllegalStateException.

In the classic and domain-specific APIs, if a MessageListener’s onMessage
method calls stop or close on its own Connection or close on its own Session,
then the stop or close method will either fail and throw a
javax.jms.IllegalStateException, or it will succeed and close the connection.

Changes to Section 6.1.5 “Pausing delivery of incoming messages”

Existing text

A message listener must not attempt to stop its own connection as this would
lead to deadlock. The JMS provider must detect this and throw a
javax.jms.IllegalStateException.

Replacement text

In the simplified API, if the stop method is called from a message listener
on its own JMSContext then it must throw a javax.jms.IllegalStateException.

In the classic and domain-specific APIs, if the stop method is called from a
message listener on its own Connection then it will either fail and throw a
javax.jms.IllegalStateException or it will succeed and stop the connection,
blocking until all other message listeners that may have been running have
returned.

Since two alternative behaviors are permitted in this case, applications
using the classic and domain-specific APIs should avoid calling stop from
a message listener on its own Connection because this is not portable.

Changed to Section 6.1.8 “Closing a connection”

Existing text

A message listener must not attempt to close its own connection as this would
lead to deadlock. The JMS provider must detect this and throw a
javax.jms.IllegalStateException.

Replacement text

In the simplified API, if the close method is called from a message listener
on its own JMSContext then it must throw a javax.jms.IllegalStateException.

In the classic and domain-specific APIs, if the close method is called from a
message listener on its own Connection then it will either fail and throw a
javax.jms.IllegalStateException or it will succeed and close the connection,
blocking until all other message listeners that may have been running have
returned, and all pending receive calls have completed. If close succeeds and
the acknowledge mode of the session is set to AUTO_ACKNOWLEDGE, the current
message will still be acknowledged automatically when the onMessage() call
completes.

Since two alternative behaviors are permitted in this case, applications
using the classic and domain-specific APIs should avoid calling close from
a message listener on its own Connection because this is not portable.

Changes to Section 6.2.15 “Closing a session”

Existing text

A message listener must not attempt to close its own session as this would
lead to deadlock. The JMS provider must detect this and throw a
javax.jms.IllegalStateException

Replacement text

In the simplified API, if the close method is called from a message listener
on its own JMSContext then it must throw a javax.jms.IllegalStateException.

In the classic and domain-specific APIs, if the close method is called from a
message listener on its own Session then it will either fail and throw a
javax.jms.IllegalStateException or it will succeed and close the Session,
blocking until any pending receive call in progress has completed. If close
succeeds and the acknowledge mode of the session is set to AUTO_ACKNOWLEDGE,
the current message will still be acknowledged automatically when the
onMessage() call completes.

Since two alternative behaviors are permitted in this case, applications
using the classic and domain-specific APIs should avoid calling close from
a message listener on its own Session because this is not portable.

Changes to the javadocs for javax/jms/Connection.html#close():

Existing text:

When this method is invoked, it should not return until message
processing has been shut down in an orderly fashion. This means that all
message listeners that may have been running have returned, and that all
pending receives have returned.

Replacement text:

When this method is invoked, it should not return until message
processing has been shut down in an orderly fashion. This means that all
message listeners that may have been running have returned, and that all
pending receives have returned.

However if the close method is called from a message listener on its own
connection, then it will either fail and throw a
javax.jms.IllegalStateException, or it will succeed and close the connection,
blocking until all other message listeners that may have been running have
returned, and all pending receive calls have completed. If close succeeds and
the acknowledge mode of the session is set to AUTO_ACKNOWLEDGE, the current
message will still be acknowledged automatically when the onMessage() call
completes.

Since two alternative behaviors are permitted in this case, applications
should avoid calling close from a message listener on its own
connection because this is not portable.

Existing text:

A message listener must not attempt to close its own connection as this
would lead to deadlock. The JMS provider must detect this and throw a
IllegalStateException.

Replacement text:

[Delete this text]

Changes to the javadocs for javax/jms/Connection.html#stop():

Existing text:

This call blocks until receives and/or message listeners in progress have
completed.

Replacement text:

[Delete this text]

Existing text:

A call to stop must not return until delivery of messages
has paused. This means that a client can rely on the fact that none of
its message listeners will be called and that all threads of control
waiting for receive calls to return will not return with a
message until the connection is restarted. The receive timers for a
stopped connection continue to advance, so receives may time out while
the connection is stopped.

If message listeners are running when stop is invoked, the
stop call must wait until all of them have returned before
it may return. While these message listeners are completing, they must
have the full services of the connection available to them.

A message listener must not attempt to stop its own connection as this
would lead to deadlock. The JMS provider must detect this and throw a
IllegalStateException.

Replacement text:

This call blocks until receives and/or message listeners in progress have
completed. A call to stop must not return until delivery of messages
has paused. This means that a client can rely on the fact that none of
its message listeners will be called and that all threads of control
waiting for code calls to return will not return with a
message until the connection is restarted. The receive timers for a
stopped connection continue to advance, so receives may time out while
the connection is stopped.

However if the stop method is called from a message listener on its own
connection, then it will either fail and throw a
javax.jms.IllegalStateException, or it will succeed and stop the connection,
blocking until all other message listeners that may have been running have
returned.

Since two alternative behaviors are permitted in this case, applications
should avoid calling stop from a message listener on its own
Connection because this is not portable.

Changes to the javadocs for javax/jms/Session.html#close()

Existing text:

This call will block until a receive call or message listener in
progress has completed.

Replacement text:

This call will block until a receive call or message listener in
progress has completed.

However if the close method is called from a message listener on its own
Session, then it will either fail and throw a javax.jms.IllegalStateException,
or it will succeed and close the session, blocking until any pending receive
call in progress has completed. If close succeeds and the acknowledge mode
of the session is set to AUTO_ACKNOWLEDGE, the current message will still
be acknowledged automatically when the onMessage call completes.

Since two alternative behaviors are permitted in this case, applications
should avoid calling close from a message listener on its own
Session because this is not portable.

Existing text:

A MessageListener must not attempt to close its own
Session> as this would lead to deadlock. The JMS provider must
detect this and throw a IllegalStateException.

Replacement text:

[Delete this text]

Comment by Nigel Deakin [ 19/Dec/14 ]

Views are also invited on whether the same changes should be made to the new JMS 2.0 methods JMSContext#stop and JMSContext#close. The current proposal is to leave these methods unchanged since there is no need to change them, and it is better to stick with the current, unambiguous, definition.

However there is one reason why we might want to keep the simplified API consistent with the classic API, and allow stop and close to be called in the simplified API as well as in the classic API. This is if we decided that it is actually better to allow stop and close to be called than throw an exception (i.e. requiring an exception was a mistake).

If we decided that, then in JMS 2.1 we could remove the option to throw an exception (which we could reasonably argue wasn't an incompatible change to applications).

I'm attracted by this, as I've received complaints that requiring an exception to be thrown has made it harder to write applications, but unless there is clear support for this we should stick to the more limited proposals above.

Comment by chris.barrow [ 06/Jan/15 ]

I am strongly in favor of this suggestion (keep the simplified API consistent with the classic API, and allow stop and close to be called in the simplified API as well as in the classic API), for several reasons:

  1. consistency is always better
  2. the ability to call stop and close from within a message listener is a useful feature for flow control purposes (as Matthew pointed out in an e-mail discussion), or to allow remote control of an application.
  3. as a general principle we should avoid imposing unnecessary restrictions on API usage, to improve usability. I do not see any compelling reason to forbid calling Connection.stop or start from within a MessageListener, since by definition JMS implementations are in control of listener execution, so can avoid deadlocks.

Then for 2.1 we can remove the option to throw an exception.

Comment by Nigel Deakin [ 06/Jan/15 ]

Further to my comment here, and in response to feedback here, on the community mailing list, and directly to me, I'm now proposing to allow stop and close to be called in the simplified API as well as in the classic API. Here are the updated changes:

Proposed changes

Changes to A.1.19 Clarification: use of stop or close from a message listener (JMS_SPEC-48)

Existing text

If a MessageListener’s onMessage method calls stop or close on its own
Connection, close on its own Session, or stop or close on its own JMSContext,
then the JMS provider must throw a javax.jms.IllegalStateException.

Replacement text

If a MessageListener’s onMessage method calls stop or close on its own
Connection, close on its own Session, stop or close on its own JMSContext,
or stop on a JMSContext which uses the same connection,
then the stop or close method will either fail and throw a
javax.jms.IllegalStateException (for methods on Session and Connection)
or javax.jms.IllegalStateRuntimeException (for methods on JMSContext),
or it will succeed and stop or close the Connection, Session or
JMSContext as appropriate.

Changes to Section 6.1.5 "Pausing delivery of incoming messages"

Existing text

If any message listeners are running when stop is invoked, stop must wait
until all of them have returned before it may return. While these message
listeners are completing, they must have the full services of the connection
available to them.

A message listener must not attempt to stop its own connection as this would
lead to deadlock. The JMS provider must detect this and throw a
javax.jms.IllegalStateException.

Replacement text

If any message listeners are running when stop is invoked, stop must wait
until all of them have returned before it may return. While these message
listeners are completing, they must have the full services of the connection
available to them.

If the stop method is called from a message listener on its own Connection or
JMSContext, or on a JMSContext that uses the same connection, then it will
either fail and throw a javax.jms.IllegalStateException (in the case of
Connection) or javax.jms.IllegalStateRuntimeException (in the case of JMSContext),
or it will succeed and stop the connection, blocking until all other message
listeners that may have been running have returned.

Since two alternative behaviors are permitted in this case, applications
should avoid calling stop from a message listener on its own Connection or
JMSContext, or on a JMSContext that uses the same connection, because this is
not portable.

Changes to Section 6.1.8 "Closing a connection"

Existing text

A message listener must not attempt to close its own connection as this would
lead to deadlock. The JMS provider must detect this and throw a
javax.jms.IllegalStateException.

Closing a Connection, QueueConnection or TopicConnection closes its
constituent sessions, producers, consumers or queue browsers. The connection
close is sufficient to signal the JMS provider that all resources for the
connection should be released.

Closing a JMSContext closes the underlying session and any underlying producers
and consumers. If there are no other active (not closed) JMSContext objects
using the underlying connection then this method also closes the underlying
connection.

Replacement text (the first two paragraphs below are unchanged):

Closing a Connection, QueueConnection or TopicConnection closes its
constituent sessions, producers, consumers or queue browsers. The connection
close is sufficient to signal the JMS provider that all resources for the
connection should be released.

Closing a JMSContext closes the underlying session and any underlying producers
and consumers. If there are no other active (not closed) JMSContext objects
using the underlying connection then this method also closes the underlying
connection.

If a message listener attempts to close its own connection (either by calling
close on a Connection object or by calling close on a JMSContext object
which has no other active JMSContext objects using the underlying connection)
then it will either fail and throw a javax.jms.IllegalStateException (in the
case of Connection) or javax.jms.IllegalStateRuntimeException (in the case of
JMSContext), or it will succeed and close the connection, blocking until
all other message listeners that may have been running have returned, and all
pending receive calls have completed. If close succeeds and the acknowledge
mode of the session is set to AUTO_ACKNOWLEDGE, the current message will still
be acknowledged automatically when the onMessage call completes.

Since two alternative behaviors are permitted in this case, applications
should avoid calling close from a message listener on its own Connection
or JMSContext because this is not portable.

Changes to Section 6.2.15 "Closing a session"

Existing text

A message listener must not attempt to close its own session as this would
lead to deadlock. The JMS provider must detect this and throw a
javax.jms.IllegalStateException

Replacement text

If a message listener attempts to close its own session (either by calling
close on a Session object or by calling close on a JMSContext object)
then it will either fail and throw a javax.jms.IllegalStateException (in the
case of Session) or javax.jms.IllegalStateRuntimeException (in the case of
JMSContext), or it will succeed and close the session, blocking until
any pending receive call in progress has completed. If close succeeds and
the acknowledge mode of the session is set to AUTO_ACKNOWLEDGE, the current
message will still be acknowledged automatically when the onMessage call
completes.

Since two alternative behaviors are permitted in this case, applications
should avoid calling close from a message listener on its own Session
or JMSContext because this is not
portable.

Changes to the javadocs for javax/jms/Connection.html#close():

Existing text:

When this method is invoked, it should not return until message
processing has been shut down in an orderly fashion. This means that all
message listeners that may have been running have returned, and that all
pending receives have returned.

Replacement text:

When this method is invoked, it should not return until message
processing has been shut down in an orderly fashion. This means that all
message listeners that may have been running have returned, and that all
pending receives have returned.

However if the close method is called from a message listener on its own
connection, then it will either fail and throw a
javax.jms.IllegalStateException, or it will succeed and close the connection,
blocking until all other message listeners that may have been running have
returned, and all pending receive calls have completed. If close succeeds and
the acknowledge mode of the session is set to AUTO_ACKNOWLEDGE, the current
message will still be acknowledged automatically when the onMessage() call
completes.

Since two alternative behaviors are permitted in this case, applications
should avoid calling close from a message listener on its own
connection because this is not portable.

Existing text:

A message listener must not attempt to close its own connection as this
would lead to deadlock. The JMS provider must detect this and throw a
IllegalStateException.

Replacement text:

[Delete this text]

Changes to the javadocs for javax/jms/Connection.html#stop():

Existing text:

If message listeners are running when stop is invoked, the
stop call must wait until all of them have returned before
it may return. While these message listeners are completing, they must
have the full services of the connection available to them.

A message listener must not attempt to stop its own connection as this
would lead to deadlock. The JMS provider must detect this and throw a
IllegalStateException.

Replacement text: (the first paragraph below is unchanged)

If message listeners are running when stop is invoked, the
stop call must wait until all of them have returned before
it may return. While these message listeners are completing, they must
have the full services of the connection available to them.

However if the stop method is called from a message listener on its own
connection, then it will either fail and throw a
javax.jms.IllegalStateException, or it will succeed and stop the connection,
blocking until all other message listeners that may have been running have
returned.

Since two alternative behaviors are permitted in this case, applications
should avoid calling stop from a message listener on its own
Connection because this is not portable.

Changes to the javadocs for javax/jms/Session.html#close()

Existing text:

This call will block until a receive call or message listener in progress has completed. A blocked message consumer receive call returns null when this session is closed.

Replacement text: (the first paragraph below is unchanged)

This call will block until a receive call or message listener in progress has completed. A blocked message consumer receive call returns null when this session is closed.

However if the close method is called from a message listener on its own Session, then it will either fail and throw a javax.jms.IllegalStateException, or it will succeed and close the session, blocking until any pending receive call in progress has completed. If close succeeds and the acknowledge mode of the session is set to AUTO_ACKNOWLEDGE, the current message will still be acknowledged automatically when the onMessage call completes.

Since two alternative behaviors are permitted in this case, applications should avoid calling close from a message listener on its own Session because this is not portable.

Existing text:

A MessageListener must not attempt to close its own
Session as this would lead to deadlock. The JMS provider must
detect this and throw a IllegalStateException.

Replacement text:

[Delete this text]

Changes to the javadocs for javax/jms/JMSContext.html#stop():

Existing text:

If message listeners are running when stop is invoked, the stop call must wait
until all of them have returned before it may return. While these message
listeners are completing, they must have the full services of the connection
available to them.

A message listener must not attempt to stop its own JMSContext as this would
lead to deadlock. The JMS provider must detect this and throw a
IllegalStateRuntimeException

Replacement text: (the first paragraph below is unchanged)

If message listeners are running when stop is invoked, the stop call must wait
until all of them have returned before it may return. While these message
listeners are completing, they must have the full services of the connection
available to them.

However if the stop method is called from a message listener on its own
JMSContext, or any other JMSContext that uses the same connection,
then it will either fail and throw a javax.jms.IllegalStateRuntimeException,
or it will succeed and stop the connection, blocking until all other message
listeners that may have been running have returned.

Since two alternative behaviors are permitted in this case, applications
should avoid calling stop from a message listener on its own JMSContext, or
any other JMSContext that uses the same connection, because this is not
portable.

Changes to the javadocs for javax/jms/JMSContext.html#close()

Existing text:

When this method is invoked, it should not return until message processing has
been shut down in an orderly fashion. This means that all message listeners
that may have been running have returned, and that all pending receives have
returned. A close terminates all pending message receives on the connection's
sessions' consumers. The receives may return with a message or with null,
depending on whether there was a message available at the time of the close.
If one or more of the connection's sessions' message listeners is processing
a message at the time when connection close is invoked, all the facilities of
the connection and its sessions must remain available to those listeners until
they return control to the JMS provider.

Replacement text: (the first paragraph below is unchanged)

When this method is invoked, it should not return until message processing has
been shut down in an orderly fashion. This means that any message listener
that may have been running has returned, and that any pending receive call has
returned. A close terminates any pending receive call on the JMSContext's
consumers. The receive call may return with a message or with null, depending
on whether there was a message available at the time of the close. If one of
the JMSContext's message listeners is processing a message at the time when
close is invoked from another thread, all the facilities of the JMSContext
must remain available to it until it returns control to the JMS provider.

However if the close method is called from a message listener on its own
JMSContext, then it will either fail and throw a
javax.jms.IllegalStateRuntimeException, or it will succeed and close the
JMSContext. If close succeeds and the session mode of the JMSContext is set to
AUTO_ACKNOWLEDGE, the current message will still be acknowledged automatically
when the onMessage call completes.

Since two alternative behaviors are permitted in this case, applications
should avoid calling close from a message listener on its own
JMSContext because this is not portable.

Existing text:

A MessageListener must not attempt to close its own JMSContext as this would
lead to deadlock. The JMS provider must detect this and throw a
IllegalStateRuntimeException.

Replacement text:

[Delete this text]

Comment by chris.barrow [ 06/Jan/15 ]

This looks fine. Just one thing, in a few places in the replacement texts there is mention of javax.jms.IllegalStateRException. I presume that is intended to read javax.jms.IllegalStateRuntimeException.

Comment by Nigel Deakin [ 07/Jan/15 ]

Thanks for reporting this typo. I've corrected the proposed changes to say javax.jms.IllegalStateRuntimeException

Comment by Nigel Deakin [ 08/Jan/15 ]

Draft spec now updated.
PDF (with change bar) at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf?rev=312.
Latest PDF at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf

Updated source for javax.jms.Connection can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/Connection.java?rev=312
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/Connection.java?rev1=311&rev2=312

Updated source for javax.jms.Session can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/Session.java?rev=312
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/Session.java?rev1=311&rev2=312

Updated source for javax.jms.JMSContext can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/JMSContext.java?rev=312
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/JMSContext.java?rev1=311&rev2=312

Comment by chris.barrow [ 08/Jan/15 ]

I have reviewed the draft spec (PDF) and the changes look fine to me.

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-164] Typos in section 7.3.5 and 12.2: Change Session to MessageProducer Created: 02/Jan/15  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

JMS 2.0 section 7.3.5. "Restrictions on usage in Java EE" and section 12.2 "Restrictions on the use of JMS API in the Java EE web or EJB container" contain references to various send methods. The spec states that these are on javax.jms.Session when they are actually on javax.jms.MessageProducer.

Changes to 7.3.5. "Restrictions on usage in Java EE"

Existing text

  • javax.jms.Session method send(Message message, CompletionListener completionListener)
  • javax.jms.Session method send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)
  • javax.jms.Session method send(Destination destination, Message message, CompletionListener completionListener)
  • javax.jms.Session method send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)

Replacement text

  • javax.jms.MessageProducer method send(Message message, CompletionListener completionListener)
  • javax.jms.MessageProducer method send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)
  • javax.jms.MessageProducer method send(Destination destination, Message message, CompletionListener completionListener)
  • javax.jms.MessageProducer method send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)

Changes to 12.2 "Restrictions on the use of JMS API in the Java EE web or EJB container"

Existing text

  • javax.jms.Session method send(Message message, CompletionListener completionListener)
  • javax.jms.Session method send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)
  • javax.jms.Session method send(Destination destination, Message message, CompletionListener completionListener)
  • javax.jms.Session method send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)

Replacement text

  • javax.jms.MessageProducer method send(Message message, CompletionListener completionListener)
  • javax.jms.MessageProducer method send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)
  • javax.jms.MessageProducer method send(Destination destination, Message message, CompletionListener completionListener)
  • javax.jms.MessageProducer method send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)


 Comments   
Comment by Nigel Deakin [ 07/Jan/15 ]

Draft spec now updated.
PDF (with change bar) at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf?rev=309.
Latest PDF at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-160] JMS API source contains self-closing HTML tags Created: 17/Nov/14  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

The JMS API source contains self-closing HTML tags in its javadoc comments. For example, the source of javax.jms.Message contains the tag <br/>.

To reproduce the issue, simply run the javadoc command on the API source using the Java 8 version of javadoc.

Self-closing tags are not valid HTML and they cause the Java 8 version of javadoc to fail (unless a flag has been set to suppress this).

It looks as if this incorrect HTML was added in JMS 2.0.



 Comments   
Comment by Nigel Deakin [ 01/Dec/14 ]

Changes to javadoc for Message

Change <br/> to <br> in 12 places.

Changes to javadoc for JMSConsumer

Change <br/> to <br> in 15 places.

Comment by Nigel Deakin [ 07/Jan/15 ]

Source code now updated.

Updated source for javax.jms.Message can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/Message.java?rev=303
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/Message.java?rev1=302&rev2=303

Updated source for javax.jms.JMSConsumer can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/JMSConsumer.java?rev=303
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/JMSConsumer.java?rev1=302&rev2=303

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-161] serialVersionUID of JMSException has changed from JMS 1.1 to JMS 2.0 Created: 19/Nov/14  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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

Issue Links:
Related
is related to MQ-359 serialVersionUID of JMSException has ... Open
Tags: jms20-errata

 Description   

The serialVersionUID of javax.jms.JMSException has changed from JMS 1.1 to JMS 2.0, which means that if an instance of this exception is serialized using JMS 1.1 it cannot be deserialized using JMS 2.0 or vice versa.



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

Although these classes are defined in the JMS specification, their implementation is, strictly speaking, part of the RI. Fixing this issue will not require a revision to the spec.

Comment by Nigel Deakin [ 25/Nov/14 ]

Now fixed in the reference implementation. See MQ-359 for fix details.

This issue will be updated when the new API jar is released.

Comment by Nigel Deakin [ 09/Dec/14 ]

A new JMS 2.0 API jar containing this fix has been released to Maven Central at
http://search.maven.org/#artifactdetails%7Cjavax.jms%7Cjavax.jms-api%7C2.0.1-b01%7Cjar
This is a release candidate (hence the b01 suffix), for the purposes of testing.

The final release of this jar will occur at the same time as the JMS 2.0 errata release.

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the release of the JMS 2.0.1 API jar that accompanied the JMS 2.0 rev A maintenance release





[JMS_SPEC-162] Typos in section 7.3 "Asynchronous send" Created: 01/Dec/14  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

There are two minor typos in the JMS 2.0 specification, section 7.2 "Asynchronous send".

In the third bullet point, change "synchronously" to "asynchronously using"

In the fourth bullet point, change "synchronously" to "asynchronously".



 Comments   
Comment by Nigel Deakin [ 01/Dec/14 ]

Changes to section 7.3. Asynchronous send

Existing text:

  • In the domain-specific API for point-to-point messaging a QueueSender may be used to send a message synchronously any of the methods inherited from MessageProducer and listed above.
  • In the domain-specific API for pub/sub messaging a TopicPublisher may be used to send a message synchronously using any of the methods inherited from MessageProducer and listed above.

Replacement text:

  • In the domain-specific API for point-to-point messaging a QueueSender may be used to send a message asynchronously using any of the methods inherited from MessageProducer and listed above.
  • In the domain-specific API for pub/sub messaging a TopicPublisher may be used to send a message asynchronously using any of the methods inherited from MessageProducer and listed above.
Comment by Nigel Deakin [ 07/Jan/15 ]

Draft spec now updated.
PDF (with change bar) at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf?rev=311.
Latest PDF at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-125] Define whether a JMS provider should call reset after sending a BytesMessage asynchronously Created: 17/May/13  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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:
Related
is related to JMS_SPEC-166 Define that the JMS provider should c... Open
Tags: jms20-errata

 Description   

This issue concerns the behaviour of the JMS provider when it sends a BytesMessage.

The spec is not clear on what state the body of a BytesMessage is left in after it has been sent. We're talking about the message object in the sending program, not in the receiving program.

A JMS 2.0 vendor has asked for the behaviour to be clarified for async send. However this issue will discuss the behaviour for both async and sync send.

There are three possibilities:

1. The JMS provider leaves the body in write-only mode with the stream positioned at the end. That would allow the application to send a message, append additional data to the message body, and send it a second time. An application which wanted to read the message body would have to call reset.

2. The JMS provider leaves the BytesMessage in read-only with the stream positioned at the start. To achieve this the send method would need to call reset before returning.

3. Leave the behaviour undefined.

This issue applies to both synchronous and asynchronous send. In the sync case the issue is what state the message is left in after the call to send returns. In the async case the issue is what state the message is in when the CompletionListener callback is performed. Let's consider these separately.

Asynchronous send

Option 1 (leave the body in write-only mode with the stream positioned at the end):

  • It is not practically possible for a JMS provider to implement this correctly. This is because of the need to support the case where the JMS provider is used to send a message whose implementation is not its own (as required by JMS 2.0 section 3.12). In that case the JMS provider must use the public API to read the data from the "foreign" message. After it has done so the message would be in read-only mode, with the stream positioned at the end. The only way to change the message to write-only mode would be to call reset, but that would position the stream back at the start.

Option 2 (leave the body in read-only mode with the stream positioned at the start).

  • This is the current de facto spec requirement for async send. This is because there is a JMS 2.0 TCK test which sends a BytesMessage asynchronously and which attempts to read the body of the message object passed to the CompletionListener. without calling reset. All existing JMS 2.0 providers will have passed this test.
  • There is also a clear use case for this option, since It is expected that a CompletionListener callback method may want to read the message in order to identify the message that was successfully sent.

Option 3 (leave the behaviour undefined).

  • This is undesirable because the only things a portable application application could do would be to call reset and read the message, or call clearBody to clear it and re-write it from scratch. If a JMS provider left the body in write-only mode with the stream positioned at the end, and the application took advantage of this to append to the body, then the application would not be portable.

Proposal: It is therefore proposed to update the JMS 2.0 specification to require the behaviour described in option 2: when a BytesMessage is sent asynchronously, the message object that was sent must be set to be read-only with the stream positioned at the start prior to calling the CompletionListener. To achieve this the send method would need to call reset before returning.

Synchronous send

JMS 1.1 was not specific about this and different vendors already adopt different behaviour. There are no TCK tests which rely on a specific behaviour. It is therefore probably too late to define more specific behaviour, especially as this has not been reported as an issue by users or vendors.

In practice I would suggest that for a synchronous send there is little reason for a sending application to want to read a the body of a BytesMessage after it has been sent.

Nevertheless, for consistency, we should perhaps change the spec to recommend that when a message is sent synchronously, the provider should call reset before the send() returns. But this will need to remain a recommendation since existing JMS 1.1 providers may have interpreted this differently, making it too late to standardise this.

Proposal It is proposed to update the JMS 2.0 specification to recommend, but not require, that the provider should call reset before the send() returns, and to add a warning that portable applications must not make assumptions about what state the message is in.



 Comments   
Comment by John D. Ament [ 21/May/13 ]

What is the use case for trying to read data from a BytesMessage that you just sent?

Comment by Nigel Deakin [ 22/May/13 ]

The reason the Message is passed to the CompletionListener is to allow it to determine which message has been sent (e.g. there may be more than one incomplete send). To do that it might need to read the message.

This is a somewhat obscure use case (though it came up in a TCK test) but we have the opportunity to define the required behaviour here and so should take it.

Comment by Nigel Deakin [ 09/Dec/14 ]

Proposed changes (supersed by updated proposal below)

javadoc for BytesMessage: Existing text:

When the message is first created, and when clearBody is called, the body of
the message is in write-only mode. After the first call to reset has been
made, the message body is in read-only mode.

After a message has been sent, the client that sent it can retain and modify
it without affecting the message that has been sent. The same message object
can be sent multiple times.

When a message has been received, the provider has called reset so that the
message body is in read-only mode for the client.

Replacement text: (new words marked *thus)

When the message is first created, and when clearBody is called, the body of
the message is in write-only mode. After the first call to reset has been
made, the message body is in read-only mode.

After a message has been sent synchronously, it is recommended that the
provider has called reset so that the message body is in read-only mode.

After a message has been sent asynchronously, the provider must call reset
prior to invoking the CompletionListener so that the message body is in
read-only mode. This means that the message passed to the
CompletionListener may be read without the application needing to call
reset.

In both cases, after a message has been sent (a synchronous send has returned
or an asynchronous send has completed and the CompletionListener has been
invoked), the client that sent it can retain and modify it without affecting
the message that has been sent. The same message object can be sent multiple
times.

When a message has been received, the provider has called reset so that the
message body is in read-only mode for the client.

Comment by mbwhite [ 09/Dec/14 ]

A side issue this raises is if the message object reference by the completion listener is the same object as referenced by the thread that sending the message.

Another option would be suggest that the message that is passed to the completion listener be a clone in read-only mode. This would let the main thread retain the message in write-only.

The implication as well is that behavior with 'foreign' messages is identical to 'own' messages. Reasonable - but would be worth adding in the messaging section.

Comment by Nigel Deakin [ 19/Dec/14 ]

Updated proposal

Here's an updated proposal, drawn more narrowly. It mentions only async send, and uses wording which would not prevent the message passed to the completion listener being a clone, without explicitly saying that it can be.

In the javadoc for BytesMessage, insert the following new text after the sentence ending "After the first call to reset has been made, the message body is in read-only mode.":

Inserted text:

When a BytesMessage is sent asynchronously, the provider must call reset
on the BytesMessage passed to the CompletionListener. This means that the
CompletionListener can read the message body without needing to call
reset.

Comment by Nigel Deakin [ 09/Jan/15 ]

Updated source for javax.jms.BytesMessage can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/BytesMessage.java?rev=317
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/BytesMessage.java?rev1=316&rev2=317

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-122] Typos in javadocs for ConnectionFactory.createContext Created: 08/May/13  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

1. There's a typo in the javadocs for ConnectionFactory.createContext(int sessionMode)

In the paragraph "In a Java EE web or EJB container, when there is an active JTA transaction in progress: ", change:

Since the argument is ignored, developers are recommended to use createSession(), which has no arguments, instead of this method.

to:

Since the argument is ignored, developers are recommended to use createContext(), which has no arguments, instead of this method.

2. There's a typo in the javadocs for ConectionFactory.createContext(String userName, String password, int sessionMode):

In the paragraph "In a Java EE web or EJB container, when there is an active JTA transaction in progress: ", change:

Since the argument is ignored, developers are recommended to use createSession(), which has no sessionMode parameter, instead of this method.

to:

Since the argument is ignored, developers are recommended to use createContext(String userName, String password), which has no sessionMode parameter, instead of this method.



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

Proposed changes to ConnectionFactory#createContext(int sessionMode):

Existing text

Since the argument is ignored, developers are recommended to use createSession(), which has no arguments, instead of this method.

Replacement text

Since the argument is ignored, developers are recommended to use createContext() instead of this method.

Proposed changes to ConnectionFactory#createContext(String userName, String password, int sessionMode):

Existing text

Since the argument is ignored, developers are recommended to use createSession(), which has no arguments, instead of this method.

Replacement text

Since the argument is ignored, developers are recommended to use createContext(String userName, String password) instead of this method.

Comment by Nigel Deakin [ 12/Jan/15 ]

Updated source for javax.jms.JMSContext can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/ConnectionFactory.java?rev=319
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/ConnectionFactory.java?rev1=317&rev2=319

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-133] Update javadoc comments for QueueConnection#createQueueSession and TopicConnection#createTopicSession Created: 19/Aug/13  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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

Tags: jms20-errata

 Description   

The javadoc comments for QueueConnection#createQueueSession and TopicConnection#createTopicSession should be updated to match those for Connection#createSession (mutatis mutandis), by describing the required behaviour in the various Java EE containers etc.



 Comments   
Comment by Nigel Deakin [ 22/Dec/14 ]

Here are the proposed changes.

javadoc for QueueConnection#createQueueSession

It is proposed the existing javadoc for this method is replaced by a copy of the javadoc for Connection#createSession (after applying the changes for JMS_SPEC-155 and JMS_SPEC-157), with the following modifications

  • The first paragraph "This method has been superseded by...instead of this one" is omitted.
  • "Creates a Session object" is changed to "Creates a QueueSession object"
  • "Returns: a newly created queue session" is changed to "Returns: a newly created QueueSession"
  • "if the Connection object fails to create a session" is changed to "if the QueueConnection object fails to create a QueueSession"
  • In the section "See Also:", the references to createSession(int), createSession() are omitted.

Existing text:

Creates a QueueSession object.

Parameters:

transacted - indicates whether the session is transacted

acknowledgeMode - indicates whether the consumer or the client will acknowledge any messages it receives; ignored if the session is transacted. Legal values are Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, and Session.DUPS_OK_ACKNOWLEDGE.

Returns:

a newly created queue session

Throws:

JMSException - if the QueueConnection object fails to create a session due to some internal error or lack of support for the specific transaction and acknowledgement mode.

See Also:

Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE

Replacement text:

Creates a QueueSession object, specifying transacted and acknowledgeMode.

The effect of setting the transacted and acknowledgeMode arguments depends on whether this method is called in a Java SE environment, in the Java EE application client container, or in the Java EE web or EJB container. If this method is called in the Java EE web or EJB container then the effect of setting the transacted} and acknowledgeMode arguments also depends on whether or not there is an active JTA transaction in progress.

In a Java SE environment or in the Java EE application client container:

  • If transacted is set to true then the session will use a local transaction which may subsequently be committed or rolled back by calling the session's commit or rollback methods. The argument acknowledgeMode is ignored.
  • If transacted is set to false then the session will be non-transacted. In this case the argument acknowledgeMode is used to specify how messages received by this session will be acknowledged. The permitted values are Session.CLIENT_ACKNOWLEDGE, Session.AUTO_ACKNOWLEDGE and Session.DUPS_OK_ACKNOWLEDGE. For a definition of the meaning of these acknowledgement modes see the links below.

In a Java EE web or EJB container, when there is an active JTA transaction in progress:

  • Both arguments transacted and acknowledgeMode are ignored. The session will participate in the JTA transaction and will be committed or rolled back when that transaction is committed or rolled back, not by calling the session's commit or rollback methods. Since both arguments are ignored, developers are recommended to use createSession(), which has no arguments, instead of this method.

In the Java EE web or EJB container, when there is no active JTA transaction in progress:

  • If transacted is set to false and acknowledgeMode is set to JMSContext.AUTO_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE then the session will be non-transacted and messages will be acknowledged according to the value of acknowledgeMode.
  • If transacted is set to false and acknowledgeMode is set to JMSContext.CLIENT_ACKNOWLEDGE then the JMS provider is recommended to ignore the specified parameters and instead provide a non-transacted, auto-acknowledged session. However the JMS provider may alternatively provide a non-transacted session with client acknowledgement.
  • If transacted is set to true, then the JMS provider is recommended to ignore the specified parameters and instead provide a non-transacted, auto-acknowledged session. However the JMS provider may alternatively provide a local transacted session.
  • Applications are recommended to set transacted to false and acknowledgeMode to JMSContext.AUTO_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE since since applications which set transacted to false and set acknowledgeMode to JMSContext.CLIENT_ACKNOWLEDGE, or which set transacted to true, may not be portable.

Applications running in the Java EE web and EJB containers must not attempt to create more than one active (not closed) Session object per connection. If this method is called in a Java EE web or EJB container when an active Session object already exists for this connection then a JMSException may be thrown.

Parameters:

transacted - indicates whether the session will use a local transaction, except in the cases described above when this value is ignored.

acknowledgeMode - when transacted is false, indicates how messages received by the session will be acknowledged, except in the cases described above when this value is ignored.

Returns:

a newly created QueueSession

Throws:

JMSException - if the QueueConnection object fails to create a QueueSession due to some internal error, lack of support for the specific transaction and acknowledgement mode, or because this method is being called in a Java EE web or EJB application and an active session already exists for this connection.

Since:

JMS 1.1

See Also:

Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE

javadoc for TopicConnection#createTopicSession

It is proposed the existing javadoc for this method is replaced by a copy of the javadoc for Connection#createSession (after applying the changes for JMS_SPEC-155 and JMS_SPEC-157), with the following modifications

  • The first paragraph "This method has been superseded by...instead of this one" is omitted.
  • "Creates a Session object" is changed to "Creates a TopicSession object"
  • "Returns: a newly created topic session" is changed to "Returns: a newly created TopicSession "
  • "if the Connection object fails to create a session" is changed to "if the TopicConnection object fails to create a TopicSession"
  • In the section "See Also:", the references to createSession(int), createSession() are omitted.

Existing text:

Creates a TopicSession object.

Parameters:

transacted - indicates whether the session is transacted

acknowledgeMode - indicates whether the consumer or the client will acknowledge any messages it receives; ignored if the session is transacted. Legal values are Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, and Session.DUPS_OK_ACKNOWLEDGE.

Returns:

a newly created topic session

Throws:

JMSException - if the TopicConnection object fails to create a session due to some internal error or lack of support for the specific transaction and acknowledgement mode.

See Also:

Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE

Replacement text:

Creates a TopicSession object, specifying transacted and acknowledgeMode.

The effect of setting the transacted and acknowledgeMode arguments depends on whether this method is called in a Java SE environment, in the Java EE application client container, or in the Java EE web or EJB container. If this method is called in the Java EE web or EJB container then the effect of setting the transacted} and acknowledgeMode arguments also depends on whether or not there is an active JTA transaction in progress.

In a Java SE environment or in the Java EE application client container:

  • If transacted is set to true then the session will use a local transaction which may subsequently be committed or rolled back by calling the session's commit or rollback methods. The argument acknowledgeMode is ignored.
  • If transacted is set to false then the session will be non-transacted. In this case the argument acknowledgeMode is used to specify how messages received by this session will be acknowledged. The permitted values are Session.CLIENT_ACKNOWLEDGE, Session.AUTO_ACKNOWLEDGE and Session.DUPS_OK_ACKNOWLEDGE. For a definition of the meaning of these acknowledgement modes see the links below.

In a Java EE web or EJB container, when there is an active JTA transaction in progress:

  • Both arguments transacted and acknowledgeMode are ignored. The session will participate in the JTA transaction and will be committed or rolled back when that transaction is committed or rolled back, not by calling the session's commit or rollback methods. Since both arguments are ignored, developers are recommended to use createSession(), which has no arguments, instead of this method.

In the Java EE web or EJB container, when there is no active JTA transaction in progress:

  • If transacted is set to false and acknowledgeMode is set to JMSContext.AUTO_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE then the session will be non-transacted and messages will be acknowledged according to the value of acknowledgeMode.
  • If transacted is set to false and acknowledgeMode is set to JMSContext.CLIENT_ACKNOWLEDGE then the JMS provider is recommended to ignore the specified parameters and instead provide a non-transacted, auto-acknowledged session. However the JMS provider may alternatively provide a non-transacted session with client acknowledgement.
  • If transacted is set to true, then the JMS provider is recommended to ignore the specified parameters and instead provide a non-transacted, auto-acknowledged session. However the JMS provider may alternatively provide a local transacted session.
  • Applications are recommended to set transacted to false and acknowledgeMode to JMSContext.AUTO_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE since since applications which set transacted to false and set acknowledgeMode to JMSContext.CLIENT_ACKNOWLEDGE, or which set transacted to true, may not be portable.

Applications running in the Java EE web and EJB containers must not attempt to create more than one active (not closed) Session object per connection. If this method is called in a Java EE web or EJB container when an active Session object already exists for this connection then a JMSException may be thrown.

Parameters:

transacted - indicates whether the session will use a local transaction, except in the cases described above when this value is ignored.

acknowledgeMode - when transacted is false, indicates how messages received by the session will be acknowledged, except in the cases described above when this value is ignored.

Returns:

a newly created TopicSession

Throws:

JMSException - if the TopicConnection object fails to create a TopicSession due to some internal error, lack of support for the specific transaction and acknowledgement mode, or because this method is being called in a Java EE web or EJB application and an active session already exists for this connection.

Since:

JMS 1.1

See Also:

Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE

Comment by Nigel Deakin [ 09/Jan/15 ]

Updated source for javax.jms.QueueConnection can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/QueueConnection.java?rev=316
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/QueueConnection.java?rev1=315&rev2=316

Updated source for javax.jms.TopicConnection can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/TopicConnection.java?rev=316
Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/TopicConnection.java?rev1=315&rev2=316

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-119] Remove reference to password alias Created: 26/Apr/13  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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

Tags: jms20-errata

 Description   

The JMS 2.0 specification, section 12.4.3 "Injection syntax" includes an example of the use of password aliases in Java EE. Although password aliases were discussed for Java EE they were not included in the final release, so the example should be removed.



 Comments   
Comment by Nigel Deakin [ 02/Dec/14 ]

Proposed change

In the JMS 2.0 specification, section 12.4.3 "Injection syntax", delete the following text:

Since it is undesirable to hardcode clear text passwords in an application, the password may be specified as an alias:

@Inject
@JMSPasswordCredential(
   username="admin",
   password="${ALIAS=myAdminPassword}")
private JMSContext context;

The use of a password alias allows the password to be defined in a secure manner separately from the application. See the Java EE 7 platform specification for more information on password aliases.

Comment by Nigel Deakin [ 02/Dec/14 ]

I have updated the specification in the source code repository. PDF may be downloaded here.

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-120] Typo: in example, change .class() to .class Created: 26/Apr/13  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

The JMS spec contains the following code in an example:

StockObject stockObject = message.getBody(StockObject.class());

This is incorrect. It should be changed to

StockObject stockObject = message.getBody(StockObject.class);

i.e. class should not be followed by ().



 Comments   
Comment by Nigel Deakin [ 02/Dec/14 ]

JMS specification section 14.4.10 "Unpacking an ObjectMessage": Existing text:

StockObject stockObject = message.getBody(StockObject.class());

Replacement text

StockObject stockObject = message.getBody(StockObject.class);
Comment by Nigel Deakin [ 02/Dec/14 ]

I have updated the specification in the source code repository. PDF may be downloaded here.

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-128] Typo in section 4.1.4 "Queue" Created: 06/Jun/13  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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: jms20-errata

 Description   

There's a typo in section 4.1.4 "Queue":

The sentence

See Section 0 "<new page>Administered objects" for more information...

contains an incorrect section number and a spurious page throw.



 Comments   
Comment by Nigel Deakin [ 01/Dec/14 ]

Draft spec now updated. PDF (with change bar) at https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/specification/word/JMS20.pdf?rev=305

Comment by Nigel Deakin [ 19/Dec/14 ]

Proposed changes to JMS specification section 4.1.4 "Queue"

Existing text

See Section 0 "<new page>Administered objects" for more information...

(where <new page> means that the subsequent text was on the next page)

Replacement text

See Section 5 "Administered objects" for more information...

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[JMS_SPEC-60] Obscurity setting special JMSHeaders Created: 17/Nov/11  Updated: 22/Nov/11  Resolved: 22/Nov/11

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: Improvement Priority: Minor
Reporter: koen.serneels Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
is duplicated by JMS_SPEC-34 Calling setJMSDeliveryMode or setJMSP... Resolved

 Description   

Currently it is specced that some headers can only set by "send or publish" method.
This is very confusing. For example someone not knowing about this might be tempted to set JMSPriority on a message.
This will not trigger any exception, but in the end be completely ignored if send by he regular send method (.send(message)) instead of the overloaded send(message, deliveryMode, priority, timeToLive).
The question is; why are these headers mutable on the javax.jms.Message in the first place?



 Comments   
Comment by rdohna [ 21/Nov/11 ]

We assume that the setters are there for cross-provider posting, i.e. a client consumes a message from a destination bound to one JMS provider (say Glassfish MQ) and resends it to a destination bound to another JMS provider (say Active MQ). The outgoing provider may want to set the priority of that message object, while it doesn't know which implementation it is.

But you are right: It's very confusing.

Comment by Nigel Deakin [ 22/Nov/11 ]

Changing Issue Type to "Improvement"
Changing priority to "Low priority"

Comment by Nigel Deakin [ 22/Nov/11 ]

This issue is a duplicate of JMS_SPEC-34

I've added some additional information to JMS_SPEC-34 which explains why these methods are needed and confirms that the javadoc will be clarified.

I'll close this issue as a duplicate. Feel free to continue any discussion on JMS_SPEC-34

Comment by Nigel Deakin [ 22/Nov/11 ]

Corrected "Affects version" to 1.1.





[JMS_SPEC-167] JMS 2.0: Session javadoc should mention consumer.close is allowed outside thread of control Created: 22/Jan/15  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: jms-spec
Component/s: None
Affects Version/s: 2.0
Fix Version/s: JMS 2.0 rev A

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

Tags: jms20-errata

 Description   

The class level javadoc for Session contains the following paragraph (my bolding):

Once a connection has been started, any session with one or more registered message listeners is dedicated to the thread of control that delivers messages to it. It is erroneous for client code to use this session or any of its constituent objects from another thread of control. The only exception to this rule is the use of the session or connection close method.

The last sentence should be augmented to include message consumer close since from JMS 2.0 that method is now explicitly allowed to be called from another thread (see JMS_SPEC-48 and MessageConsumer.close javadoc). Moreover, it should not really mention connection close because that is irrelevant (the connection is not a constituent object of the Session). Suggested rewording for the last sentence:

The only exceptions to this rule are the use of the session and message consumer close methods

.



 Comments   
Comment by Nigel Deakin [ 22/Jan/15 ]

I don't think the spec says that you are allowed to call MessageConsumer#close from outside the thread of control, though perhaps it should.

JMS_SPEC-48 and MessageConsumer.close javadoc say you can call this method from a message listener on its own consumer, but in that case it would still be called from the thread of control.

I suppose the connection close method is mentioned because it implicitly closes the session(s), and so could be considered to be "using this session".

Comment by Nigel Deakin [ 22/Jan/15 ]

Added to the list for JMS 2.1

Comment by chris.barrow [ 27/Jan/15 ]

My remark about being allowed to call MessageConsumer#close from any thread is based on the following:

  • from the javadoc:

    This method is the only {@code MessageConsumer} method that can be called concurrently.

  • from a comment in MS_SPEC-48 saying

    The JMS EG has agreed to revise the behaviour of consumer close to:...Allowing a consumer to be closed from any thread, even if it isn't the thread of control

Did I misunderstand?

Comment by Nigel Deakin [ 27/Jan/15 ]

Updated: Thanks for the follow-up. Looks like it was me who misunderstood. I agree with your proposal for the following reasons:

1. JMS 2.0 section 8.8 "closing a consumer" already says

close is the only method on a consumer that may be invoked from a thread of control separate from the one which is currently controlling the session.

So this change simply updates the javadocs for Session to say the same thing.

2. MessageConsumer.close contains the words words "This method is the only MessageConsumer method that can be called concurrently" in, which were added in JMS 2.0.

That sentence isn't very clear, but Session.close, has had identical wording since JMS 1.1, and I believe it is intended to mean that the method doesn't have to be called from the "thread of control".

3. Closing a session implicitly closes all consumers, so if session close can be called from outside the "thread of control" then it is reasonable to expect the same for consumer close.

So I agree with your proposal to amend the Session javadoc.

I'll see if we can fit it into the JMS 2.0 errata.

Comment by chris.barrow [ 27/Jan/15 ]

OK thanks.

Comment by Nigel Deakin [ 12/Feb/15 ]

Proposed changes to the class javadoc for Session

Existing text:

Once a connection has been started, any session with one or more registered message listeners is dedicated to the thread of control that delivers messages to it. It is erroneous for client code to use this session or any of its constituent objects from another thread of control. The only exception to this rule is the use of the session or connection close method.

Replacement text:

Once a connection has been started, any session with one or more registered message listeners is dedicated to the thread of control that delivers messages to it. It is erroneous for client code to use this session or any of its constituent objects from another thread of control. The only exception to this rule is the use of the session or message consumer close method.

Comment by Nigel Deakin [ 12/Feb/15 ]

Updated source

The draft JMS 2.0 javadocs can be viewed at
https://jms-spec.java.net/2.0RevA-SNAPSHOT/apidocs/index.html

Updated source for javax.jms.Session can be viewed at, and downloaded from,
https://java.net/projects/jms-spec/sources/repository/content/jms2.0a/src/main/java/javax/jms/Session.java?rev=328

Diffs can be viewed at
https://java.net/projects/jms-spec/sources/repository/diff/jms2.0a/src/main/java/javax/jms/Session.java?rev1=327&rev2=328

Comment by chris.barrow [ 12/Feb/15 ]

Thanks, looks good.

Comment by Nigel Deakin [ 14/May/15 ]

Fixed in the JMS 2.0 rev A maintenance release





[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-30] Define mandatory activation config properties clientId and subscriptionName Created: 14/Jul/11  Updated: 20/Mar/13  Resolved: 07/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0FD, 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 EJB_SPEC-41 Define mandatory activation config pr... Resolved
blocks MQ-251 Implement JMSRA activation properties... Closed
Related
is related to JMS_SPEC-54 Define a standard way to configure th... Resolved
Tags: jms20-jsr345, pd20-added

 Description   

This is a request for the JMS and/or EJB specifications to define additional mandatory activation config properties for JMS MDBs. Although MDBs are specified in the EJB specification, this request should be considered first by the JMS 2.0 expert group who may then want to raise it with the EJB 3.2 expert group.

The EJB 3.1 spec is distinctly vague about how a MDB is defined. The relevant sections are 5.4.15, 5.4.16 and 5.4.17.1. The only activation config properties defined are acknowledgeMode (only used when transactions are bean-managed, and which must be either Auto-acknowledge or Dups-ok-acknowledge), messageSelector, destinationType (which must be must be either javax.jms.Queue or javax.jms.Topic) and subscriptionDurability (which must be either Durable or NonDurable). But it doesn't specify how the destination is defined or, when subscriptionDurability is Durable, how the subscription name and client identifier are defined.

The JCA 1.6 spec has some additional guidance, at least for MDBs that use a resource adapter. Section B2 states that providers are "strongly encouraged" to provide the properties mentioned above and also destination, subscriptionName and clientId, with destination and destinationType as "required" properties.

Whatever else we do, there seems to be a clear need to make these mandatory for JMS MDBs, whether or not they use JCA.

The JMS 2.0 and EJB 3.2 expert groups should also decide whether the EJB spec is the best place to list such JMS-specific details. Although MDBs (which are not just for JMS) should remain in the EJB spec, perhaps any additional specification for JMS MDBs should be in the JMS spec.



 Comments   
Comment by Nigel Deakin [ 15/Sep/11 ]

Following discussions, it is proposed that changes are sought to the EJB 3.2 spec to add additional activation configuration properties clientId and subscriptionName for JMS message-driven beans as follows:

Section 5.4 of the EJB 3.1 spec currently defines the the following activation configuration properties for JMS message-driven beans:
acknowledgeMode (optional, default is AUTO_ACKNOWLEDGE)
messageSelector (default is an empty String)
destinationType (optional, no default)
subscriptionDurability (default is NonDurable)

This should be extended to define the following additional activation configuration properties:

clientId
subscriptionName

These property names match those recommended in JCA 1.6.

If set, clientId would be used to set clientId for the connection used by the MDB, and must be unique in accordance with JMS 1.1. There would be no default value. JMS 1.1 states that clientId must be set if a durable subscription is being used. However in JMS 2.0 JMS_SPEC-39 proposes that this requirement would be removed and clientId would always be optional.

If a durable subscription is being used, then JMS requires that subscriptionName be set. In the case of a MDB the subscriptionName is normally given a name unique to the MDB, to distinguish it from other MDBs and other applications subscribed to the same topic. It is therefore proposed that the EJB specification state that if the subscription is durable and subscriptionName is not set then the container will automatically set subscriptionName to the name of the MDB.

As with the existing activation configuration properties for JMS message-driven beans defined in the EJB specification, clientId and subscriptionName could be specified either using the MessageDriven annotation

@MessageDriven(activationConfig =  {
    @ActivationConfigProperty(propertyName = "subscriptionDurability.", propertyValue = "Durable"),
    @ActivationConfigProperty(propertyName = "clientId", propertyValue = "MyMDB"),
    @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "MySub")
})

or in ejb-jar.xml:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>test.MyMDB</ejb-name>
      <activation-config>
         <activation-config-property>
            <activation-config-property-name>subscriptionDurability</activation-config-property-name>
            <activation-config-property-value>Durable</activation-config-property-value>
         </activation-config-property>
         <activation-config-property>
            <activation-config-property-name>clientId</activation-config-property-name>
            <activation-config-property-value>MyMDB</activation-config-property-value>
         </activation-config-property>
         <activation-config-property>
            <activation-config-property-name>subscriptionName</activation-config-property-name>
            <activation-config-property-value>MySub</activation-config-property-value>
         </activation-config-property>                  
      </activation-config>
    </message-driven>
  </enterprise-beans>
</ejb-jar>

Note: The issue of how to define the destination on which a JMS message-driven bean listens for messages will be considered separately, as this is a more complex topic.

Comment by Nigel Deakin [ 07/Nov/11 ]

Added tag jsr345 to identify that this issue requires changes to the EJB spec, not the JMS spec

Comment by Nigel Deakin [ 05/Dec/12 ]

Renaming issue to reflect the fact that this issue covers the activation config properties clientId and subscriptionName only.

Comment by Nigel Deakin [ 07/Feb/13 ]

The activation properties clientId and subscriptionName are now defined in the JMS 2.0 specification, section 13.1 "MDB activation properties" as follows:

Activation property Description
clientId This property may be used to specify the client identifier that will be used when connecting to the JMS provider from which the endpoint (message-driven bean) is to receive messages.

Setting this property is always optional.
subscriptionName This property only applies to endpoints (message-driven beans) that receive messages published to a topic. It may be used to specify the name of the durable or non-durable subscription.

The EJB 3.2 specification has also been updated with a consistent definition.

Now that this feature has been added to the JMS 2.0 and EJB 3.2 specifications, this issue can be marked as resolved.





[JMS_SPEC-27] Clarify the relationship between the JMS and other Java EE specifications Created: 06/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.0

Type: Improvement Priority: Critical
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: ed20-added

 Description   

Summary

We need to clarify the relationship between the JMS and other Java EE specifications. This is mainly a documentation exercise, especially for those methods which are forbidden or modified in a EJB or Web container, but there are some ambiguities, especially when the transaction context is undefined.

More detail

If you want use the JMS API in a Java EE application such as a EJB or servlet you soon discover that much of the JMS spec (including the JMS javadocs) does not apply, at least in the EJB and web containers. For example, you aren't allowed to create message listeners, you need to defined MDBs instead. You aren't allowed to create local transactions, you need to use CMT or BMT transactions instead. You aren't allowed to set clientID on a connection. You aren't allowed to perform client acknowledgement. Essentially, in a Java EE container, the JMS API is simply different. However this is not explained in the JMS spec but is described in other specs, notably the EJB and Java EE platform specs.

Some of this information of necessity in other specs, but the absence of any mention of it in the JMS spec or javadocs is confusing to users.

I would like the JMS expert group to review what it says about JMS in other specs and consider whether this material should be moved to the JMS spec, duplicated in the JMS spec, or cross-referenced from the JMS spec. In addition the javadocs need to be clarified to mention that some API is not allowed, or has a different effect, in a Java EE web or EJB container.

I see this mainly as a documentation exercise. However this analysis will inevitably identify that some areas of behaviour are not well defined. For example, the EJB spec states explicitly that in an "undefined transactional context" it is not defined how the JMS provider should handle transactions. This means that vendors may behave differently which reduces the portability of application. If possible this should be resolved.



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

I've now updated the API, javadocs and the draft spec.
The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

I've written a completely new section to add to the new chapter 12 "Use of JMS API in Java EE applications" which was added for JMS_SPEC-45. This is intended to simply restate what is already defined in the EJB 3.1 and Java EE 6 platform specs, though I have extended it to cover the simplified API. here it is:

12.2. Restrictions on the use of JMS API in the Java EE web or EJB container

JMS applications which run in the Java EE web or EJB container are subject to a number of restrictions in the way the JMS API may be used. These restrictions are necessary for the following reasons:

  • In a Java EE web or EJB container, a JMS provider operates as a transactional resource manager which must participate in JTA transactions as defined in the Java EE platform specification. This overrides the behaviour of JMS sessions as defined elsewhere in the JMS specification. For more details see section 12.3 "Behaviour of JMS sessions in the Java EE web or EJB container".
  • The Java EE web or EJB containers need to be able to manage the threads used to run applications.
  • The Java EE web and EJB containers perform connection management which may include the pooling of JMS connections.

The restrictions described in this section do not apply to the Java EE application client container.
Applications running in the Java EE web and EJB containers must not attempt to create more than one active (not closed) Session object per connection.

  • If an application attempts to use the Connection object’s createSession method when an active Session object exists for that connection then a JMSException should be thrown.
  • If an application attempts to use the MessagingContext object's createMessagingContext method then a JMS{{RuntimeException}} should be thrown, since the first messaging context already contains a connection and session and this method would create a second session on the same connection.

The following methods are intended for use by the application server and their use by applications running in the Java EE web or EJB container may interfere with the container's ability to properly manage the threads used in the runtime environment. They must therefore not be called by applications running in the Java EE web or EJB container:

  • javax.jms.Session method setMessageListener
  • javax.jms.Session method getMessageListener
  • javax.jms.Session method setBatchMessageListener
  • javax.jms.Session method getBatchMessageListener
  • javax.jms.Session method run
  • javax.jms.Connection method createConnectionConsumer
  • javax.jms.Connection method createDurableConnectionConsumer

The following methods may interfere with the container's ability to properly manage the threads used in the runtime environment and must not be used by applications running in the Java EE web or EJB container:

  • javax.jms.MessageConsumer method setMessageListener
  • javax.jms.MessageConsumer method getMessageListener
  • javax.jms.MessageConsumer method setBatchMessageListener
  • javax.jms.MessageConsumer method getBatchMessageListener
  • javax.jms.MessagingContext method setMessageListener
  • javax.jms.MessagingContext method getMessageListener
  • javax.jms.MessagingContext method setBatchMessageListener
  • javax.jms.MessagingContext method getBatchMessageListener

This restriction means that applications running in the Java EE web or EJB container which need to receive messages asynchronously may only do so using message-driven beans.

The following methods may interfere with the container's management of connections and must not be used by applications running in the Java EE web or EJB container:

  • javax.jms.Connection method setClientID
  • javax.jms.Connection method stop
  • javax.jms.Connection method setExceptionListener
  • javax.jms.MessagingContext method setClientID
  • javax.jms.MessagingContext method stop
  • javax.jms.MessagingContext method setExceptionListener

Applications which need to use a specific client identifier must set it on the connection factory, as described in section 4.3.2 "Client Identifier"

All the methods listed in this section may throw a javax.jms.JMSException (if allowed by the method) or a javax.jms.JMSRuntimeException (if not) when called by an application running in the Java EE web or EJB container. This is recommended but not required.

Comment by Nigel Deakin [ 26/Jan/12 ]

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

The javadocs for all the methods listed above which are not permitted in a Java EE web or Java EE container now include the following statement:

* This method must not be used in a Java EE web or EJB application. 
* Doing so may cause a <code>JMSException</code> to be thrown though this is not guaranteed.

In addition, the list of exceptions for these methods now states that they may throw a JMSException (or JMSRuntimeException if called in a Java EE web or EJB container, together with the caveat that "it is not guaranteed that an exception is thrown in this case"

The three Connection methods createSession now include the statement:

* Applications running in the Java EE web and EJB containers must not attempt 
* to create more than one active (not closed) <code>Session</code> object per connection. 
* If this method is called in a Java EE web or EJB container when an active
* <code>Session</code> object already exists for this connection 
* then a <code>JMSException</code> will be thrown.

The list of exceptions for these methods states that they will (must) throw a JMSException if "this method is being called in a Java EE web or EJB application and an active session already exists for this connection."

The MessageConsumer method createMessagingContext now includes the statement:

* This method is for use in a Java SE environment or in the Java EE application client container only. 
* It may not be used in a Java EE environment because this would violate
* the Java EE restriction that a connection may have only one session.

The list of exceptions for this method now states that it will (must) throw an exception if "this method is being called in a Java EE web or EJB application"

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-54] Define a standard way to configure the destination on which a JMS MDB consumes messages Created: 21/Oct/11  Updated: 20/Mar/13  Resolved: 07/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0FD, 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 CONNECTOR_SPEC-4 Clarify whether the ResourceAdapter.e... Resolved
blocks MQ-250 Implement JMSRA activation properties... Closed
Related
is related to JMS_SPEC-30 Define mandatory activation config pr... Resolved
is related to JMS_SPEC-55 Define a standard way to configure th... Resolved
Tags: eg, jms20-jsr345, pd20-added

 Description   

This is a request for the JMS and/or EJB specifications to improve the way in which specify how an application or deployer may specify the destination from which a JMS message-driven bean to receive messages. There are several significant omissions from the specification which need to be rectified.

Although MDBs are specified in the EJB specification, this request should be considered first by the JMS 2.0 expert group who may then want to raise it with the EJB 3.2 expert group.

Review of existing specification (EJB 3.1)

In the EJB 3.1 specification, Section 16.9 "Message Destination References" states that the destination used by a JMS message-driven bean can be specified using the <message-destination-link> element of the <message-driven> element in ejb-jar.xml:

<message-driven>
   <ejb-name>ExpenseProcessing</ejb-name>
   <ejb-class>com.wombat.empl.ExpenseProcessingBean</ejb-class>
   <messaging-type>javax.jms.MessageListener</messaging-type>
   ...
   <message-destination-type>javax.jms.Queue</message-destination-type>
   <message-destination-link>ExpenseProcessingQueue</message-destination-link>
   ...
</message-driven>

Issues with the existing specification

This raises the following questions:

1. What is <message-destination-link>?

The <message-destination-link> element defines the destination from which the MDB consumes messages in terms of a "message destination reference".

The purpose of "message destination references" is to allow an application which sends messages to a particular destination and also consumes from the same destination to inform the deployer of this fact without having to actually specify the name (or JNDI name) of the destination.

As stated above, a MDB can specify the "message destination reference" of the destination from which it consumes messages using a <message-destination-link> element under the <message-driven> element. Another component (e.g. a session bean or another MDB) can specify the destination to which it sends messages using a <message-destination-link> element under a <message-destination-ref> element. If these two elements contain the same string then the deployer knows they refer to the same queue or topic.

A message destination reference is not the JNDI name of the queue or topic. It is just a logical name. It can be mapped to an actual JNDI name using the <assembly-descriptor> element in ejb-jar.xml as follows:

Here's how ejb-jar.xml could be used to define a MDB as consuming messages from a "message destination reference" called MsgBeanInQueue which was mapped to a JNDI name jms/inboundQueue:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <display-name>MDB1</display-name>
      <ejb-name>MessageBean</ejb-name>
      <messaging-type>javax.jms.MessageListener</messaging-type>
      <transaction-type>Container</transaction-type>
      <message-destination-type>javax.jms.Queue</message-destination-type>
      <message-destination-link>MsgBeanInQueue</message-destination-link>
    </message-driven>
  </enterprise-beans>
  <assembly-descriptor>
    <message-destination>
      <lookup-name>jms/inboundQueue</lookup-name>   <!---
      <message-destination-name>MsgBeanInQueue</message-destination-name>
    </message-destination>
  </assembly-descriptor>
</ejb-jar> 

A message destination reference can typically also be mapped to an actual JNDI name using the application-server-specific deployment descriptor, though by definition this is beyond the scope of the EJB specification.

2. Is that the only way you can define the destination on which a MDB consumes messages in ejb-jar.xml? Can you define its JNDI name directly without bothering with references?

No, the EJB specification doesn't mention any way to define the destination in ejb-jar.xml apart from using the <message-destination-link> element of ejb-jar.xml. In particular it doesn't define any way to define its JNDI name directly, analogous to using either the JNDI API or a @Resource(lookup="jms/foo") declaration for managed connections.

3. Can I define the message destination reference for a MDB using annotation?

No, there is equivalent to <message-destination-link> using annotation.

4. Can I define the JNDI name of the destination on which a MDB consumes messages directly using annotation?

No, there is no way to define this using annotation, analogous to using a @Resource(lookup="jms/foo") declaration when using the JMS API directly.

So, what seems to be missing?

A. As explained in (2) and (4) above, there isn't a standard way for MDB applications to short-circuit the use of message destination references and define the JNDI name of the destination from which a JMS message-driven bean consumes messages, either using ejb-jar.xml or annotations. This contrasts with EJBs which send messages, where the JNDI name of the destination can be specified in the MDB code using the JNDI API or a @Resource(lookup="jms/foo") declaration.

B. As explained in (3) above, there is no standard way for the application to define using annotation the "message destination reference" on which the JMS message-driven bean is consuming messages.

Proposals:

A. It is proposed that the <message-driven> element in ejb-jar.xml be extended to define an additional sub-element which can be used to specify the JNDI name of the destination from which a JMS message-driven mean consumes messages. A suggested element name is <message-destination-jndi-name>:

<ejb-jar>
  <display-name>Ejb1</display-name>
  <enterprise-beans>
    <message-driven>
      <display-name>MDB1</display-name>
      <ejb-name>MessageBean</ejb-name>
      <message-destination-type>javax.jms.Queue</message-destination-type>
      <message-destination-jndi-name>jms/inboundQueue<message-destination-jndi-name>
      ...

It might be asked why this needs to be defined by a new subelement of <message-driven> rather than, say, a new standard activation configuration property. The answer is that the way that the JNDI name is defined needs to be consistent with the way that the message destination reference is defined, which is by the <message-destination-link> subelement of <message-driven>

B. It is proposed that the equivalent annotation be a new attribute of the @MessageDriven annotation, called messageDestinationJndiName. For example:

@MessageDriven(messageDestinationJndiName="jms/inboundQueue")
public class MyMDB implements MessageListener {
....

C. It is proposed that the @MessageDriven annotation be extended to allow applications to define the "message destination reference" on which the JMS message-driven bean is consuming messages, using a new attribute messageDestinationLink"

@MessageDriven(messageDestinationLink="ExpenseProcessingQueue")
public class MyMDB implements MessageListener {
....


 Comments   
Comment by rdohna [ 25/Oct/11 ]

Linked these two issues

Comment by Nigel Deakin [ 25/Oct/11 ]

Corrected names of annotation attributes

Comment by Nigel Deakin [ 07/Nov/11 ]

Added tag jsr345 to identify that this issue requires changes to the EJB spec, not the JMS spec

Comment by Nigel Deakin [ 05/Dec/12 ]

The current proposal is to define a standard activation property destinationLookup.

However this is only possible if the connector spec can guarantee that the resource adapter will be able to perform the lookup in the endpointActivation call. I have logged CONNECTOR_SPEC-4 to request clarification .

Comment by Nigel Deakin [ 07/Feb/13 ]

Note that CONNECTOR_SPEC-4 is now resolved.

Comment by Nigel Deakin [ 07/Feb/13 ]

The JMS 2.0 and EJB 3.2 specifications now define a activation property destinationLookup. This is defined as follows (JMS 2.0 section 13.1 "MDB activation properties"):

Activation property Description
destinationLookup This property may be used to specify the lookup name of an administratively-defined javax.jms.Queue or javax.jms.Topic object which defines the JMS queue or topic from which the endpoint (message-driven bean) is to receive messages.

This issue can now be marked as resolved.





[JMS_SPEC-52] Clarify that a message may be sent using a different session from that used to create the message Created: 21/Sep/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.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-170 Implement clarified behaviour of meth... Open
Tags: ed20-added

 Description   

The JMS 1.1 API defines how a JMS message object is created using one of the following methods on a Session:

Message 	createMessage() 
BytesMessage 	createBytesMessage() 
MapMessage 	createMapMessage() 
ObjectMessage 	createObjectMessage() 
ObjectMessage 	createObjectMessage(java.io.Serializable object) 
StreamMessage 	createStreamMessage() 
TextMessage 	createTextMessage() 
TextMessage 	createTextMessage(java.lang.String text) 

The following question has been raised:

Can a message be sent using a MessageProducer that was created from a different Session than was used to create the message?

This is not stated explicitly in the specification, and discussions within the JSR 343 Expert group show that different individuals have come to different conclusions on this issue.

My own interpretation is that a MessageProducer must be able to send a javax.JMS.Message irrespective of how it was created. It might have been created using Session.createMessage(), or it may have been received by a MessageConsumer.

Section 4.4.5 "Optimized message implementations" of the JMS 1.1 specification states:

A session provides message create methods that use provider-optimized implementations. This allows a provider to minimize its overhead for handling messages.
Sessions must be capable of sending all JMS messages regardless of how they may be implemented.

Furthermore, Section 3.12 of the JMS 1.1 specification states explicitly that a MessageProducer must be able to send a message that was created using a different JMS provider, and which would therefore have used a different session:

A provider must be prepared to accept, from a client, a message whose implementation is not one of its own. A message with a 'foreign' implementation may not be handled as efficiently as a provider's own implementation; however, it must be handled.

Despite this, there is a widespread view within the JMS community that for messages created within the same JVM by the same JMS provider, the session used to create the message must be the same as that used to send it.

It is therefore proposed that the JMS specification be clarified that there is no such restriction, and that a MessageProducer can be used to send any message object

  • irrespective of which session or connection was used to create it,
  • irrespective of whether the message was created within this JVM or received from a JMS destination, and
  • irrespective of whether the MessageProducer and message are implemented by the same or different JMS providers.


 Comments   
Comment by Nigel Deakin [ 22/Sep/11 ]

Edited description to clarify that a MessageProducer can be used to send any message object
irrespective of what connection (as well as session) was used to create it.

Comment by Nigel Deakin [ 19/Dec/11 ]

I've now updated the javadocs and the draft spec to clarify this issue (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

The six message-creation methods on Session have been modified to include the following additional javadoc comments:

* The message object returned may be sent using any session or messaging context. 
* It is not restricted to being sent using the session used to create it.
* <p>
* The message object returned may be optimised for use with the JMS provider
* used to create it. However it can be sent using any JMS provider, not just the 
* JMS provider used to create it.

The second sentence above has been included because it would be confusing and inconsistent to mention that a message may be sent using a different session and not also mention the even more significant fact that a message may be sent using a different JMS provider.

The six message-creation methods on the proposed new MessagingContext interface have been modified to include the following additional javadoc comments:

* The message object returned may be sent using any session or messaging context. 
* It is not restricted to being sent using the messaging context used to create it.
* <p>
* The message object returned may be optimised for use with the JMS provider
* used to create it. However it can be sent using any JMS provider, not just the 
* JMS provider used to create it.

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:

Section 4.4.5. "Optimized Message Implementations" has been updated to state:

A session provides the following methods to create messages: createMessage, createBytesMessage, createMapMessage, createObjectMessage, createStreamMessage and createTextMessage.

These methods allow the JMS provider to create message implementations which are optimized for that particular provider and allow the provider to minimize its overhead for handling messages.

A session provides message create methods that use provider-optimized implementations. This allows a provider to minimize its overhead for handling messagesHowever .the fact that these methods are provided on a session does not mean that messages must be sent using a message producer created from the same session. Messages may be sent using any session, not just the session used to create the message.

Furthermore, Sessions must be capable of sending all JMS messages regardless of how they may be implemented. See section 3.12 "Provider Implementations of JMS Message Interfaces".

Section 11.5.5 "Clarification: message may be sent using any session" is the change log for this clarification.





[JMS_SPEC-51] New methods to replace Session.createDurableSubscriber() and return a MessageConsumer Created: 16/Sep/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.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-171 New methods to replace Session.create... Closed
Tags: ed20-added

 Description   

In JMS 1.1 the following two methods on Session return a TopicSubscriber.

TopicSubscriber createDurableSubscriber(Topic topic)

TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal)

These are the only "domain-independent" methods in the whole JMS 1.1 API which depend on a "domain-specific" interface. This dependency prevents the "domain-specific" interfaces being removed from JMS as proposed in JMS_SPEC-47.

It is therefore proposed to modify these methods to return a MessageConsumer. Since this is a supertype of TopicSubscriber it should not break existing applications.



 Comments   
Comment by Nigel Deakin [ 20/Sep/11 ]

It has been pointed out that the above proposal would require existing applications would need to cast the MessageConsumer that is returned down to a TopicSubscriber.

This suggests that we need to provide new versions of this method which return a MessageConsumer. This would allow us to mark the old methods as deprecated and propose them for removal.

We can't simply add new methods with the same name which return a MessageConsumer since the compiler would consider these duplicate methods.

Two options have been proposed:

Option 1

We could define new methods named createConsumer:

MessageConsumer createConsumer(Topic topic, java.lang.String name)

MessageConsumer createConsumer(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal)

However there's potential confusion between the first of those methods and the existing method to create an ordinary consumer with a message selector:

MessageConsumer createConsumer(Destination destination, java.lang.String messageSelector)

The compiler would allow it, but if the user tried to create a durable subscription using a variable which was really a Topic but which was declared as Destination then the wrong method would be called.

It could also be argued that removing the word "durable" from the method name would be confusing for users.

We could either live with these drawbacks, or we could use:

Option 2

We could define new methods named createDurableConsumer:

MessageConsumer createDurableConsumer(Topic topic, java.lang.String name)

MessageConsumer createDurableConsumer(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal)

Comment by Nigel Deakin [ 03/Jan/12 ]

Following a discussion within the JSR 343 expert group I've selected option 2 above.

I've now updated the javadocs and the draft spec accordingly (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
(Two createDurableConsumer methods have been added to Session. See below for javadocs).

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 6.11.1 "Durable TopicSubscriber" and 11.5.9 "createDurableConsumer" which is the change log).

Here are the two new methods:

    /** Creates a durable subscription with the specified name on the
      * specified topic, and creates a <code>MessageConsumer</code> 
      * on that durable subscription.
      * <P>
      * If the durable subscription already exists then this method
      * creates a <code>MessageConsumer</code> on the existing durable
      * subscription.
      * <p>
      * A durable subscription is used by a client which needs to receive
      * all the messages published on a topic, including the ones published 
      * when there is no <code>MessageConsumer</code> or <code>TopicSubscriber</code> associated with it. 
      * The JMS provider retains a record of this durable subscription 
      * and ensures that all messages from the topic's publishers are retained 
      * until they are delivered to, and acknowledged by,
      * a <code>MessageConsumer</code> or <code>TopicSubscriber</code> on this durable subscription
      * or until they have expired.
      * <p>
      * A durable subscription will continue to accumulate messages 
      * until it is deleted using the <code>unsubscribe</code> method. 
      * <p>
      * A durable subscription which has a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being active. 
      * A durable subscription which has no <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being inactive. 
      * <p>
      * Only one session at a time can have a
      * <code>MessageConsumer</code> or <code>TopicSubscriber</code> for a particular durable subscription.
      * <p>
      * A durable subscription is identified by a name specified by the client
      * and by the client identifier if set. If the client identifier was set
      * when the durable subscription was first created then a client which 
      * subsequently wishes to create a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * on that durable subscription must use the same client identifier.
      * <p>
      * A client can change an existing durable subscription by calling
      * <code>createDurableConsumer</code> 
      * with the same name and client identifier (if used),
      * 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.
      *
      * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
      * @param name the name used to identify this subscription
      *  
      * @exception JMSException if the session fails to create the durable subscription 
      *            and <code>MessageConsumer</code> due to some internal error.
      * @exception InvalidDestinationException if an invalid topic is specified.
      *
      * @since 2.0
      */ 
     MessageConsumer createDurableConsumer(Topic topic, String name) throws JMSException;
     /** Creates a durable subscription with the specified name on the
      * specified topic, and creates a <code>MessageConsumer</code> 
      * on that durable subscription, specifying a message 
      * selector and whether messages published by its
      * own connection should be delivered to it.
      * <P>
      * If the durable subscription already exists then this method
      * creates a <code>MessageConsumer</code> on the existing durable
      * subscription.
      * <p>
      * A durable subscription is used by a client which needs to receive
      * all the messages published on a topic, including the ones published 
      * when there is no <code>MessageConsumer</code> or <code>TopicSubscriber</code> associated with it. 
      * The JMS provider retains a record of this durable subscription 
      * and ensures that all messages from the topic's publishers are retained 
      * until they are delivered to, and acknowledged by,
      * a <code>MessageConsumer</code> or <code>TopicSubscriber</code> on this durable subscription
      * or until they have expired.
      * <p>
      * A durable subscription will continue to accumulate messages 
      * until it is deleted using the <code>unsubscribe</code> method. 
      * <p>
      * A durable subscription which has a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being active. 
      * A durable subscription which has no <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being inactive. 
      * <p>
      * Only one session at a time can have a
      * <code>MessageConsumer</code> or <code>TopicSubscriber</code> for a particular durable subscription.
      * <p>
      * A durable subscription is identified by a name specified by the client
      * and by the client identifier if set. If the client identifier was set
      * when the durable subscription was first created then a client which 
      * subsequently wishes to create a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * on that durable subscription must use the same client identifier.
      * <p>
      * A client can change an existing durable subscription by calling
      * <code>createDurableConsumer</code> 
      * with the same name and client identifier (if used),
      * 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.
      *
      * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
      * @param name the name used to identify this 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 noLocal if set, inhibits the delivery of messages published
      * by its own connection
      *  
      * @exception JMSException if the session fails to create the durable subscription 
      *                         and <code>MessageConsumer</code> due to some internal error.
      * @exception InvalidDestinationException if an invalid topic is specified.
      * @exception InvalidSelectorException if the message selector is invalid.
      *
      * @since 2.0
      */ 
      MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;   
Comment by Nigel Deakin [ 03/Jan/12 ]

I've changed the summary line for this issue from
Change Session.createDurableSubscriber() to return a MessageConsumer
to
New methods to replace Session.createDurableSubscriber() and return a MessageConsumer.

This reflects the decision not to change the existing methods (to preserve backwards compatibility) but to add new methods.





[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.





[JMS_SPEC-45] Clarify and improve Connection.createSession Created: 09/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0ED, 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-172 Implement two new Connection.createS... Closed
Tags: ed20-added

 Description   

In the JMS 1.1 specification, the following method on a javax.jms.Connection is used to create a javax.jms.Session:

Session createSession(boolean transacted, int acknowledgeMode) throws JMSException

where transacted may be set to true or false and
acknowledgeMode may be set to Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, and Session.DUPS_OK_ACKNOWLEDGE

(There are similar methods on javax.jms.QueueConnection and javax.jms.TopicConnection: this whole issue applies to all three.)

This is a rather confusing method for several reasons:

  • It uses two arguments to define a single aspect of the session
  • In a Java EE transaction, both arguments are ignored anyway
  • In a Java EE unspecified transaction context, the meaning of the arguments is undefined and unclear

It uses two arguments to define the same thing

This method uses two arguments to define what is in practice a single aspect of the session with four possibilities: if transacted is set to false then the session is non-transacted and the acknowledgeMode argument defines which of three kinds of acknowledgement are used when receiving messages. If transacted is set to true then the acknowledgeMode argument is ignored.

This is inconsistent with the method Session.getAcknowledgeMode() which returns one of four values: Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, or Session.DUPS_OK_ACKNOWLEDGE if the session is not transacted and Session.SESSION_TRANSACTED if the session is transacted.

This also leads to code which is potentially misleading, since if transacted is false the user still has to set acknowledgeMode to some value even if it is ignored, which leads to code such as

Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);

Some developers like to use

Session session = connection.createSession(true,Session.SESSION_TRANSACTED);

though this is still misleading since since if transacted was set to true then the second argument is ignored anyway, and if transacted is false then setting acknowledgeMode to Session.SESSION_TRANSACTED would be an error.

In a Java EE transaction, both arguments are ignored anyway

In a Java EE transaction none of the four options listed above are permitted. Instead, both arguments to connection.createSession are ignored and a global transaction is used.

The EJB 3.1 Specification, section 13.3.5 "use of JMS APIs in Transactions" states that, in a container-managed or bean-managed transaction,

Because the container manages the transactional enlistment of JMS sessions on behalf of a bean, the parameters of the createSession(boolean transacted, int acknowledgeMode) method createQueueSession... are ignored.

This also applies to web applications. The Java EE platform spec, Section EE.6.7 "Java Message Service (JMS) 1.1 Requirements" specifies that

The behavior of a JMS provider should be the same in both the EJB container and the web container." It continues "The EJB specification describes restrictions on the use of JMS in an EJB container, as well as the interaction of JMS with transactions in an EJB container. Applications running in the web container should follow the same restrictions.

Instead, the receiving and sending of messages must be part of the container-managed or bean-managed transaction, and the transaction will be committed or rolled back in the way that container-managed or bean-managed transactions are committed or rolled back.

  • Container-managed transactions are either committed when the appropriate business method completes or are rolled back using EJBContext.setRollbackOnly.
  • Bean-managed transactions are either committed using UserTransaction.commit or rolled back using UserTransaction.rollback.

How explicit is the EJB specification about all this? In addition to specifying that in a transactional context the arguments to Connection.createSession are ignored, it also states the following:

  • Section 13.3.5 states that "within a transaction" the bean should not use the acknowledge method. This therefore covers both container-managed and bean-managed transactions.
  • Section 13.3.3 states that in the case of bean-managed transactions, the bean must not invoke the commit or rollback methods on the javax.jms.Session interface.
  • Section 13.3.4 states that in the case of container-managed transactions, the bean must not "use any resource-managed specific transaction management methods that would interfere with the container's demarcation of transaction boundaries" and again must not invoke the commit or rollback methods on the javax.jms.Session interface.
  • Section 13.1.1 states that in the case of bean-managed transactions, "all resource manager accesses between the UserTransaction.begin and UserTransaction.commit calls are part of a transaction", thereby apparently ruling out the use of non-transacted sessions using auto-acknowledgement and dups-ok-acknowledgement as well as those using client-acknowledgement.
  • Section 13.1.1 also states in a container-managed transaction the transaction demarcation depends on the transaction attributes of the bean method. It doesn't explicitly state that all resource manager accesses should be part of this transaction, but this is implied.

In a Java EE unspecified transaction context, the meaning of the arguments undefined and unclear

The previous section only relates to the use of the JMS API "in transactions". It does not cover how the JMS API should behave when there is no current container-managed or bean-managed transaction. That is, when there is an unspecified transaction context.

The EJB 3.1 Specification, section 13.6.5 "Handling of Methods that run with an unspecified transaction context" defines an "unspecified transaction context" as covering "the cases in which the EJB architecture does not fully define the transaction semantics of an enterprise bean method execution".

Section 13.6.5 goes on to give a list of examples of when an "unspecified transaction context" may arise. All the cases given are for container-managed transactions, leaving an ambiguity about what an "unspecified transaction context" means when using bean-managed transactions. An obvious interpretation is that that if a bean is configured to use bean-managed transactions, then business methods or onMessage() code executed before a call to userTransaction.begin(), or after a call to UserTransaction.commit or UserTransaction.rollback, is executed in an unspecified transaction context, as is any code executed in the four bean lifecycle callback methods listed in 13.6.5 (PostConstruct,PreDestroy, PostActivate, or PrePassivate). However this is not explicitly stated in the EJB spec.

So, what does the EJB spec say should happen in an "unspecified transaction context"?

Section 13.6.5 is written with all resource managers (not just JMS) in mind, and states that

"The EJB specification does not prescribe how the container should manage the execution of a method with an unspecified transaction context—the transaction semantics are left to the container implementation.

It goes on to give some options, which include treating "each call... to a resource manager as a single transaction", merging multiple calls into a single transaction, or accessing the resource manager "without a transaction context".

Now in the case of JMS the application has a way to give the container a hint as to what behaviour they desire: the arguments to {[createSession}}. So it would seem reasonable to follow these.

However the EJB 3.1 specification, section 13.3.5 does explicitly state that "The Bean Provider should not use the JMS acknowledge method either within a transaction or within an unspecified transaction context. Message acknowledgment in an unspecified transaction context is handled by the container.

It is curious that although Session.acknowledge is prohibited in a unspecified transaction context, Session.commit is not, even though both perform message acknowledgement. If the former is invalid, then the latter must be as well.

This means that within an unspecified transaction context:

  • a non-transacted session using client acknowledgement is explicitly prohibited
  • a (local) transacted session is implicitly prohibited
  • a non-transacted session is permitted, with both client-acknowledgement and dups-ok-acknowledgement (which is an optimised version of auto-acknowledgement) allowed.

Summary

So in Connection.createSession (and QueueConnection.createQueueSession and TopicConnection.createTopicSession we have a method which offers different options depending on the context in which it is used:

  • In a Java EE transaction there are no options: the session is part of a transaction managed by the container and the application has no choice on the matter.
  • In a Java EE unspecified transaction context there are two options:
    • non-transacted session with auto-acknowledgement
    • non-transacted session with dups-ok-acknowledgement
  • In a Java SE environment there are four options:
    • non-transacted session with auto-acknowledgement
    • non-transacted session with dups-ok-acknowledgement
    • non-transacted session with client-acknowledgement
    • transacted session

So, in the light of all this, what are the problems?

  • the special behaviour of this method in a Java EE transaction is not mentioned anywhere in the JMS specification or in the javadocs, which means that users are surprised when they discover that the arguments to createSession are ignored. Fortunately, however, the required behaviour is clearly defined in the EJB specification.
  • the special behaviour in a Java EE unspecified transaction context is also not mentioned anywhere in the JMS specification or in the javadocs. Unfortunately, the required behaviour is not explicitly described in the EJB specification but has to be pieced together from various different sections, as in the analysis above. This needs to be confirmed and stated explicitly.
  • the actual API for createSession, with its two arguments, not only does not reflect the four options available in the normal Java SE case, it does not reflect the zero options available in the Java EE transaction case or the two options available in the Java EE unspecified transaction context case. However when compared the the two preceding issues this is perhaps not such a major issue.

Proposals

It is proposed that

  • The JMS specification and javadocs be updated to describe how createSession behaves in a Java EE applicaiton, both in a transaction and in an unspecified transaction context. The former case will be a restatement of the existing EJB spec, the latter case will be intended to remove any ambiguities in the EJB spec along the lines of the analysis above.
  • A new method be provided in a javax.jms.Connection
Session createSession(int sessionMode) throws JMSException

In a normal Java SE environment sessionMode may be set to 
Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE 
or Session.TRANSACTED

In a Java EE transaction, sessionMode is ignored.

In a Java EE undefined transaction context, sessionMode may be set to 
Session.AUTO_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE only.
  • A further new method be provided in a javax.jms.Connection
Session createSession() throws JMSException

This method is  particularly intended for use in a Java EE environment,
though it may also be used in a normal Java SE environment.

In a normal Java SE environmentm this is equivalent to calling createSession(Session.AUTO_ACKNOWLEDGE)

In a Java EE transaction, the session will be part of a transaction managed by the container. 

In a Java EE undefined transaction context, the session will have a sessionMode of Session.AUTO_ACKNOWLEDGE.
  • The existing method createSession(boolean transacted,int acknowledgeMode will remain with a note added to encourage applications to use the other two methods. In accordance with Java EE policy it will remain in the API indefinitely, and will not be formally marked as @Deprecated.


 Comments   
Comment by Nigel Deakin [ 23/Sep/11 ]

Description updated to propose new method Session createSession() with no arguments for use in a Java EE environment.

Comment by Nigel Deakin [ 30/Sep/11 ]

Updated to propose that the existing method createSession(boolean transacted,int acknowledgeMode will be formally marked as @Deprecated

Comment by Nigel Deakin [ 18/Oct/11 ]

Do we need a new method getSessionMode()?

There is already a method getAcknowledgeMode() which Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE or Session.TRANSACTED as appropriate. It therefore already returns the session mode though the name is misleading.

We have lived with this mis-named method for a long time so I don't think it is necessary to create a new method getSessionMode() which is functionally identical but more appropriately named. We could never remove the old method, so this would simply clutter up the API whilst confusing the user.

We should therefore stick with getAcknowledgeMode and change the javadoc documentation to clarify that what it returns is the same as the session mode.

Comment by Nigel Deakin [ 13/Jan/12 ]

Before we finalise the above proposals I'd like to explore in more detail exactly how createSession (and other methods in the JMS API) are required to behave in a Java EE environment. Before we can clarify the use of this method we need to be able to answer the following questions.

(I've already suggested answers to some, but not all, of these questions in my proposals above. However I think it's very important to get this right and it's work revisiting them. In addition, there are several additional issues which need to be answered before users can unambiguously know how this method is required to behave.)

1. JMS resources which do not support JTA transactions

In the EJB 3.1 specification, section 13.3.5 "use of JMS APIs in Transactions" states that:

Because the container manages the transactional enlistment of JMS sessions on behalf of a bean, the parameters of the createSession(boolean transacted, int acknowledgeMode) method createQueueSession... are ignored."

The reference to "transaction enlistment" appears to be a reference to JTA transactions managed by the application server, which may be "bean-managed" (using the UserTransaction API to begin and commit the transaction) or, for EJBs, "container-managed".

Q1.1: Does the sentence quoted above mean that the JMS session must participate in the transaction, or is it permitted to create a session which does not participate in the transaction.

There have been suggestions that connections which are "non-managed" or "non-JCA" connections are not required to participate in the transaction. However there is no mention of such cases in the EJB spec.

Q1.2: Is this permitted?

Q1.3: Are such cases also exempt from the requirement that the arguments to createSession be ignored?

2. When there isn't a container-managed or bean-managed transaction.

I'd also like to explore the case where there isn't a container-managed or bean-managed transaction. The EJB 3.1 Specification, section 13.6.5 "Handling of Methods that run with an unspecified transaction context" contains some guidance about the transaction semantics in such a case.

Q2.1: What is an "unspecified transaction context"? Does this mean any case where there is not an active JTA transaction, such as where the transaction attribute is set to "Never"? Does it include the BMT case before userTransaction.begin() or after userTransaction.commit()? Does it include all of the EJB callback methods?

3. The ban on calling acknowledge()

Section 13.3.5 of the EJB spec, "Use of JMS APIs in Transactions", states that "The Bean Provider should not use the JMS acknowledge method either within a transaction or within an unspecified transaction context. Message acknowledgment in an unspecified transaction context is handled by the container."

Q3.1: What is the reason for this restriction? Is it necessary?

Q3.2: If acknowledge is called in a Java EE environment, what should happen? Should an exception be thrown?

Q3.3: Do these restrictions on explicit message acknowledgement also apply to local transactions, given that calling session.commit has the effect of acknowledging all messages received in the local transaction?

4. Bean-managed transactions

In a application that uses bean-managed transactions, what happens if the session is created before the transaction is started? Consider the following:

Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(destination);
producer.send(message1);
userTransaction.begin();
producer.send(message2);
. . .
userTransaction.commit();

Q4.1: Is this valid?

Q4.2: Is message1 sent immediately or is it committed as part of the user transaction?

Q4.3: Is message2 sent immediately or is it committed as part of the user transaction?

Comment by Nigel Deakin [ 24/Jan/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

  • New methods Connection.createSession(int sessionMode) and Connection.createSession() which create a Session.
  • New javadoc comment for the existing method Connection.createSession(boolean transacted, int acknowledgeMode) which creates a Session.
  • New javadoc comments for the various methods on ConnectionFactory and MessagingContext which create a MessagingContext

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

  • Updated section 1.4.7 "Java Platform, Enterprise Edition (Java EE)"
  • Deleted section 1.4.8 "Integration of JMS with the EJB Components"
  • New chapter 12 "Use of JMS API in Java EE applications"
  • New section 12.2 "Use of JMS API in Java EE applications"
  • New sections 11.5.14 & 11.5.15 which are the change log for these changes

(I'll come back later and formally answer the questions I made in the previous comment)

Comment by Nigel Deakin [ 24/Jan/12 ]

I have updated the description above to remove the statement that the existing method createSession(boolean transacted,int acknowledgeMode will be marked as @Deprecated and that the javadocs will warn that this method may be removed in the future.

The Java EE Backwards Compatibility Requirements do not allow us to use @Deprecated, not do they allow us to remove existing methods from the API.

Instead the javadoc comment for this method will simply have a note which encourages applications to use the other two createSession methods instead.

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-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-42] Make support for JMSXDeliveryCount mandatory Created: 05/Aug/11  Updated: 02/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.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-173 Implement JMSXDeliveryCount Closed
blocks MQ-236 Broker support JMS2.0 mandatory JMSXD... Closed
Tags: ed20-added

 Description   

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

It is proposed that support for the JMS defined message property JMSXDeliveryCount be made mandatory.

The JMS 1.1 specification currently defines an optional JMS defined message property JMSXDeliveryCount. When used, this is set by the JMS provider when a message is received, and is set to the number of times this message has been delivered (including the first time). The first time is 1, the second time 2, etc.

Support for this property would allow arbitrary containers and applications to improve the way they handle "poisonous" messages - messages which cannot be consumed for some reason and need to be redelivered. For example, it would allow applications to detect when a message has been redelivered more than a specified number of times and perform some special handling such as redirecting it to some other destination.

This property wouldn't need to be perfectly accurate every time. For example, it wouldn't be necessary to persist this value in the server. A "best efforts" implementation would probably be adequately.



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

I've now updated the javadocs and the draft spec with this change (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

The only change is to Message. This wording is very generic and doesn't mention individual properties. All I've done is to mention that some properties may be mandatory, some may be optional. I've also added a clarification to state that the effect of setting a message selector on a property (such as JMSXDeliveryCount) which is set by the provider on receive is undefined.

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:

Section 3.5.9 "JMS Defined Properties" has been updated to state that the property JMSXDeliveryCount is now mandatory with a reference to 3.5.11 "JMSXDeliveryCount" for a definition.

Some of the wording in this section has been rearranged to reflect the fact that some properties are optional but that one (JMSXDeliveryCount) is now mandatory. A clarification has been added to state that the effect of setting a message selector on a property (such as JMSXDeliveryCount) which is set by the provider on receive is undefined.

Section 3.4.7 "JMSRedelivered" has been updated to say "The JMS-defined message property JMSXDeliveryCount will be set to the number of times a particular message has been delivered. See section 3.5.11 "JMSXDeliveryCount".

A new section 3.5.11 "JMSXDeliveryCount" has been added. This states:

When a client receives a message the mandatory JMS-defined message property JMSXDeliveryCount will be set to the number of times the message has been delivered. The first time a message is received it will be set to 1, so a value of 2 or more means the message has been redelivered.

If the JMSRedelivered value is set then the {{JMSXDeliveryCount}}property must always be 2 or more.

The purpose of the JMSXDeliveryCount property is to allow consuming applications to identify whether a particular message is being repeatedly redelivered and take appropriate action.

The value of the JMSXDeliveryCount property is not guaranteed to be exactly correct. The JMS provider is not expected to persist this value to ensure that its value is not lost in the event of a failure.

4.4.11 Message Acknowledgement: The sentence "a session must set the JMSRedelivered flag of messages it redelivers due to a recovery" has been amended to state that it should also increment the JMSXDeliveryCount property as well.

4.4.12 "Duplicate Delivery of Messages": The sentence "The JMSRedelivered message header field will be set for a message redelivered under these circumstances" has been amended to the JMSXDeliveryCount property should be incremented as well.

4.5.2 "Asynchronous delivery": This states that if a message listener throws an exception in AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE mode the message will be immediately redelivered and the JMSRedelivered message header field will be set. This has been amended to state that the JMSXDeliveryCount message property will be incremented as well.

4.10. "Reliability": This states "Unacknowledged messages redelivered due to system failure must have the JMSRedelivered message header field set by the JMS provider.". This has been amended to state "Unacknowledged messages redelivered due to system failure must have the JMSRedelivered message header field set, and the JMSXDeliveryCount incremented, by the JMS provider, as described in sections 3.4.7 "JMSRedelivered" and 3.5.11 "JMSXDeliveryCount"

11.5.6 "JMSXDeliveryCount" is the change log for this change.





[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-39] Make clientId optional when creating a durable 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.0ED, 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

Tags: ed20-added

 Description   

(There was a change of mind on this issue. Initially this feature was added for both JMS 1.1 unshared subscriptions as well as JMS 2.0 shared subscriptions but we changed our mind and in the end it was added for JMS 2.0 shared subscriptions only. This note was added retrospectively to make this issue easier to understand when reading it.)

This is a proposal to make clientId optional when creating a durable subscription

In JMS 1.1, a durable subscription is defined by the combination of clientId and subscriptionName. Section 6.11.1 of the Specification states:

Sessions with durable subscribers must always provide the same client
identifier. In addition, each client must specify a name that uniquely identifies
(within client identifier) each durable subscription it creates.

Whilst it is clear that a durable subscription needs to have a name to allow it to be identified, it is less clear why it needs to be identified by clientId. This is the only place in the JMS API where a connection must have clientId set.

This requirement to have clientId set causes complication for applications, especially in a Java EE application, where clientId must be set on the connection factory. This means that the connection factory can only be used to create a single instance, and if a connection pool is used it must be constrained to allow only a single instance.

It is therefore proposed that the use of clientId be made optional when creating a durable subscription. In this case, the subscription will be defined by the name of the subscription alone.

This change is not intended to change the existing restrictions stated in Section 6.11.1:

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



 Comments   
Comment by timlfox [ 05/Aug/11 ]

I don't understand how client id can be optional. The unique id of a durable subscription is effectively defined by a tuple (client_id, subscription_name).

This means there can be many different durable subscriptions with the same value of subscription_name but different values of client_id.

Client id normally maps to some kind of notion of user, so this allows each user to maintain their own namespace within which they don't have to worry about naming of durable subscriptions.

Removing client id would mean there is effectively one "global" namespace of durable subscriptions. This is not desirable IMHO.

Comment by Nigel Deakin [ 05/Aug/11 ]

If clientID was set then it would still be used (to maintain backwards compatibility). However this change would allow a durable subscription to be created for which its identifying "tuple" was (null,subscription_name).

Comment by Nigel Deakin [ 21/Dec/11 ]

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

The only changes are to comments, not to the API. The updated comments as follows:

On the Session interface the javadocs for the two createDurableSubscriber methods and the unsubscribe method have been rewritten as follows:

    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>TopicSubscriber</code>
     * on that durable subscription.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no <code>TopicSubscriber</code> associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a <code>TopicSubscriber</code> on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A durable subscription which has a <code>TopicSubscriber</code>
     * associated with it is described as being active.
     * A durable subscription which has no <code>TopicSubscriber</code>
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * <CODE>TopicSubscriber</CODE> for a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>TopicSunscriber</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * 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.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this subscription
     *
     * @exception JMSException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationException if an invalid topic is specified.
     *
     * @since 2.0
     */
    TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException;
    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>TopicSubscriber</code>
     * on that durable subscription, specifying a message
     * selector and whether messages published by its
     * own connection should be delivered to it.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no <code>TopicSubscriber</code> associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a <code>TopicSubscriber</code> on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A durable subscription which has a <code>TopicSubscriber</code>
     * associated with it is described as being active.
     * A durable subscription which has no <code>TopicSubscriber</code>
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * <CODE>TopicSubscriber</CODE> for a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>TopicSunscriber</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * 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.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this 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 noLocal if set, inhibits the delivery of messages published
     * by its own connection
     *
     * @exception JMSException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationException if an invalid topic is specified.
     * @exception InvalidSelectorException if the message selector is invalid.
     *
     * @since 2.0
     */
     TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;
    /** Unsubscribes a durable subscription that has been created by a client.
      *
      * <P>This method deletes the state being maintained on behalf of the
      * subscriber by its provider.
      * <p>
      * A durable subscription is identified by a name specified by the client
      * and by the client identifier if set. If the client identifier was set
      * when the durable subscription was created then a client which
      * subsequently wishes to use this method to
      * delete a durable subscription must use the same client identifier.
      *
      * <P>It is erroneous for a client to delete a durable subscription
      * while there is an active <CODE>MessageConsumer</CODE>
      * or <CODE>TopicSubscriber</CODE> for the
      * subscription, or while a consumed message is part of a pending
      * transaction or has not been acknowledged in the session.
      *
      * @param name the name used to identify this subscription
      *
      * @exception JMSException if the session fails to unsubscribe to the
      * durable subscription due to some internal error.
      * @exception InvalidDestinationException if an invalid subscription name
      * is specified.
      *
      * @since 1.1
      */
    void unsubscribe(String name) throws JMSException;
Comment by Nigel Deakin [ 21/Dec/11 ]

On the proposed MessagingContext interface the javadocs for the two createSyncDurableSubscriber methods, the two setMessageListener methods used to create durable subscriptions, the two setBatchMessageListener methods used to create durable subscriptions and the unsubscribe method have been rewritten as follows:

    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>SyncMessageConsumer</code>
     * on that durable subscription.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>SyncMessageConsumer</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>SyncMessageConsumer</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createSyncDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * 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.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this subscription
     *
     * @exception JMSRuntimeException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationRuntimeException if an invalid topic is specified.
     *
     */
    SyncMessageConsumer createSyncDurableSubscriber(Topic topic, String name);
    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>SyncMessageConsumer</code>
     * on that durable subscription, specifying a message selector and
     * whether messages published by its own connection should be delivered to it.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>SyncMessageConsumer</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>SyncMessageConsumer</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createSyncDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * 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.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this 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 noLocal if set, inhibits the delivery of messages published
     * by its own connection
     *
     * @exception JMSRuntimeException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationRuntimeException if an invalid topic is specified.
     * @exception InvalidSelectorRuntimeException if the message selector is invalid.
     *
     */
    SyncMessageConsumer createSyncDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal);
    /**
     * Creates a durable subscription with the specified name on the specified topic,
     * and creates a consumer on that durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * 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.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the durable subscription
     * @param listener - The listener to which the messages are to be delivered
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     */
void setMessageListener (Topic topic, String subscriptionName, MessageListener listener);
    /**
     * Creates a durable subscription with the specified name on the specified topic,
     * and creates a consumer on that durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>,
     * specifying a message selector and whether messages published by its
     * own connection should be delivered to it.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * 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.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the 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 NoLocal - If true, inhibit* subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * 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.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the 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 NoLocal - If true, inhibits the delivery of messages published by its own connection.
     * @param listener - The listener to which the messages are to be delivered
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     * @throws InvalidSelectorRuntimeException - If the message selector is invalid.
     */
    void setMessageListener(Topic topic, String subscriptionName, String messageSelector, boolean NoLocal, MessageListener listener);
   /**
     * Creates a durable subscription with the specified name on the specified topic,
     * and creates a consumer on that durable subscription
     * that will deliver messages in batches to the specified <code>BatchMessageListener</code>
     * with the specified maximum batch size and timeout.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * 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.
     * <p>
     * Messages will be delivered to the specified <code>BatchMessageListener</code>
     * in batches whose size is no greater than the specified maximum batch size.
     * The JMS provider may defer message
     * delivery until the specified batch timeout has expired in order to
     * assemble a batch of messages that is as large as possible but no greater
     * than the batch size.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the durable subscription
     * @param listener - The listener to which the messages are to be delivered
     * @param maxBatchSize - The maximum batch size that should be used. Must be greater than zero.
     * @param batchTimeout - The batch timeout in milliseconds. A value of zero means no
     * timeout is required The JMS provider may override the
     * specified timeout with a shorter value.
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     */
    void setBatchMessageListener(Topic topic, String subscriptionName, BatchMessageListener listener, int maxBatchSize, long batchTimeout);
    /**
     * Creates a durable subscription with the specified name on the specified topic,
     * using the specified message message selector,
     * and creates a consumer on that durable subscription
     * that will deliver messages in batches to the specified <code>BatchMessageListener</code>
     * with the specified maximum batch size and timeout.
     * This method can specify whether messages published by its own connection
     * should be delivered to the specified listener.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * 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.
     * <p>
     * Messages will be delivered to the specified <code>BatchMessageListener</code>
     * in batches whose size is no greater than the specified maximum batch size.
     * The JMS provider may defer message
     * delivery until the specified batch timeout has expired in order to
     * assemble a batch of messages that is as large as possible but no greater
     * than the batch size.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the 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 NoLocal - If true, inhibits the delivery of messages published by its own connection.
     * @param listener - The listener to which the messages are to be delivered
     * @param maxBatchSize - The maximum batch size that should be used. Must be greater than zero.
     * @param batchTimeout - The batch timeout in milliseconds. A value of zero means no
     * timeout is required The JMS provider may override the
     * specified timeout with a shorter value.
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     * @throws InvalidSelectorRuntimeException - If the message selector is invalid.
     */
    void setBatchMessageListener(Topic topic, String subscriptionName, String messageSelector, boolean NoLocal,
BatchMessageListener listener, int maxBatchSize, long batchTimeout);
    /** Unsubscribes a durable subscription that has been created by a client.
     *
     * <P>This method deletes the state being maintained on behalf of the
     * subscriber by its provider.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was created then a client which
     * subsequently wishes to use this method to
     * delete a durable subscription must use the same client identifier.
     *
     * <P>It is erroneous for a client to delete a durable subscription
     * while there is an active consumer on that subscription,
     * or while a consumed message is part of a pending
     * transaction or has not been acknowledged in the session.
     * <P>
     * If the active consumer is represented by a <CODE>SyncMessageConsumer</CODE> then calling
     * <CODE>close</CODE> on either that object or the <CODE>MessagingContext</CODE> used to create it
     * will render the consumer inactive and allow the subscription to be deleted.
     * <P>
     * If the active consumer was created by calling <code>setMessageListener</code> on the <CODE>MessagingContext</CODE>
     * then calling <CODE>close</CODE> on the <CODE>MessagingContext</CODE>
     * will render the consumer inactive and allow the subscription to be deleted.
     * <p>
     * If the active consumer is represented by a <code>MessageConsumer</code> or <code>TopicSubscriber</code> then calling
     * <code>close</code> on that object or on the <code>Session</code> or <code>Connection</code> used to create it
     * will render the consumer inactive and allow the subscription to be deleted.
     *
     * @param name the name used to identify this subscription
     *
     * @exception JMSRuntimeException if the session fails to unsubscribe to the
     * durable subscription due to some internal error.
     * @exception InvalidDestinationRuntimeException if an invalid subscription name
     * is specified.
     */
    void unsubscribe(String name);
Comment by Nigel Deakin [ 21/Dec/11 ]

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf
All changes are hightlighted. The changes made for this issue are as follows:

In JMS 2.0 it is no longer mandatory for the client identifier to be set when creating or activating a durable subscription. The following changes have been updated to reflect this change:

Section 4.3.2 "Client Identifier" has been changed to state that its use in identifying a durable subscription is optional.

Section 6.3 "Durable Subscription" has been amended by adding a cross-reference to Section 6.11.1 "Durable TopicSubscriber" at the end.

Section 6.11.1 "Durable TopicSubscriber" has been completely rewritten. This section was essentially a copy of the javadoc comment on the createDurableSubscriber methods and since those javadoc comments have been rewritten to make them clearer this section has been rewritten as well.

The only substantive change is to state that the use of client identifier in identifying a durable subscription is optional. Cross-references to Section 6.3 "Durable Subscription" and Section 4.3.2 "Client Identifier" have been added at the end.

Section 11.5.7. Durable subscriptions has been added, which is a change log.

Comment by Nigel Deakin [ 18/Jan/12 ]

Additional changes have been made to the javadoc comments for the following methods to clarify the case where the durable subscription already exists:

  • Session.createDurableSubscriber (2 methods)
  • Session.createDurableConsumer (2 methods, added for JMS_SPEC-51)
  • MessagingContext.createSyncDurableConsumer (2 methods)
  • MessagingContext.setMessageListener (only the 2 methods for durable subscriptions)
  • MessagingContext.setBatchMessageListener (only the 2 methods for durable subscriptions

Here's an example for Session.createDurableSubscriber:

This is the old comment:

     * If the durable subscription already exists then this method
     * creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.

This is the new comment:

     * If a durable subscription already exists with the same name 
     * and client identifier (if set) and the same topic and message selector 
     * then this method creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.

Note that the javadoc comment for these methods already states the following:

     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which 
     * subsequently wishes to create a <code>TopicSunscriber</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createDurableSubscriber</code> 
     * with the same name and client identifier (if used),
     * 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 updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

Comment by Nigel Deakin [ 26/Nov/12 ]

It has now been decided that changing the Session method createDurableSubscriber to make clientId optional for durable subscriptions breaks the http://java.net/projects/javaee-spec/pages/CompatibilityRequirements Backwards Compatibility Requirements for Java EE Specifications.

It will therefore remain mandatory to set clientId when creating a non-shared durable subscription using the following existing or new methods:

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

However setting clientId will be optional when creating a shared durable subscriptions using any of the following new methods:

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
Comment by Nigel Deakin [ 20/Mar/13 ]

Marking this issue as "resolved", with a resolution of "Won't fix"





[JMS_SPEC-34] Calling setJMSDeliveryMode or setJMSPriority on a javax.jms.Message before it is sent don't have any effect Created: 25/Jul/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.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:
Duplicate
duplicates JMS_SPEC-60 Obscurity setting special JMSHeaders Closed
Tags: ed20-added

 Description   

This issue relates to the following methods on javax.jms.Message:

setJMSPriority
setJMSDeliveryMode

Many novice developers think these methods can be used to set the priority and delivery mode of a message before it is sent. In fact these methods have no effect: the only way to set priority and delivery mode is by using methods on javax.jms.MessageProducer.

This a common cause of confusion to developers. Can we either deprecate these methods or else change them so that actually do something?



 Comments   
Comment by Nigel Deakin [ 25/Jul/11 ]

The same issue applies to the following methods on javax.jms.Message as well:

setJMSDeliveryMode
setJMSExpiration
setJMSPriority
setJMSMessageID
setJMSTimestamp
setJMSRedelivered
setJMSDeliveryTime (proposed in JMS_SPEC-44)

If any of these methods are called on a message before it is sent they have no effect. The javadoc comment on each of these methods states "This method can be used to change the value for a message that has been received.", despite it being far from obvious why an application might want to do this.

Comment by Nigel Deakin [ 22/Nov/11 ]

These methods are needed because a JMS provider is required to be capable of sending messages whose implementation is not its own. This would typically occur if an application received a message from provider 1 and then sent the same message using provider 2.

When this happens, provider 2 is responsible for setting the JMSDestination, JMSDeliveryMode, JMSExpiration, JMSPriority, JMSMessageID and JMSTimestamp header field values on the message. The only way that provider 2 can set these values on a message implemented by provider 1 is using these public setter methods.

Here's an example: if the application sends a message with a priority of 3 then it does this either by setting the priority on the MessageProducer by calling its setPriority method prior to sending the message, or by setting the priority on the individual message send by calling the MessageProducer method send(destination, message, deliveryMode, priority, timeToLive). The provider is responsible for ensuring that, after the message has been sent, the message's JMSPriority header holds the appropriate priority so that the line of code following the call to send could obtain this value. (See section 3.4.10 of the JMS 1.1 spec).

// message1 was obtained from provider 1
// we're sending it using provider 2
messageConsumer.setPriority(3);
messageConsumer.send(message1);
int priority = message1.getJMSPriority(); // should return 3

In the above example, provider 2's send method needs to be able to set the JMSPriority header on message1, which was implemented by provider 1, so it needs a standard, public API to do this.

We therefore cannot remove these methods. It would, however, be possible to clarify the javadoc comments to make it clear that these methods cannot be used by the sending application to control the message priority, delivery mode. We will improve the wording in JMS 2.0.

I suspect that some people who fall into the trap of misunderstanding these methods simply guess the method name, see that it gets accepted by their IDE, and use it. There's not much we can do about this (though since most IDEs can display javadoc comments clarifying the javadoc may help).

Comment by koen.serneels [ 23/Nov/11 ]

My opinion is still that it should always be the goal of a good API to minimize the percentage of obscurity.
By offering methods in a public API that do nothing, you are creating confusion from the start.

Can't there be a Message SPI or some other way that the provider can set the priority before sending? Imho this is just bad design which leads to errornous code and time consuming debegugging to find out "why this setter method doesn't work" ?.

Comment by Nigel Deakin [ 23/Nov/11 ]

@koen.serneels: You're perfectly right, the existence of these methods is misleading and with hindsight the people who designed this API should have done something different. But removing them would be a non-compatible change so I think we're stuck with them.

Comment by Nigel Deakin [ 22/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

The javadoc comments for the following methods on Message have been updated:

setJMSDeliveryMode
setJMSExpiration
setJMSPriority
setJMSMessageID
setJMSTimestamp
setJMSRedelivered
setJMSDeliveryTime (proposed in JMS_SPEC-44)

Currently the javadoc comments for these methods simply states:

    /** Sets the message's [name of property] value
      *  
      * <P>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.

These have been changed as follows:

   /** Sets the message's [name of property] 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 [describe feature] 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.

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:

Section 3.4.1 "How Message Header Values Are Set" has been updated.

Section 11.5.8. "Clarification: message headers that are intended to be set by the JMS provder" is the change log for this issue.

Comment by Nigel Deakin [ 23/Feb/12 ]

Clarified the explanation in the second comment .





[JMS_SPEC-49] Improve specification of ExceptionListener Created: 16/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.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

Tags: ed20-added

 Description   

The use of a ExceptionListener is described in the JMS 1.1 specification in section 4.3.8 "ExceptionListener":

If a JMS provider detects a problem with a connection, it will inform the connection's ExceptionListener, if one has been registered. To retrieve an ExceptionListener, the JMS provider calls the connection's getExceptionListerer()
method. This method returns the ExceptionListener for the connection. If no ExceptionListener is registered, the value null is returned. The connection can then use the listener by calling the listener 's onException() method, passing it a JMSException describing the problem.

This allows a client to be asynchronously notified of a problem. Some connections only consume messages, so they would have no other way to learn their connection has failed.

A Connection serializes execution of its ExceptionListener.

A JMS provider should attempt to resolve connection problems itself prior to notifying the client of them.

The exceptions delivered to ExceptionListener are those that have no other place to be reported. If an exception is thrown on a JMS call it, by definition, must not be delivered to an ExceptionListener (in other words, ExceptionListener is not for the purpose of monitoring all exceptions thrown by a connection).

Despite this, there have been a number of questions about the use of an ExceptionListener. These questions are listed below, together with proposed answers. It is proposed that the answers to these questions be incorporated into the specification.

Question 1: When Connection.stop() or Connection.close() is called, must these methods wait until any active calls to ExceptionListeners for that connection have returned, in the same way that they must wait until any active call to MessageListeners have returned?

Proposed answer: No.

Question 2: Is there any restriction on the use of Connection.stop() or Connection.close() from an ExceptionListener?

Proposed answer: No.

Question 3: What does "a Connection serializes execution of its ExceptionListener" mean?

Proposed answer: This means that if a connection encounters multiple problems and therefore needs to call its ExceptionListener multiple times, then it will only invoke onMessage() from one thread at a time. Note however that if the same ExceptionListener is registered with different connections then it is undefined whether these connections could call onMessage() from different threads simultaneously.

Question 4: What is the effect of ExceptionListener.onException() being slow or blocking?

Proposed answer: This is undefined. There is no requirement that any other operation need block until ExceptionListener.onException() has return, apart from other calls to ExceptionListener.onException() for the same connection.



 Comments   
Comment by Nigel Deakin [ 16/Sep/11 ]

I've now written the following draft text:

Changes to section 4.3.8 "ExceptionListener":

After:

A Connection serializes execution of its ExceptionListener.

Insert:

This means that if a connection encounters multiple problems and therefore needs to call its ExceptionListener multiple times, then it will only invoke onMessage() from one thread at a time. Note however that if the same ExceptionListener is registered with multiple connections then it is undefined whether these connections could call onMessage() from different threads simultaneously.

At the end, insert:

There is no restriction on the use of the JMS API by the listener's onException method. However since that method will only be called when there is a serious problem with the connection, any attempt to use that connection may fail and cause exceptions.

New text in the javadoc for ExceptionListener:

There is no restriction on the use of the JMS API by the listener's onException method. However since that method will only be called when there is a serious problem with the connection, any attempt to use that connection may fail and cause exceptions.

A Connection serializes execution of its ExceptionListener. This means that if a connection encounters multiple problems and therefore needs to call its ExceptionListener multiple times, then it will only invoke onMessage from one thread at a time. Note however that if the same ExceptionListener is registered with multiple connections then it is undefined whether these connections could call onMessage from different threads simultaneously.

New text in the javadoc for Connection.stop():

For the avoidance of doubt, if an exception listener for this connection is running when stop is invoked, there is no requirement for the exception listener to return before the stop method returns.

New text in the javadoc for Connection.close():

For the avoidance of doubt, if an exception listener for this connection is running when stop is invoked, there is no requirement for the exception listener to return before the stop method returns.

Comment by Nigel Deakin [ 03/Jan/12 ]

I've now updated the javadocs and the draft spec with these clarifications (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 updated javadocs for Connection.stop, Connection.close, Session.close, MessagingContext.stop, MessagingContext.close)

  • The javadoc comments for the stop and close methods on the Connection interface have been amended to clarify that, if an exception listener for the connection is running when stop or close are invoked, there is no requirement for the stop or close call to wait until the exception listener has returned before it may return.
  • Similarly, the javadoc comment for the close method on the Session interface has been amended to clarify that, if an exception listener for the session's connection is running when close is invoked, there is no requirement for the close call to wait until the exception listener has returned before it may return.
  • The javadoc comments for the stop and close methods on the MessagingContext interface have been amended to clarify that, if an exception listener for the MessagingContext's connection is running when stop or close are invoked, there is no requirement for the stop or close call to wait until the exception listener has returned before it may return.

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 to section 4.3.8 "Exception Listener":

  • The existing text which states that a connection "serializes execution of its ExceptionListener" has been extended to explain what this means.
  • A note has been added to state that there are no restrictions on the use of the JMS API by the listener's onException method.

In addition a new section 11.5.11 has been added which is the change log for this issue.





[JMS_SPEC-48] Specify that connection.stop() or close() may not be called from a MessageListener Created: 16/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0ED, 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

Tags: ed20-added

 Description   

Possible deadlock when calling connection.stop()

If the javax.jms.MessageListener method onMessage calls Connection.stop() then, according to the JMS 1.1 specification, deadlock may result.

Section 4.3.4 "Pausing Delivery of Incoming Messages" states:

If MessageListeners are running when stop is invoked, stop must wait until all of them have returned before it may return. While these MessageListeners are completing, they must have the full services of the connection available to them.

This means that if a MessageListener calls Connection.stop() then the call to stop() will block forever, waiting for the onMessage() method which is calling it to return.

To avoid the possibility of applications causing deadlock, the JMS specification needs to be clarified to state that a MessageListener must not call connection.stop().

The section above states that a MessageListener must have "the full services of the connection" available to it. The meaning of the term "full services" is not defined, but it needs to be made clear that this does not include the ability to call Connection.stop().

Possible deadlock when calling connection.close()

A similar issue exists for Connection.close(). If the javax.jms.MessageListener method onMessage calls Connection.close() then, according to the JMS 1.1 specification, deadlock may result.

Section 4.3.5 "Closing a connection" states:

If one or more of the connection's session's message listeners is processing a message at the point when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider.

When connection close is invoked it should not return until message processing has been shut down in an orderly fashion. This means that all message listeners that may have been running have returned, and that all pending receives have returned.

Again, this means that if a MessageListener calls Connection.close() then the call to close() will block forever, waiting for the onMessage() method which is calling it to return.

To avoid the possibility of applications causing deadlock, the JMS specification needs similarly to be clarified to state that a MessageListener must not call connection.close().

The section above states that a MessageListener must have "all the facilities of the connection" available to it. The meaning of the term "all the facilities" is again not defined, but it needs to be made clear that those does not include the ability to call Connection.close().

Enforcement

JMS provider should be required to throw a javax.jms.IllegalStateException if Connection.stop() or Connection.close() is called from the onMessage method of a javax.jms.MessageListener.



 Comments   
Comment by Nigel Deakin [ 16/Sep/11 ]

I've now drafted the spec changes as follows:

Section 4.3.4 "Pausing Delivery of Incoming Messages"

After:

If MessageListeners are running when stop is invoked, stop must wait until all of them have returned before it may return. While these MessageListeners are completing, they must have the full services of the connection available to
them.

Append:

However a MessageListeners must not call the connection's stop() method as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.stop() is called from the onMessage method of a javax.jms.MessageListener.

Section 4.3.5 "Closing a Connection"

After:

If one or more of the connection’s session’s message listeners is processing a message at the point when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider.

Append:

However a message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.close() is called from the onMessage method of a javax.jms.MessageListener.

Section 4.4.1 "Closing a Session"

After:

When session close is invoked, it should not return until its message processing has been shut down in an orderly fashion. This means that none of its message listeners are running, and that if there is a pending receive, it has
returned with either null or a message.

Append:

A message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Session.stop() is called from the onMessage method of a javax.jms.MessageListener.

Javadoc for Connection.stop()

After:

If message listeners are running when stop is invoked, the stop call must wait until all of them have returned before it may return. While these message listeners are completing, they must have the full services of the connection available to them.

Insert:

However a message listener must not call the connection's stop() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.stop() is called from the onMessage method of a javax.jms.MessageListener.

Javadoc for Connection.close()

After:

When this method is invoked, it should not return until message processing has been shut down in an orderly fashion. This means that all message listeners that may have been running have returned, and that all pending receives have returned. A close terminates all pending message receives on the connection's sessions' consumers. The receives may return with a message or with null, depending on whether there was a message available at the time of the close. If one or more of the connection's sessions' message listeners is processing a message at the time when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider.

Append:

However a message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.close() is called from the onMessage method of a javax.jms.MessageListener.

Javadoc for Session.close()

After:

This call will block until a receive call or message listener in progress has completed. A blocked message consumer receive call returns null when this session is closed.

Append:

A message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Session.close() is called from the onMessage method of a javax.jms.MessageListener.

Comment by Nigel Deakin [ 04/Jan/12 ]

I've now updated the javadocs and the draft spec
(these changes are additive, so those docs include other changes).

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)

Section 4.3.4 "Pausing Delivery of Incoming Messages"

A message listener must not attempt to stop its own connection as this would lead to deadlock. The JMS provider must detect this and throw a javax.jms.IllegalStateException.

Section 4.3.5 "Closing a Connection"

A message listener must not attempt to close its own connection as this would lead to deadlock. The JMS provider must detect this and throw a javax.jms.IllegalStateException.

Section 4.4.1 "Closing a Session"

A message listener must not attempt to close its own session as this would lead to deadlock. The JMS provider must detect this and throw a javax.jms.IllegalStateException.

Section 11.5.12 "Clarification of use of stop or close from a message listener (JMS_SPEC-48)"

This is the change log for this issue.

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

New javadoc comment on Connection.stop():

      * A message listener must not attempt to stop its own connection as this 
      * would lead to deadlock. The JMS provider must detect this and throw a 
      * javax.jms.IllegalStateException.

New javadoc comment on Connection.close():

      * A message listener must not attempt to close its own connection as this 
      * would lead to deadlock. The JMS provider must detect this and throw a 
      * javax.jms.IllegalStateException.

New javadoc comment on Session.close():

      * A message listener must not attempt to close its own session as this 
      * would lead to deadlock. The JMS provider must detect this and throw a 
      * javax.jms.IllegalStateException.

New javadoc comment on MessagingContext.stop():

     * A message listener must not attempt to stop its own MessagingContext as this 
     * would lead to deadlock. The JMS provider must detect this and throw a 
     * javax.jms.IllegalStateRuntimeException.

New javadoc comment on MessagingContext.close():

     * A message listener must not attempt to close its own MessagingContext as this 
     * would lead to deadlock. The JMS provider must detect this and throw a 
     * javax.jms.IllegalStateRuntimeException.
Comment by Nigel Deakin [ 05/Dec/12 ]

I'd like to reopen this issue. Since the changes described above was added to the spec it has been pointed out that a similar issue applies with the close() methods on MessageConsumer and JMSConsumer.

I would therefore like to propose that we amend the definition of MessageConsumer.close() and JMSConsumer.close() to match the other methods listed here.

Comment by Nigel Deakin [ 05/Dec/12 ]

I've now drafted the necessary API changes:

New javadoc comment on MessageConsumer.close():

	 * This call blocks until a {@code receive} or message listener in progress
	 * has completed. A blocked message consumer {@code receive} call returns
	 * null when this message consumer is closed.
	 * <p>
	 * A {@code MessageListener} must not attempt to close its own
	 * {@code MessageConsumer} as this would lead to deadlock. The JMS provider
	 * must detect this and throw a {@code IllegalStateException}.
	 * 
	 * @exception IllegalStateException
	 *                this method has been called by a {@code MessageListener}
	 *                on its own {@code MessageConsumer}

Note that the words "this call blocks until a... message listener in progress has completed" are not new and were in JMS 1.1.

New javadoc comment on JMSConsumer.close()

	 * This call blocks until a {@code receive} or message listener in progress has completed.
	 * A blocked {@code receive} call returns null when
	 * this {@code JMSConsumer} is closed.
	 * <p>
	 * A {@code MessageListener} must not attempt to close its own
	 * {@code JMSConsumer} as this would lead to deadlock. The JMS provider
	 * must detect this and throw a {@code IllegalStateRuntimeException}.
	 * 
 	 * @exception IllegalStateRuntimeException
	 *                this method has been called by a {@code MessageListener}
	 *                on its own {@code JMSConsumer}

In addition I've added a new section 4.5.3 "Closing a MessageConsumer"

When the MessageConsumer's close method is invoked it should not return until its message processing has been shut down in an orderly fashion. This means that none of its message listeners are running, and that if there is a pending receive, it has returned with either null or a message.

A message listener must not attempt to close its own MessageConsumer as this would lead to deadlock. The JMS provider must detect this and throw a javax.jms.IllegalStateException.

Comment by Nigel Deakin [ 12/Feb/13 ]

The JMS EG has agreed to revise the behaviour of consumer close to:

  • Allow consumer.close to be called from within a message listener
  • Allowing a consumer to be closed from any thread, even if it isn't the thread of control

The main changes are listed below.

New Javadoc for MessageConsumer.close

/**
 * Closes the message consumer.
 * <p>
 * Since a provider may allocate some resources on behalf of a
 * {@code MessageConsumer} outside the Java virtual machine, clients should
 * close them when they are not needed. Relying on garbage collection to
 * eventually reclaim these resources may not be timely enough.
 * <P>
 * This call will block until a {@code receive} call in progress on this
 * consumer has completed. A blocked {@code receive} call returns null when
 * this message consumer is closed.
 * <p>
 * If this method is called whilst a message listener is in progress in
 * another thread then it will block until the message listener has
 * completed.
 * <p>
 * This method may be called from a message listener's {@code onMessage}
 * method on its own consumer. After this method returns the
 * {@code onMessage} method will be allowed to complete normally. 
 * <p>
 * This method is the only {@code MessageConsumer} method that can be called
 * concurrently.
 * 
 * @exception JMSException
 *                if the JMS provider fails to close the consumer due to
 *                some internal error.
 */

Spec changes: new section 8.8. Closing a consumer

8.8. Closing a consumer

The close methods on MessageConsumer, JMSConsumer, QueueReceiver and TopicSubscriber allow a consumer to be closed separately from the session or connection used to create it.

Closing a consumer terminates the delivery of messages to the consumer.

close is the only method on a consumer that may be invoked from a thread of control separate from the one which is currently controlling the session.

If close is called in one thread whilst another thread is calling receive on the same consumer then the call to close must block until the receive call has completed. A blocked receive call returns null when the consumer is closed.

If close is called in one thread whilst a message listener for this consumer is in progress in another thread then the call to close must block until the message listener has completed.

If close is called from a message listener's onMessage method on its own consumer then after this method returns the onMessage method must be allowed to complete normally.

Closing a consumer has no effect on the acknowledgement of messages delivered to the application, or on any transaction in progress. This is because message acknowledgement and transactions are functions of the session, not the consumer.

  • If the session mode is AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE then any messages delivered to the application will be automatically acknowledged as normal.
  • If the session mode is CLIENT_ACKNOWLEDGE then any messages delivered to the application may be acknowledged by calling acknowledge in the normal way. It makes no difference whether this occurs before or after the consumer is closed.
  • If the session is transacted then the application may commit or rollback the transaction as normal. It makes no difference whether this occurs before or after the consumer is closed.
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-50] Clarify that JMS providers must implement both P2P and Pub-Sub Created: 19/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.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

Tags: ed20-added

 Description   

In the JMS Specification 1.1, Chapter 1.3 "What Is Required by JMS" says:

Providers of JMS point-to-point functionality are not required to provide publish/subscribe functionality and vice versa.

However Java EE 6 in Section EE.2.7.8 "Java™ Message Service (JMS)" says

The Java Message Service is a standard API for messaging that supports reliable point-to-point messaging as well as the publish-subscribe model. This specification requires a JMS provider that implements both point-to-point messaging as well as publish-subscribe messaging.

It is proposed to change the JMS specification to bring it in to line with Java EE, and make it mandatory for a standalone JMS provider to implement both point-to-point messaging (Queues) and publish-subscribe messaging (Topics).



 Comments   
Comment by Nigel Deakin [ 16/Sep/11 ]

This has been agreed in principle by the JSR 343 Expert group and will be in the JMS 2.0 Early Draft.

Comment by Nigel Deakin [ 03/Jan/12 ]

I've now updated the draft spec to reflect this decision (these changes are additive, so those docs include other changes).

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 only sections affected are section 1.3 "What Is Required by JMS" and section 11.5.10 which is the change log for this issue.)





[JMS_SPEC-20] New "Not Before" Header Created: 24/May/11  Updated: 07/Nov/11  Resolved: 07/Nov/11

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

Type: New Feature Priority: Major
Reporter: fribeiro Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

It would be nice to be able to filter out messages that shouldn't be consumed before a timestamp provided in a standard "not before" header.

I've heard before that at least one implementation provides a custom header for this use case, but can't find the reference now.



 Comments   
Comment by clebertsuconic [ 24/May/11 ]

+1 Most providers have scheduled delivery as part of their implementation. I even thought this was part of the API already.

There should be a standard way IMO through the API.

Comment by Nigel Deakin [ 07/Nov/11 ]

The JSR 343 Expert group has proposed JMS_SPEC-44 which is effectively a duplicate of this issue. I will therefore mark this issue as resolved with a resolution of "Duplicate.

Please look at JMS_SPEC-44 and add any comments you feel appropriate.





[JMS_SPEC-15] Queue Depth Created: 24/May/11  Updated: 09/Mar/12  Resolved: 09/Mar/12

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

Type: New Feature Priority: Major
Reporter: colincrist Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JMS_SPEC-18 Standard set of server JMX MBeans Open
duplicates JMS_SPEC-59 Basic metadata/management via JMS Open

 Description   

As a client I would like to get the current queue depth on a queue. All existing providers give this information via a custom API or JMX at present.



 Comments   
Comment by fribeiro [ 24/May/11 ]

Maybe we should revise whether the spec specifies the notifications that must be supported by implementations – this one should definitely be there.

Comment by rdohna [ 09/Dec/11 ]

JMS_SPEC-15 is a special case of JMS_SPEC-59

Comment by Nigel Deakin [ 09/Mar/12 ]

@fribeiro: I'm not sure what you mean by notifications here and how it relates to obtaining the queue depth (and I don't want to guess). Can you please log your proposal as a new JIRA issue?

Comment by Nigel Deakin [ 09/Mar/12 ]

I'm merging this proposal with two more general proposals:

JMS_SPEC-59 - which covers general non-JMX metadata queries
JMS_SPEC-18 - which covers general JMX facilities

I'm going to close this issue as a duplicate of those. Feel free to contribute comments to those issues.





[JMS_SPEC-12] Message producer confirms aka async message production. Created: 23/May/11  Updated: 05/Mar/12  Resolved: 05/Mar/12

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

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

Issue Links:
Duplicate
duplicates JMS_SPEC-43 New API to send a message with async ... Resolved

 Description   

The synchronous 1.1 JMS API has an impact on how a single thread can produce messages with a session. There is too much waiting around for a reply from the server.

As a JMS client I would like to send a message on a non-transacted session with persistent delivery and receive asynchronous confirmation that it is stable via a callback. The session can then interact with the server in a more efficient manner.

RabbitMQ has a good write up of the functionality http://www.rabbitmq.com/blog/2011/02/10/introducing-publisher-confirms.
29West and Tervela have similar capability.
No doubt some JMS implementations have similar capabilities using non-JMS APIs.



 Comments   
Comment by timlfox [ 08/Jun/11 ]

+1 on this feature.

HornetQ was a pioneer with this - it's definitely a must for high throughput reliable message sending.

http://docs.jboss.org/hornetq/2.2.2.Final/user-manual/en/html/send-guarantees.html#asynchronous-send-acknowledgements

Comment by bsnyder [ 10/Jun/11 ]

Agreed, this is one area where there is a hole in the JMS 1.x spec.

Comment by rdohna [ 14/Jun/11 ]

I can see that there are some very-high-throughput use cases for this feature, but you'd need to implement your own two-phase commit, wouldn't you? It's a lot of code every client would have to re-implement... and it's easy to get it wrong and extremely difficult to test. It's quite a chimaera between transactional and non-transactional, isn't it?

I think we should either find a solution that's easier to work with, or choose to leave it out of the standard; it may have to be optimised for every JMS implementation anyway.

Comment by colincrist [ 15/Jun/11 ]

Persistent messaging does not imply container managed transactions. In the classic J2EE world the way to do persistent messaging and database co-ordination is via XA. This is fine for many use cases but I have found JMS used a great deal without a J2EE container and XA is not the only way to avoid data loss although it does require a bit of coding to co-ordinate

If say on some thread(s) messages are sent whilst on another the stability confirms are received sometime later then the application can update its store that the message (say an order) has indeed been sent successfully and can also do this in batch, keeping the disk I/O under control. This approach leads to a flurry of application generated duplicate messages on recovery as the application has to send messages it has not seen stability confirms for but this is the price you pay for scalability. On the plus side there is far less waiting around to co-ordinate disk writes via XA so you get a hugh increase in throughput, 10s-100s of times faster is not uncommon.

The implementation of this part of the API is up to the provider and its performance would be another differentiator between products.

Comment by rdohna [ 16/Jun/11 ]

NON_PERSISTENT means at-most-once message delivery. PERSISTENT currently (as of JMS 1.1) means once-and-only-once message delivery. I understand that this issue requests something else, as it doesn't want to pay the price for the transaction overhead, but still wants guaranteed delivery.

This means that you'd have to mark the reason for the message as "in progress" before you send the message. When you receive an ack, you'd mark that status as "done". This as a manual two-phase commit, isn't it?

Now whenever the sender or the receiver fails, there are two options: If the receiver is idempotent, you can resend all "in progress" messages... that's a new at-least-once message delivery and not yet supported by JMS... there may be use cases for this.

But if you still require full once-and-only-once guarantee, there has to be some resolution mechanism to re-sync the status of the sender and the receiver. Distributed transactions have such mechanisms, but that's expensive... and I can see no way around that.

If JMS 2.0 defines a at-least-once delivery guarantee, I'd prefer not to have every client to repeat that code, but to hide it somehow at a lower layer. But I don't have any good ideas, yet.

Comment by abien [ 18/Jun/11 ]

+1 for callback. But why just with persistent messages? Could be also interesting for transient messages.

Comment by Nigel Deakin [ 05/Mar/12 ]

This requirement appears to have been satisfied by JMS_SPEC-43, which was included in the JMS 2.0 Early Draft. Please review that draft and provide any comments.

That other issue appears to be a duplicate of this one. Given that the other issue contains details of the proposed changes I will close this issue as being a duplicate. Feel free to make comments on the other issue, or directly to users@jms-spec.java.net.





[JMS_SPEC-63] Introduce concept of platform default JMS connection factory in Java EE Created: 04/Dec/11  Updated: 20/Mar/13  Resolved: 23/Aug/12

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

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

Issue Links:
Dependency
depends on JAVAEE_SPEC-2 Define platform default JMS connectio... Resolved
Tags: jms20-jsr342-added

 Description   

In a Java EE environment a JMS provider is mandatory present and can be used without the user having to configure or setup anything.

Some implementations (e.g. JBoss AS), provide by default a JMS connection factory for this platform provided JMS provider (java:/ConnectionFactory and java:JmsXA), yet in other implementations (e.g. GlassFish) users have to create a connection factory themselves.

I would like to propose to formally introduce the concept of a platform default JMS connection factory and make this available under some portable JNDI name (e.g. java:/JmsConnectionFactory). The exact configuration of this factory should be an implementation detail, but the spirit of the specification should be that it must not be purposely crippled and should be principally intended for production use.

Besides shielding users from having to create a connection factory, an additional benefit might be that other platform JMS facilities that otherwise would need an explicit reference to a connection factory, could default to this standard connection factory.

E.g. from http://java.net/downloads/jms-spec/JMS2.0Devoxx2011.pdf slide 23:

@Inject 
@JMSConnection(lookup="jms/connFactory") 
@JMSDestination(lookup="jms/inboundQueue") 
MessageProducer producer;

could become:

@Inject 
@JMSDestination(lookup="jms/inboundQueue") 
MessageProducer producer; // defaults to java:/JmsConnectionFactory

etc.



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

I think this is a good idea, which I'll raise with the JSR 343 expert group. This might need to be defined in the Java EE platform spec rather than the JMS spec. I'll investigate.

Comment by Nigel Deakin [ 19/Jan/12 ]

I have logged this in the Java EE issue tracker as JAVAEE_SPEC-2

Comment by Nigel Deakin [ 23/Aug/12 ]

This has now been included in the Java EE 7 specification. A new section EE 5.19 "Default JMS COnnection Factory" states:

The Java EE Platform requires that a Java EE Product Provider provide a JMS provider in the operational environment (see Section EE.2.7.8, "Java™ Message Service (JMS)") . The Java EE Product Provider must also provide a preconfigured, JMS ConnectionFactory for use by the application in accessing this JMS provider.

The Java EE Product Provider must make the default JMS connection factory accessible to the application under the JNDI name java:comp/defaultJMSConnectionFactory.

The Application Component Provider or Deployer may explicitly bind a JMS ConnectionFactory resource reference to the default connection factory using the lookup element of the Resource annotation or the lookup-name element of the resource-ref deployment descriptor element. For example,

@Resource(name="myJMSCF", lookup="java:comp/defaultJMSConnectionFactory") 
ConnectionFactory myJMScf;

In the absence of such a binding for a JMS connection factory resource reference, the reference will map to a JMS connection factory for the product's JMS provider.

For example, the following will map to a preconfigured connection factory for the product's default JMS provider:

@Resource(name="myJMSCF")
ConnectionFactory myJMScf;




[JMS_SPEC-62] Define standard way to create JMS Destination objects from within a Java EE application Created: 23/Nov/11  Updated: 24/Feb/12  Resolved: 24/Feb/12

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

Type: New Feature Priority: Major
Reporter: arjan tijms Assignee: Unassigned
Resolution: Invalid Votes: 2
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: destination, javaee

 Description   

The JMS 1.1 spec states in section 2.3 that JMS Destinations (Queue and Topic) are administered objects for the following reason:

It is also expected there will be major differences in how a provider's system is installed and administered. If JMS clients are to be portable, they must be isolated from these proprietary aspects of a provider.

In practice however, there is often only very little information needed to create a basic Destination that is suitable for a lot of use-cases and there aren't really any major differences there. Especially if such Destinations are completely used internally in the application, they don't necessarily need to be administered objects. Many Java EE servers do make it possible to define Destinations from within the application, but every implementation has a different way to do this. This hurts portability.

For instance;

JBoss AS 6.x

*-hornetq-jms.xml
<configuration xmlns="urn:hornetq"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"
>    
    <queue name="myQueue">
        <entry name="/queue/myQueue" />
    </queue>
</configuration>

Glassfish 3.1.x

META-INF/glassfish-resources.xml
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" 
    "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <admin-object-resource res-adapter="jmsra" res-type="javax.jms.Queue" jndi-name="java:app/myQueue" >        
        <property name="Name" value="myQueue"/>
    </admin-object-resource>
</resources>

As can be seen in these two examples, all that the user needs to declare is a name and whether a queue or topic is required.

I would like to propose to define a standard way to define Destinations from within a Java EE application, analogous to how JDBC datasources can be defined via a DataSourceDefinition annotation and a corresponding <data-source> element in application.xml.



 Comments   
Comment by arjan tijms [ 04/Dec/11 ]

Slide 29 of http://java.net/downloads/jms-spec/JMS2.0Devoxx2011.pdf mentions exactly this:

JSR 342 (Java EE 7) will define new annotations:

@JMSConnectionFactoryDefinition( 
    name="java:app/MyJMSFactory", 
    resourceType="javax.jms.QueueConnectionFactory", 
    clientId="foo",
    resourceAdapter="jmsra", 
    initialPoolSize=5, 
    maxPoolSize=15
)
@JMSDestinationDefinition( 
    name="java:app/orderQueue", 
    resourceType="javax.jms.Queue", 
    resourceAdapter="jmsra", 
    destinationName="orderQueue"
)
Comment by Nigel Deakin [ 08/Dec/11 ]

As mentioned in those Devoxx slides, the Java EE 7 platform expert group is planning to include a feature similar to this. Please contact the Java EE 7 expert group for more information. http://javaee-spec.java.net

This is a platform issue and won't be addressed in the JMS spec.

Comment by Nigel Deakin [ 24/Feb/12 ]

Please see section EE.5.17.5 "JMS Destination Definition" of the proposed Java EE 7 specification (available via http://javaee-spec.java.net). This states

An application may define a JMS Destination resource. A JMS Destination resource is a JMS Queue or Topic.

The JMS {{Destination}}resource may be defined in any of the JNDI namespaces described in Section EE.5.2.2, “Application Component Environment Namespaces”.

A JMS Destination resource may be defined in a web module, EJB module, application client module, or application deployment descriptor using the jms-destination element.

For example:

<jms-destination>
    <description>Sample JMS Destination definition</description>
    <name>java:app/MyJMSDestination</name>
    <class-name>javax.jms.Queue</class-name>
    <resource-adapter-name>myJMSRA</resource-adapter-name>
    <resource-name>myQueue1</resource-name>
    <property>
      <name>Property1</name>
      <value>10</value>
    </property>
    <property>
      <name>Property2</name>
      <value>20</value>
    </property>
    </jms-destination>

A JMS Destination resource may also be defined using the JMSDestinationDefinition annotation on a container-managed class, such as a servlet or enterprise bean class.

For example:

@JMSDestinationDefinition(
    name="java:app/MyJMSQueue",
    className="javax.jms.Queue",
    resourceName="myQueue1")

The JMSDestinationDefinition annotation can be overridden by a deployment descriptor when the application is deployed.)

Once defined, a JMS Destination resource may be referenced by a component using the resource-ref deployment descriptor element or the Resource annotation. For example, the above Destination could be referenced as follows:

@Stateless
public class MySessionBean {
    @Resource(lookup = "java:app/MyJMSQueue")
    Queue myQueue;
    ...
}

The following JMSDestinationDefinition annotation elements (and corresponding XML deployment descriptor elements) are considered to specify an address for a JMS Destination resource: resourceAdapterName, resourceName.

Comment by Nigel Deakin [ 24/Feb/12 ]

I've marked this as resolved, with a resolution of "invalid". This doesn't mean the suggestion was invalid, of course, but that the request applied to a different specification. Comments and feedback remain welcome.





[JMS_SPEC-53] Make Connection and other interfaces implement AutoCloseable Created: 29/Sep/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.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-169 Make Connection and other interfaces ... Closed
Tags: ed20-added

 Description   

This is a proposal to change all the JMS interfaces that currently implement a close() method to implement the java.lang.AutoCloseable interface?

This would affect Connection, Session, MessageConsumer, MessageProducer, QueueBrowser.

This is a new feature of Java SE 7 which makes it easier to write code which closes a resource after use.

There's a nice explanation here:
http://www.javacodegeeks.com/2011/07/java-7-try-with-resources-explained.html]

Briefly, it allows you to write code such as:

try { 
   Connection conn = connectionFactory.createConnection();
   Session sess = conn.createSession(false,Session.AUTO_ACKNOWLEDGE;
   MessageProducer producer = seession.createProducer(dest);
}{
   Message mess = sess.createTextMessage("hello");
   producer.send(mess);
} catch(JMSException e){
  // exception handling
}

When this code is executed, the close() methods on the connection, session and producer are always called after use.

  • There's no need to call close() on any of the objects that are created.
  • There's no need to provide a finally block containing the calls to close().
  • Objects are closed in the reverse order in which they were created.
  • There's no need to guard against calling close() on a null value.
  • There's no need to use a nested try/catch block within the finally block to catch exceptions thrown by close()
  • If the try() block throws an exception, and a subsequent call to close() throws a second exception as a consequence, then it is the first exception, not the second exception, that is passed to the catch block. So you only see the exception that really matters. Any suppressed exceptions can still be accessed from the thrown exception if needed.

This change would be of benefit to both Java SE and Java EE applications. The only drawback I can think of is that it would introduce a dependency on Java SE 7. This isn't an issue for Java EE 7 applications since these are already dependent on Java SE 7. But it would force Java SE applications to use Java SE 7. However by the time JMS 2.0 is released, in a year from now, Java 7 will be pretty widespread so this might not be a problem.



 Comments   
Comment by Nigel Deakin [ 16/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
(One-line changes to Connection, Session, MessageProducer, MessageConsumer and QueueBrowser)

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 4.3.5 "Closing a Connection", 4.4.1 "Closing a Session", the example in section 9.1.3. Creating a Connection", and, in the changelog, section 11.5.3 "Automatically closing a connection or session")

I've now made Connection, Session, MessageProducer, MessageConsumer and QueueBrowser all extend AutoCloseable. (Note that MessagingContext, part of the proposed simplified API, already extends AutoCloseable)

(This updates the previous version of this comment which only referred to changes to Connection).

Comment by Nigel Deakin [ 05/Feb/12 ]

I've also changed javax.jms.SyncMessageConsumer to extend AutoCloseable, for consistency with MessageConsumer. API and javadocs updated.





[JMS_SPEC-55] Define a standard way to configure the connection factory used by a JMS MDB to consume messages Created: 07/Nov/11  Updated: 20/Mar/13  Resolved: 07/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 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 CONNECTOR_SPEC-4 Clarify whether the ResourceAdapter.e... Resolved
blocks MQ-250 Implement JMSRA activation properties... Closed
Related
is related to JMS_SPEC-54 Define a standard way to configure th... Resolved
Tags: jms20-jsr345, pd20-added

 Description   

This is a request for the EJB specification to define a standard way to configure the connection factory used by a MDB to consume messages.

Currently there is no standard way to do this, and vendors differ in the way in which connection information is specified in a MDB. Some vendors support an activation property connectionFactoryJndiName but this is not defined in the EJB 3.1 (or the JCA 1.6) specifications and support for it is not universal. In fact some vendors expect connection information to be specified directly using non-standard activation properties rather than via a connection factory.

This limits the portability of applications between different JMS providers, resource adapters and application servers. It will also hinder the automatic provisioning of JMS resources in a PaaS environment which is a goal of Java EE 7.

Two alternatives are proposed:

1. Define a mandatory activation property connectionFactoryJndiName

This would make it mandatory for application servers to support the activation property connectionFactoryJndiName. This would essentially standardise what some vendors support already.

This could be specified in ejb-jar.xml as follows:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>MyMDB</ejb-name>
      <activation-config>          
         <activation-config-property>
            <activation-config-property-name>connectionFactoryJndiName</activation-config-property-name>
            <activation-config-property-value>jms/connectionFactory</activation-config-property-value>
         </activation-config-property>
      <activation-config>   
      ...

...or using annotation as follows:

@MessageDriven(
    activationConfig = {
        @ActivationConfigProperty(
            propertyName="connectionFactoryJndiName", propertyValue="jms/connectionFactory")
    })
public class MyMDB implements MessageListener {
....

2. Define a new element under the <message-driven> element and a corresponding annotation

This option would propose that the <message-driven> element in ejb-jar.xml be extended to define an addition sub-element which can be used to specify the JNDI name of the connection factory used by a JMS message-driven bean to consume messages. A suggested element name is <connection-factory-jndi-name>:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>MessageBean</ejb-name>
      <message-destination-type>javax.jms.Queue</message-destination-type>
      <connection-factory-jndi-name>jms/connectionFactory<connection-factory-jndi-name>
      ...

To provide an equivalent annotation, a new attribute would need to be added to the @MessageDriven annotation. A suggested name is connectionFactoryJndiName:

@MessageDriven(connectionFactoryJndiName="jms/connectionFactory")
public class MyMDB implements MessageListener {
....

It might be asked why this needs to be defined by a new subelement of <message-driven> and a new attribute of @MessageDriven rather than by a new standard activation configuration property. Possible answers are:

  • this is needed for consistency with the existing <message-destination-link> and the proposed <message-destination-jndi-name> subelements of <message-driven>. (See JMS_SPEC-54).
  • the connection factory is such an important property of a JMS MDB that it deserves explicit support in the ejb-jar.xml schema and by the compiler, rather than being relegated to being just an activation property.

Options

In brief, the options are:

1) New mandatory activation property connectionFactoryJndiName
2) New element <connection-factory-jndi-name> and corresponding annotation @MessageDriven(connectionFactoryJndiName=...
3) Both 1) and 2)
4) Neither



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

The current proposal is to define a standard activation property connectionFactoryLookup.

However this is only possible if the connector spec can guarantee that the resource adapter will be able to perform the lookup in the endpointActivation call. I have logged CONNECTOR_SPEC-4 to request clarification .

Comment by Nigel Deakin [ 07/Feb/13 ]

The JMS 2.0 and EJB 3.2 specifications now define a activation property connectionFactoryLookup. This is defined as follows (JMS 2.0 section 13.1 "MDB activation properties"):

Activation property Description
connectionFactoryLookup This property may be used to specify the lookup name of an administratively-defined javax.jms.ConnectionFactory, javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory object that will be used to connect to the JMS provider from which the endpoint (message-driven bean) is to receive messages.

This issue is now incorporated in the JMS 2.0 spec and can be marked as resolved.





[JMS_SPEC-115] Remove the statement that portable applications should only have one consumer per queue Created: 19/Feb/13  Updated: 20/Mar/13  Resolved: 25/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 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

Tags: jms20-fd20-doc-added

 Description   

The JMS 1.1 specification, in section 4.4.9 "Multiple Sessions" states that

For PTP, JMS does not specify the semantics of concurrent QueueReceivers for
the same Queue; however, JMS does not prohibit a provider from supporting
this. Therefore, message delivery to multiple QueueReceivers will depend on the
JMS provider's implementation. Applications that depend on delivery to
multiple QueueReceivers are not portable

This means that a JMS provider is not required to support multiple consumers on the same queue, and that although JMS providers are allowed to do so, any application which depends on this is not portable.

I think that statement is obsolete now that all modern JMS providers allow multiple consumers on a queue. It is also anomalous now that JMS 2.0 requires shared subscriptions to allow multiple consumers.

It is therefore proposed that the section above be reworded to state that a queue may have multiple consumers, but that JMS does not define how messages from a queue are distributed amongst multiple consumers (i.e. there is no requirement for load-balancing etc).

Although JMS does not define how many concurrent consumers on a queue or shared subscription must be supported, providers are expected to support more than one consumer.



 Comments   
Comment by Nigel Deakin [ 25/Feb/13 ]

In the JMS 2.0 final draft, a new section 4.1.2 "Queue semantics" has been added. Significant text in bold:

When point-to-point messaging is being used, an application sends messages to a queue.

An application may consume messages from the queue by creating a consumer (a MessageConsumer, JMSConsumer or QueueReceiver object) on that queue. A consumer may be used to consume messages either synchronously or asynchronously.

A queue may have more than one consumer. Each message in the queue is delivered to only one consumer.

A consumer may be configured to use a message selector. In this case only messages whose properties match the message selector will be delivered to the consumer. Messages which are not selected remain on the queue or are delivered to another consumer.

The order in which an individual consumer receives messages is described in section 6.2.9 “Message order” below.
By definition, if a consumer uses a message selector, or there are other consumers on the same queue, then a consumer may not receive all the messages on the queue. However those messages that are delivered to the consumer will be delivered in the order defined in section 6.2.9.

Apart from the requirements of any message selectors, JMS does not define how messages are distributed between multiple consumers on the same queue.

A corresponding new section 4.2.2 "Topic semantics" has been added. Significant text in bold:

When pub/sub messaging is being used, an application sends messages to a topic.

An application consumes messages from a topic by creating a subscription on that topic, and creating a consumer (a MessageConsumer, JMSConsumer or TopicSubscriber object) on that subscription.

A subscription may be thought of as an entity within the JMS provider itself whereas a consumer is a JMS object within the application.

A subscription will receive a copy of every message that is sent to the topic after the subscription is created, except if a message selector is specified. If a message selector is specified then only those messages whose properties match the message selector will 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.

Some subscriptions are restricted to a single consumer. In this case all the messages in the subscription are delivered to that consumer. Some subscriptions allow multiple consumers. In this case each message in the subscription is delivered to only one consumer. JMS does not define how messages are distributed between multiple consumers on the same subscription.

The order in which messages are delivered to a consumer is described in section 6.2.10 “Message order” below. By definition, if a subscription uses a message selector, or there are other consumers on the same subscription, then a consumer may not receive all the messages sent to the topic. However those messages that are delivered to the consumer will be delivered in the order defined in section 6.2.10.





[JMS_SPEC-114] Clarify javadoc descriptions of XAQueueConnection#createSession and XATopicSession#createSession Created: 14/Feb/13  Updated: 20/Mar/13  Resolved: 14/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 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

Tags: jms20-fd20-doc-added

 Description   

In JMS 1.1 the javadoc description of Connection#createSession is "Creates an Session object...Returns: a Session object"
http://docs.oracle.com/javaee/6/api/javax/jms/XAConnection.html#createSession%28boolean,%20int%29

However the javadoc description of XAQueueConnection.html#createQueueSession is "Creates an XAQueueSession object...Returns: a newly created XAQueueSession"
http://docs.oracle.com/javaee/6/api/javax/jms/XAQueueConnection.html#createQueueSession%28boolean,%20int%29

and the javadoc description of XATopicConnection#createTopicSession is "Creates an XATopicSession object...Returns: a newly created XA topic session"
http://docs.oracle.com/javaee/6/api/javax/jms/XATopicConnection.html#createTopicSession%28boolean,%20int%29

The latter two descriptions are inconsistent with the return type. The fact that the first description is consistent with the return type confirms that this is a typo. They should be changed to be consistent with the return type declared in the method signature.

XAQueueConnection.html#createQueueSession should "return a QueueSession" and

XATopicConnection#createTopicSession should "return a TopicSession"



 Comments   
Comment by Nigel Deakin [ 14/Feb/13 ]

Now corrected at

http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/XAQueueConnection.html#createQueueSession%28boolean,%20int%29

http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/XATopicConnection.html#createTopicSession%28boolean,%20int%29





[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-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