jms-spec
  1. jms-spec
  2. JMS_SPEC-126

API to allow app servers to implement JMSContext without needing an additional connection pool

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.0
    • Fix Version/s: None
    • Labels:
      None

      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.

        Activity

        Nigel Deakin created issue -
        Nigel Deakin made changes -
        Field Original Value New Value
        Tags jms20-bug
        Nigel Deakin made changes -
        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#createSession(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}}.
        *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#createSession(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}}.
        Nigel Deakin made changes -
        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#createSession(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}}.
        *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}}.

          People

          • Assignee:
            Unassigned
            Reporter:
            Nigel Deakin
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: