[JMS_SPEC-153] Correction to 7.3.8. "Use of the CompletionListener by the JMS provider" Created: 19/May/14  Updated: 19/May/14

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

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

Tags: jms20-bug

 Description   

In the JMS 2.0 specification, section 7.3.8. "Use of the CompletionListener by the JMS provider" states:

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

This requirement was added to the specification to make the handling of async callbacks as simple as possible, and as consistent with synchronous sends as possible. However the requirement that callbacks be performed in order for a given MessageProducer is inconsistent with the longstanding JMS principle defined in section 6.2.9.1 that "messages sent by a session to a destination must be received in the order in which they were sent".

It would perhaps be more consistent if the JMS specification were changed to state that callbacks be performed in order for a given Session.

A session will only invoke one CompletionListener callback method at a time. For a given Session or JMSContext, callbacks (both onCompletion and onException) will be performed in the same order as the corresponding calls to the asynchronous send method.

Note that although this may require JMS providers to change the order in which they perform callbacks, such a change would be completely compatible with existing applications since if callbacks occur in session order then they will by definition be in message producer order as well.






[JMS_SPEC-152] New method XAJMSContext#createXAJMSContext Created: 19/May/14  Updated: 19/May/14

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

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

Tags: jms20-bug

 Description   

A new method is needed on XAJMSContext which creates a new JMSXAContext using the same connection as the existing XAJMSContext and creating a new session.

XAJMSContext createXAContext()

This is analogous to the existing method createContext on JMSContext, but for XA-capable JMSContext objects.

This method was omitted from JMS 2.0 on the grounds that the JMS specification did not permit the creation of multiple sessions from the same connection in the Java EE web or EJB container. However this is not the right place to enforce that restriction, since it is a restriction on the application, not the application server or resource adapter, and the XAJMSContext interface is for use by the application server or resource adapter, not by applications. Omitting this method places an unnecessary restriction on the ability for application servers to use multiple sessions on the same connection whilst preventing applications doing the same.






[JMS_SPEC-126] API to allow app servers to implement JMSContext without needing an additional connection pool Created: 20/May/13  Updated: 11/Oct/13

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

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

Tags: jms20-bug

 Description   

The problem

In JMS 2.0, chapter 11 "JMS application server facilities" defines some optional API which may be used by application servers to allow them to support any compliant JMS provider. Some application servers use this API directly whilst some use this API to implement a portable resource adapter.

Application servers or resource adapters that use this API typically maintain a pool of the JMS provider's Connection objects. To support this, they wrap the JMS provider's ConnectionFactory object so that a call to createConnection does not create a new Connection object but instead fetches one from a pool. They also wrap the JMS provider's Connection object so that a call to the close method does not close the connection but instead simply returns it to the pool.

The introduction of the JMSContext object in JMS 2.0 has complicated matters. Since a JMSContext contains a connection then an obvious approach is to maintain a separate pool of JMSContext objects. In such an implementation, the application server or resource adapter would wrap the JMS provider's ConnectionFactory object so that a call to createContext does not create a new JMSContext object but instead fetches one from a pool. It also would wrap the JMS provider's JMSContext object so that a call to the close method does not close the JMSContext but instead simply returns it to the pool.

However this approach requires the application server or resource adapter to maintain two separate pools of objects: a pool of Connection objects and a separate pool of JMSContext objects. This means that for every JMS application, in addition to configuring a Connection pool the user would also need to configure a JMSContext pool. This would be more complicated to administer. It would also be inefficient since a Connection that is released to the pool by a call to connection.close() could only be reused by an application that subsequently calls createConnection to create a Connection. It could not be reused by an application that subsequently called createContext to create a JMSContext.

The solution

This complication can be avoided by defining a new method which allows a JMSContext to be created using a connection that was fetched from the normal connection pool. As with the the existing methods for application server integration, implementing this method would be optional.

New method Connection#createContextForEE(Session s)

JMS providers would be required to implement a new method on Connection with the following signature:
JMSContext createContextForEE(Session session);

This method would simply create a new JMSContext using the specified connection and session.

This method would be for application server or resource adapter use only. The name createContextForEE is intended to discourage naive users from using it accidentally. The application server or resource adapter's implementation of the createContextForEE method on Connection would be encouraged to always throw an exception.

