jms-spec
  1. jms-spec
  2. JMS_SPEC-45

Clarify and improve Connection.createSession

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 2.0ED, 2.0
    • Labels:
      None

      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.

        Issue Links

          Activity

          Hide
          Nigel Deakin added a comment -

          Description updated to propose new method Session createSession() with no arguments for use in a Java EE environment.

          Show
          Nigel Deakin added a comment - Description updated to propose new method Session createSession() with no arguments for use in a Java EE environment.
          Hide
          Nigel Deakin added a comment -

          Updated to propose that the existing method createSession(boolean transacted,int acknowledgeMode will be formally marked as @Deprecated

          Show
          Nigel Deakin added a comment - Updated to propose that the existing method createSession(boolean transacted,int acknowledgeMode will be formally marked as @Deprecated
          Hide
          Nigel Deakin added a comment -

          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.

          Show
          Nigel Deakin added a comment - 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.
          Hide
          Nigel Deakin added a comment - - edited

          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?

          Show
          Nigel Deakin added a comment - - edited 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?
          Hide
          Nigel Deakin added a comment -

          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)

          Show
          Nigel Deakin added a comment - 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)
          Hide
          Nigel Deakin added a comment -

          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.

          Show
          Nigel Deakin added a comment - 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.
          Hide
          Nigel Deakin added a comment -

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

          Show
          Nigel Deakin added a comment - This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0

            People

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

              Dates

              • Created:
                Updated:
                Resolved: