1 Reply Latest reply on Aug 13, 2009 9:05 AM by Nikolay Elenkov

    BMT in Seam

    Arbi Sookazian Master

      The following SFSB is a refactoring of a Servlet example from the Java Transaction Processing book by Mark Little, et al.


      The CRUD is not happening (no changes to database).  If I remove the following annotation:


      @TransactionManagement(TransactionManagementType.BEAN)



      which defaults to CMT, the tx commits both CRUD operations to db.


      Why is this not working with BMT and does Seam even support BMT with session beans?  I don't see it in the list in Table 9.3 in SiA book.


      The following line is not throwing any exception:


      tx.commit ();



      ???


      /**
       * This SFSB demonstrates the creation of a distributed transaction that scopes work performed against
       * two different databases.
       */
      @Name("testJTPBean")
      @AutoCreate
      @Install(true)
      @Stateful
      @TransactionManagement(TransactionManagementType.BEAN)
      public class TestJTPBean implements TestJTPLocal {
           
           @Logger 
           Log log;
           
           @In 
           EntityManager em;
           
           //Seam tx injection
           //@In(create=true) 
           //UTTransaction tx;
           
           private static final String USER_TX_LOOKUP_STR = "java:comp/UserTransaction";
      
          @Begin(join=true)
          public void doTransfer() 
          {
              // get empNo to transfer
              boolean success = false;
              UserTransaction tx = null;
              int empNo = 0;
      
              try
              {
                  empNo = 1;
                  InitialContext ic = new InitialContext();
                  tx = (UserTransaction) ic.lookup ( USER_TX_LOOKUP_STR );
                  tx.begin ();
                  removeHotel ( empNo );
                  addHotel ();
                  success = true;
              }
              catch ( Exception e )
              {
                   log.error("exception: ", e);
              }
              finally
              {
                  if (!success)
                  {
                      rollback ( tx );
                  }
                  else
                  {
                      commit ( tx );
                  }
                  log.info("success = "+success);
              }
          }
      
          protected void addHotel() 
          {
               Hotel hotel = new Hotel();
              
              hotel.setAddress("1234 test");
              hotel.setName("myName");
              hotel.setCity("myCity");
              hotel.setZip("90000");
              hotel.setState("CA");
              hotel.setCountry("USA");
              em.persist(hotel);
          }
      
          
      
          private void removeHotel(int empNo) 
          {
              Hotel hotel = em.find(Hotel.class, new Long(1));
              em.remove(hotel);
      
          }
      
          private void commit ( UserTransaction tx ) 
          {
              try
              {
                  tx.commit ();
              }
              catch ( Exception e )
              {
                  log.error("error: ", e);
              }
          }
      
          private void rollback ( UserTransaction tx ) 
          {
              try
              {
                  tx.rollback ();
              }
              catch ( Exception e )
              {
                  log.error("error: ", e);
              }
          }
          
          @Remove @Destroy
          public void destroy(){}
      
      }



      output:


      11:32:17,370 INFO  [STDOUT] Hibernate: 
          select
              hotel0_.id as id121_0_,
              hotel0_.address as address121_0_,
              hotel0_.name as name121_0_,
              hotel0_.state as state121_0_,
              hotel0_.country as country121_0_,
              hotel0_.price as price121_0_,
              hotel0_.city as city121_0_,
              hotel0_.zip as zip121_0_ 
          from
              Hotel hotel0_ 
          where
              hotel0_.id=?
      11:32:17,385 WARN  [PermissionManager] no permission store available - please install a PermissionStore with the name 'org.jboss.seam.security.jpaPermissionStore' if permission management is required.
      11:32:17,385 INFO  [TestJTPBean] success = true



      components.xml:


      <?xml version="1.0" encoding="UTF-8"?>
      <components xmlns="http://jboss.com/products/seam/components"
                  xmlns:core="http://jboss.com/products/seam/core"
                  xmlns:persistence="http://jboss.com/products/seam/persistence"
                  xmlns:security="http://jboss.com/products/seam/security"
                  xmlns:transaction="http://jboss.com/products/seam/transaction"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation=
                      "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.1.xsd
                       http://jboss.com/products/seam/transaction http://jboss.com/products/seam/transaction-2.1.xsd
                       http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.1.xsd
                       http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.1.xsd">
          
          <core:init jndi-pattern="@jndiPattern@" debug="true" distributable="@distributable@" transaction-management-enabled="false"/>
          
          <core:manager conversation-timeout="120000"
                        concurrent-request-timeout="500"
                        conversation-id-parameter="cid"/>
      
          <!-- <transaction:ejb-transaction/>  -->
      
          <security:identity authenticate-method="#{authenticator.authenticate}"/>
          
          <persistence:managed-persistence-context name="em"
                                           auto-create="true"
                            persistence-unit-jndi-name="java:/jbossEntityManagerFactory"/>
                            
          <persistence:managed-persistence-context name="em2"
                                           auto-create="true"
                            persistence-unit-jndi-name="java:/jboss2EntityManagerFactory"/>
                            
          <!-- JMS setup -->
                            
          <component name="topicPublisher" class="org.jboss.seam.jms.ManagedTopicPublisher">
              <property name="topicJndiName">topic/chatroomTopic</property>
          </component>
          
          <component name="queueSender" class="org.jboss.seam.jms.ManagedQueueSender">
              <property name="queueJndiName">queue/chatroomQueue</property>
          </component>
      
       
      </components>

        • 1. Re: BMT in Seam
          Nikolay Elenkov Master

          Since this is a BMT, you have to join the transaction manually. Here's what happens:



          1. to inject the SMPC, Seam calls the @Unwrap method of ManagedPersistenceContext

          2. the PC tries to join the transaction, but since there is none active (you haven't called begin() yet), it doesn't

          3. you do stuff with the SPMC, but since it's not running in a transaction, nothing gets committed



          For this to work you have to add this right after tx.begin():


          entityManager.joinTransaction();
          



          If you use the @PersistenceContext, it joins the UT automatically (probably through some EJB interceptor), so you could argue
          that this is a bug in Seam (different behaviour for the SMPC). To get the same behaviour, I guess you could add the call to joinTransaction to EjbSynchronizations.afterBegin() (it implements SessionSynchronization)


          File a JIRA, let's see what happens :)