This new method would be used by the application server or resource adapter's ConnectionFactory implementation of createContext as follows:

1. Calls this.createConnection() to create a RA-implemented Connection which wraps a provider-implemented Connection. This would typically fetch the provider-implemented Connection from a pool.

2. Calls the RA-implemented Connection's createSession(sessionMode) method to create a RA-implemented Session which wraps a provider-implemented Session. If the RA-implemented Connection's createSession(sessionMode) method enforced the requirement that you can only create one session on a connection in a Java EE web or EJB container, then this check would be applied here. This also allows the RA-implemented Connection's createSession method to cache the provider-implemented Session if it wants to

3. Calls the provider-implemented Connection's createContext(connection,session) method (the new method we're defining here) to create the provider-implemented {{JMSContext }}object

4. Wraps the provider-implemented JMSContext object in a RA-implemented JMSContext

5. Returns the RA-implemented JMSContext to the application

The RA's JMSContext implementation would be a proxy for the JMS provider's JMSContext implementation and could delegate almost all behaviour to it. The exception to this would be the close method. This needs to be overridden so that instead of closing the session and connection it does whatever behaviour is already implemented when a wrapped session and connection is closed. So the RA's JMSContext implementation would override close as follows:

1. Calls the provider-implemented JMSContext's closeForEE() method. This is a new method (described below) offering the same behaviour as the close method but without closing the the underlying session and connection.

2. Calls the RA-implemented Session's close method. This can do whatever it does now, such as leaving the session open and cached with the connection.

2. Calls the RA-implemented Connection's close method. This can do whatever it does now, such as leaving the connection open and returning it to a pool.

New method JMSContext#closeForEE()

This method offers the same behaviour as the JMSContext close method but without closing the underlying session and connection.

It is intended to be called from an application server or resource adapter's implementation of the close method,
and so must provide the same behaviour to the application as is defined for the JMSContext close method.

This includes waiting for any receive call or message listener callback to return,
and for any incomplete asynchronous send operations for this JMSContext to be completed, including waiting for any CompletionListener callbacks to return.

It also includes ensuring that any subsequent call to acknowledge on a message received using this JMSContext causes an IllegalStateException to be thrown.

Again this method would be for application server or resource adapter use only. The name closeForEE is intended to discourage naive users from using it accidentally. The application server or resource adapter's implementation of the closeForEE method on JMSContext would be encouraged to always throw an exception.

It should be seen that this method does more than simply clean up state. It actually need to behave just the same as calling JMSContext#close since that's the method that the application will have called. The same issue applies for application servers and resource adapters that cache the JMS provider's session and connection objects in a pool and provide the application with wrappers around them. These need to be able to implement close without actually closing the object. This suggests that methods similar to closeForEE are needed on Session and Connection as well:

New method Session#closeForEE()

This method offers the same behaviour as the Session close method but without closing the session.
It is intended to be called from an application server or resource adapter's implementation of the close method,
and so must provide the same behaviour to the application as is defined for the Session close method.

This includes waiting for any receive call or message listener callback to return, and for any incomplete asynchronous send operations for this Session to be completed including waiting for any CompletionListener callbacks to return.

It also includes ensuring that any subsequent call to acknowledge on a message received using this Session causes an IllegalStateException to be thrown.

Again this method would be for application server or resource adapter use only. The name closeForEE is intended to discourage naive users from using it accidentally. The application server or resource adapter's implementation of the closeForEE method on JMSContext would be encouraged to always throw an exception.

New method Connection#closeForEE()

This method offers the same behaviour as the Connection close method but without closing the connection.
It is intended to be called from an application server or resource adapter's implementation of the close method,
and so must provide the same behaviour to the application as is defined for the Connection close method.

This includes waiting for any receive call or message listener callback to return, and for any incomplete asynchronous send operations for this Connection to be completed including waiting for any CompletionListener callbacks to return.

It also includes ensuring that any subsequent call to acknowledge on a message received using this Connection causes an IllegalStateException to be thrown.

