jsr343-experts@jms-spec.java.net

[jsr343-experts] Re: (JMS_SPEC-45) Clarify and improve Connection.createSession

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Fri, 19 Aug 2011 10:59:05 +0100

John suggested in another thread:
> Could your spec change perhaps use an enum to describe the sessionMode as well?

We could. In fact an enum would be better than using the existing constants

Nigel

On 09/08/2011 11:35, Nigel Deakin wrote:
> I have logged the following JIRA issue:
> http://java.net/jira/browse/JMS_SPEC-45
>
> This is quite a long description and it may be easier to read the formatted version in the JIRA issue rather than the
> text version below. In any case, I would appreciate your comments.
>
> Nigel
>
>
> 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,
> {quote}
> 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.
> {quote}
>
> 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.
>
> h4.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
>
> where sessionMode may be set to Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE or
> Session.AUTO_TRANSACTED
>
> * The existing createSession will remain with a note that it may be removed from a future release of the API.
>
>
>