0 Replies Latest reply on Apr 1, 2011 9:43 AM by Mauro Castaldo

    Seam Transaction Management & EJB3 CMT

    Mauro Castaldo Newbie

      I'm new to Seam.
      I'm trying to set up a Java EE Seam project using Seam 2.2.1, JPA and EJB3.
      After reading lot of documentation about Seam transaction management I found this topic still confusing so I decided to set up a project prototype to test it and debug Seam code.


      I would like to take advantage of EJB3 Container Managed Transactions (CMT) so I configured components.xlm with


      <transaction:ejb-transaction/>



      this effectively enable an EJB3 SFSB Seam component (EjbSynchronizations) that implements SessionSynchronization interface. It seams it is used to send container managed transaction synchronization events to keep the framework in sync.


      I found that Seam wraps JSF lifecycle with two transactions of type UTTransaction. I read about advantages of these global transactions so I decided to keep them enabled (default):


      <core:init transaction-management-enabled="true"/>



      I would also like to use Seam managed conversation scoped EntityManager because I like this powerful and simplified contextual injection approach (using @In) over standard EJB3 injected EntityManager (using @PersistenceContext):


      <persistence:managed-persistence-context name="entityManager" auto-create="true"
                                               entity-manager-factory="#{entityManagerFactory}"/>
      
      <persistence:entity-manager-factory name="entityManagerFactory" persistence-unit-name="myPersistenceUnit"/>
      



      I also noticed that Seam automatically enlist this conversational EntityManager in the current global transaction whenever it is injected into a Seam Component.
      To do that it uses the @Unwrap method getEntityManager() of the ManagedPersistenceContext component.


      Now the problem.


      Suppose you have this EJB:


      @Name("test")
      @Stateful
      public class TestBean implements Test {
      
          @Logger
          private Log log;
      
          @In
          private EntityManager entityManager;
      
      
          @SuppressWarnings("unchecked")
          public void testAction() {
              List<Department> departments = entityManager.createQuery("select d from Department d").getResultList();
              log.info("Size:" + departments.size());
          }
      }
      


      If i call testAction() method from a JSF page, according to EJB3 specs the EJB container should automatically start a transaction before executing code and commit o rollback it when finished (I suppose using something like an interceptor around invoke).

      Now I'm wondering if this is the same global transaction into which is enlisted the EntityManager.


      I think not, because the global transaction is a UserTransaction started in the web layer, outside the EJB container.
      Moreover if you print the current transaction within the testAction() method


          @SuppressWarnings("unchecked")
          public void testAction() { 
              UserTransaction ut = Transaction.instance();
              log.info(ut.getClass().getName());
          }
      



      you will get org.jboss.seam.transaction.UTTransaction, that is the global transaction, and not a org.jboss.seam.transaction.CMTTransaction that Seam should return in case of Container Managed Transaction.


      So what's happening under the hood?


      Do we have two different concurrent overlapped transactions (one global Seam managed UTTransaction and another EJB managed CMT transaction)?


      If yes, could these two, not shared transactions have potential side effects?


      If I use Seam managed EntityManager enlisted in global transaction, shouldn't be better to disable useless CMT and use bean managed transaction?


      Does Seam global transaction mimic CMT in relation to @TransactionAttribute annotations?


      Is there any practical case in which Seam create a CMTTransaction instead of UTTransaction?


      Is this approach correct or should I get it done in a different way?


      I hope someone could help to demistify this important topic!


      Thanks in advance.


      Mauro