Again this method would be for application server or resource adapter use only. The name closeForEE is intended to discourage naive users from using it accidentally. The application server or resource adapter's implementation of the closeForEE method on JMSContext would be encouraged to always throw an exception.

Naming considerations

An alternative name for closeForEE could be closeForPooling.

Alternatively some new interfaces could be defined which contain these new methods. This probably makes things too complicated but is included here for discussion.

A new interface PoolableConnection could be defined with two methods createContext(Session s) and closeForPooling. There would be a new method Connection#getPoolableConnection to obtain an instance of this interface from the Connection.

A new interface PoolableJMSContext could be defined with one method {closeForPooling}}. There would be a new method JMSContext#getPoolableJMSContext to obtain an instance of this interface from the JMSContext.

A new interface PoolableSession could be defined with one method {closeForPooling}}. There would be a new method JMSContext#getPoolableSession to obtain an instance of this interface from the Session.



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

Here's another idea: instead of Connection#createContextForEE(Session s) we could have Session#createContextForEE(). Both give the application server or resource adapter control over the creation of the connection and session.

Comment by clebertsuconic [ 12/Sep/13 ]

Is this really needed? all we care so for is pool the connection. a JMSContext instance should be pretty cheap to just be GCed... the JMSContext is always getting a Connection from the pool, in which case it should either reuse a previous connection or create a new one when needed.

I understand there could be an implementation mistake where this would end up being created every time. But I think it can be fixed using the current spec pretty easily without adding API changes.

Comment by clebertsuconic [ 12/Sep/13 ]

closeForEE.. I don't think that's needed as well? just reference counting and other implementation details can fix that. It seems to be fixable with implementation details rather than with API changes. maybe I'm missing something there?

Comment by clebertsuconic [ 12/Sep/13 ]

Also: with EE you only have one JMSContext. Someone could easily cache the instance on the Connection and just get it from there (if you really want to cache it).

Besides: I feel like javax.resource.spi.ManagedConnectionFactory and proper metadata would be enough to manage this.

I really feel this should be an implementation detail without requiring API changes.

Comment by Nigel Deakin [ 11/Oct/13 ]

These methods are needed to allow an application server to create JMSContext objects from existing pooled Connection (and Session) objects. Currently there is no standard API to do this.

