2 Replies Latest reply on Aug 11, 2009 6:39 PM by asookazian

    Distributed tx involving DB and JMS session

    asookazian

      Please reference this thread:
      http://www.seamframework.org/Community/NewSeamExampleFeaturingDistributedTransactions

      Using a EJB 3.0 SFSB with JSF 1.2 and Seam 2.1.2.GA running in JBoss AS 4.2.3.GA.

      Need to understand why the tx mgr is (apparently?) not enlisting the JMS session as part of a distributed tx with the other resource mgr managing a DB (via EntityManager interface).

      I am using <local-tx-datasource> to test this out in my *-ds.xml:

      <datasources>
       <local-tx-datasource>
       <jndi-name>bookingDatasource</jndi-name>
       <connection-url>jdbc:mysql://localhost:3306/jboss</connection-url>
       <driver-class>com.mysql.jdbc.Driver</driver-class>
       <user-name>jboss</user-name>
       <password>password</password>
       <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
      
       <metadata>
       <type-mapping>mySQL</type-mapping>
       </metadata>
       </local-tx-datasource>
       <local-tx-datasource>
       <jndi-name>bookingDatasource2</jndi-name>
       <connection-url>jdbc:mysql://localhost:3306/jboss2</connection-url>
       <driver-class>com.mysql.jdbc.Driver</driver-class>
       <user-name>jboss</user-name>
       <password>password</password>
       <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
      
       <metadata>
       <type-mapping>mySQL</type-mapping>
       </metadata>
       </local-tx-datasource>
      </datasources>


      Here's some relevant code snippets:

      @Name("startConversation")
      @AutoCreate
      @Install(true)
      @Stateful
      public class TestStartConversation implements TestStartConversationLocal{
      
       @Logger
       private Log log;
      
       @In
       private EntityManager em;
      
       private transient TopicPublisher topicPublisher;
       private transient TopicSession topicSession;
       private transient TopicConnection conn;
       private transient Topic topic;
      
       @Begin(join=true, flushMode=FlushModeType.MANUAL)
       public void startup(){
       log.info("in startup()");
       List<Hotel> list = em.createQuery("from Hotel").getResultList();
       log.info("list.size() = "+list.size());
      
       Hotel hotel = null;
      
       if (list != null && list.size() > 0) {
       hotel = list.get(0);
       hotel.setAddress("arbi's house1");
       }
      
       em.flush();
      
       try{
       InitialContext iniCtx = new InitialContext();
       Object tmp = iniCtx.lookup("ConnectionFactory");
       TopicConnectionFactory tcf = (TopicConnectionFactory) tmp;
       conn = tcf.createTopicConnection();
       topic = (Topic) iniCtx.lookup("topic/chatroomTopic");
       topicSession = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
       topicPublisher = topicSession.createPublisher(topic);
       topicPublisher.publish( topicSession.createObjectMessage(new ChatroomEvent("connect", "arbime")) );
       }
       catch(Exception e){
       //noop
       }
      
       }
      
      
       @Destroy
       @Remove
       public void destroy(){
       log.info("in destroy()");
       }
      
      
      }


      Please note that the distributed tx semantics are behaving as expected when I read from two different DBs in the startup() method above using two different EntityManager instances (i.e. I get tx enlist exceptions when I use local-tx-datasource instead of xa-datasource in *-ds.xml). And of course, the tx attribute type by default for the startup() method is REQUIRED as per JSR220.

      thx.

        • 1. Re: Distributed tx involving DB and JMS session
          asookazian

          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@"/>
          
           <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"/>
          
           <component name="topicPublisher" class="org.jboss.seam.jms.ManagedTopicPublisher">
           <property name="topicJndiName">topic/chatroomTopic</property>
           </component>
          
          
          </components>


          jboss-seam-chatroom-service.xml (deployed in server/default/deploy):
          <server>
          
           <mbean code="org.jboss.mq.server.jmx.Topic"
           name="jboss.mq.destination:service=Topic,name=chatroomTopic">
           <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
           <depends optional-attribute-name="SecurityManager">jboss.mq:service=SecurityManager</depends>
           <attribute name="SecurityConf">
           <security>
           <role name="guest" read="true" write="true"/>
           <role name="publisher" read="true" write="true" create="false"/>
           <role name="durpublisher" read="true" write="true" create="true"/>
           </security>
           </attribute>
           </mbean>
          
          </server>
          


          • 2. Re: Distributed tx involving DB and JMS session
            asookazian

            I am using the following code in my SFSB and there are no exceptions thrown as I would expect b/c I'm using local-tx-datasource rather than xa-datasource. So how do I know that the resources are beling enlisted? I know the code is in the org.jboss.resource.connectionmanager.TxConnectionManager class's enlist() method but that class is very convoluted to say the least...

            private transient TopicPublisher topicPublisher;
             private transient XATopicSession topicSession;
             private transient XATopicConnection conn;
             private transient Topic topic;
            
            
             /******************************* begin methods *******************************/
             @TransactionAttribute(TransactionAttributeType.REQUIRED)
             public void startup(){
             log.info("in startup()");
             List<Hotel> list = em.createQuery("from Hotel").getResultList();
             log.info("list.size() = "+list.size());
            
             try{
             InitialContext iniCtx = new InitialContext();
             XATopicConnectionFactory tcf = (XATopicConnectionFactory) iniCtx.lookup("XAConnectionFactory");
             conn = tcf.createXATopicConnection();
             topic = (Topic) iniCtx.lookup("topic/chatroomTopic");
             topicSession = conn.createXATopicSession();
             topicPublisher = topicSession.getTopicSession().createPublisher(topic);
             topicPublisher.publish( topicSession.createObjectMessage(new ChatroomEvent("connect", "arbime")) );
             }
             catch(Exception e){
             //noop
             }
             finally {
             try {
             topicSession.close();
             conn.close();
             }
             catch(Exception e) {
             //noop
             }
             }
             }


            From JSR220-core:

            The application programmer does not have to do anything to ensure transactional semantics. The enterprise beans X and Y perform the message send and database updates using the standard JMS and JDBC APIs. Behind the scenes, the EJB server enlists the session on the connection to the JMS provider and the database connections as part of the transaction. When the transaction commits, the EJB server and the messaging and database systems perform a two-phase commit protocol to ensure atomic updates across all the three resources.