Application servers can achieve this with their own JMS provider by using provider-specific API (that's what GlassFish does now). However if we want an application server to be able to achieve this with an arbitrary third-part JMS provider there needs to be a standard API for this.

There is definitely scope to debate the exact methods needed, but I think two new methods are needed (1) to create a JMSContext from a Connection and Session and (2) to do the reverse.

Comment by John D. Ament [ 11/Oct/13 ]

I personally don't see the point in doing this. Are you trying to say it should be possible for a third party to construct a JMSContext, on behalf of the application server?

Comment by Nigel Deakin [ 11/Oct/13 ]

This feature is proposed to for use in the following use cases:

(1) application servers which support third-party JMS providers directly (i.e. without using a resource adapter provided by the third party)

(2) resource adapters which support third-party JMS providers (i.e. JMS resource adapters which are not tied to a particular JMS provider but work with any JMS provider)

In these cases, when a Java EE 6 application calls connectionFactory.createConnection(), the application server or resource adapter currently intercepts this call and plucks a Connection out of the connection pool.

When a Java EE 7 application calls connectionFactory.createContext(), the application server or resource adapter will need to intercept this call and pluck a JMSContext out of the JMSContext pool. However this means that the application server will need to maintain a pool of JMSContext objects separate from the pool of Connection objects, which is potentially less efficient and gives the user something extra to configure.

This proposal is intended to avoid the need to create a second pool and allows the existing pool of Connection objects to be used both when the application calls createConnection() and when it calls createContext().

When a Java EE application calls connectionFactory.createContext(), the application server or resource adapter should be able to intercept this call, pluck a Connection out of the Connection pool, and then use the API proposed above to create a JMSContext from that Connection. There is no need to maintain a separate pool of JMSContext objects.

(Note that there'll be an opportunity to discuss this more thoroughly at the appropriate time; the comments on this issue make it clear that when that happens I'll need to explain carefully why I think this is a desirable feature).





[JMS_SPEC-123] JMSProducer#setJMSCorrelationIDAsBytes should be allowed to throw a java.lang.UnsupportedOperationException Created: 14/May/13  Updated: 14/May/13

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

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

Tags: jms20-bug

 Description   

In both JMS 1.1 and JMS 2.0, the method setJMSCorrelationIDAsBytes on Message is allowed to throw a java.lang.UnsupportedOperationException if the JMS provider does not support native correlation ID values. The javadoc states:

If a provider supports the native concept of correlation ID, a JMS client may need to assign specific JMSCorrelationID values to match those expected by native messaging clients. JMS providers without native correlation ID values are not required to support this method and its corresponding get method; their implementation may throw a java.lang.UnsupportedOperationException.

The same rule needs to be added to the method setJMSCorrelationIDAsBytes on JMSProducer. Its omission is as an error in the spec.






[JMS_SPEC-121] Injection of JMSContext objects not possible in a WebSocket @OnMessage or @OnClose callback method Created: 07/May/13  Updated: 23/May/13

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

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

Issue Links:
Related
is related to WEBSOCKET_SPEC-196 WebSocket Spec does not define the ac... Open
Tags: jms20-bug

 Description   

If you inject a JMSContext into a websocket ServerEndpoint you can use it in the @OnOpen callback, but if you attempt to use it from the @OnMessage or @OnClose callbacks you get an exception from the CDI container because there is no valid request scope or transaction scope. From a user perspective it would seem reasonable to expect to be able to use an injected JMSContext in these places.

Here's an example of a websocket ServerEndpoint that injects a JMSContext:

@ServerEndpoint("/websocket")
public class SampleWebSocket {
    
    @Resource(lookup="java:comp/DefaultJMSConnectionFactory") ConnectionFactory cf;
    @Resource(lookup = "jms/myQueue") Queue myQueue;
    
    @Inject
    private JMSContext jmsContext;

    @OnOpen
    public void onOpen(final Session session) {
        // works OK as there is a valid request scope here
        context.createProducer().send(myQueue, message);
    }

    @OnMessage
    public void onMessage(final String message, final Session client) {
        // fails as there is no valid request scope here
        context.createProducer().send(myQueue, message);
    }

    @OnClose
    public void onClose(final Session session) {
        // fails as there is no valid request scope here
        context.createProducer().send(myQueue, message);
    }


 Comments   
Comment by Nigel Deakin [ 07/May/13 ]

JMS 2.0 defines an injected JMSContext to have transaction scope if there is a current transaction, and request scope otherwise. However neither scope is available in a websocket @OnMessage or @OnClose callback.

This seems to be an inconsistency in the CDI specification. Although there is no valid HTTP request during the @OnMessage and @OnClose callbacks, CDI already widens the definition of @RequestScoped to cover cases which have no relationship with HTTP. For example CDI 1.0 states that a MDB's onMessage method is executed within a request scope, even though there is no HTTP request involved. Now that WebSockets are part of Java EE 7 (JSR 356), it seems a bit arbitrary for a MDB callback to have a valid request scope, but for a WebSocket callback to not be.

I have asked the CDI expert group to consider whether a future version of CDI should extend the definition of @RequestScoped to include a WebSocket @OnMessage callback. This is https://issues.jboss.org/browse/CDI-370

If no such change is made, the JMS expert group may need to consider whether any changes are needed to the definition of the scope of an injected JMSContext.

Comment by John D. Ament [ 07/May/13 ]

A similar issue is currently floating around the CDI spec. This isn't an issue for CDI or JMS, but that WebSockets spec needs to indicate what contexts need to be activated (for example, regular CDI injections for any object that is request or transaction scoped are not injected either) for each of these annotated methods.

I haven't tested it yet, but I believe the work around will be to make your server endpoint a session bean (which makes it fall under the EJB spec) or to make the endpoint a standard CDI object.

Here's the link to the existing CDI issue: https://issues.jboss.org/browse/CDI-370

Comment by Bruno Borges [ 16/May/13 ]

I tried that John and it does not work. A different instance is created to the CDI context, besides the one for the ws endpoint.

Comment by Nigel Deakin [ 23/May/13 ]

Added link to WEBSOCKET_SPEC-196





Generated at Sat May 30 16:37:55 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.