3 Replies Latest reply on Jul 14, 2008 12:57 AM by Jessie S. Zamora

    Distributed Transaction using JMS, EJB and MDB

    Jessie S. Zamora Newbie

      Hi, good day to all.

      First of all I would like to thank JBoss for having an excellent product. We've been using it for a mission critical system since 2005 handling more than 100T transactions a day and we encountered very few problems about it and its performance.

      Recently, we are currently developing a distributed transactional solution with JBoss.4.0.5.GA using EJB3, JMS and MDB for our new client. Honestly, I have no experience using JMS and been studying it through the various sources and tutorials from the net. Based on what I understand ( and I might be wrong ;-) ), combining EJB3, JMS and MDB with distributed support under JBoss, it guarantees the 2PC requirement. Our problem and current test setup is described below:

      1. A client app calls a PaymentServiceSessionBean to post payment on Server1.
      2. The PaymentServiceSessionBean post a topic to PaymentTopic on Server1.
      3. A PaymentMDB in server1 receives the topic and post the payment on the local db
      4. A PaymentMDB in server2 (remote) receives the topic and post the payment on its localdb.
      5. This will complete the transaction.

      However, performing distributed transaction testing I ran into problems. When the posting of payment in server1 to the database fails, the server2 posting is not rolledback. The same when a failure in db transaction in server2, the update in server1 db is committed and not rolledback.

      Theorethically I believe this common scenario is supported by JBoss and J2EE inparticular. I hope for your expert advise and technical expertise.

      Thanks in advance.[/img]

        • 1. Re: Distributed Transaction using JMS, EJB and MDB
          Tim Fox Master

          You need to be using the JMS JCA resource adapter (at java:/JmsXA) see wiki for more info.

          • 2. Re: Distributed Transaction using JMS, EJB and MDB
            Jessie S. Zamora Newbie

            Thanks Tim for the immediate reply.

            Listed below are the snippet of codes i use for the application (Error handling is remove)

            The PaymentCollectionService is the one posting the payment topic. This is deployed on server1.

            
            @Stateless
            public class PaymentCollectionService implements IPaymentCollectionService {
             @PersistenceContext(unitName="paymentPU")
             private EntityManager em;
            
             @Resource(mappedName="java:/JmsXA")
             private TopicConnectionFactory connFactory;
            
             @Resource(mappedName="topic/PaymentTopic")
             private Topic paymentTopic;
            
            
             public void postPayment(String action, Receipt receipt) throws Exception {
             Connection conn = null;
             Session session = null;
             MessageProducer sender = null;
            
             try {
             conn = connFactory.createConnection();
             session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
             sender = session.createProducer(paymentTopic);
             ObjectMessage om = session.createObjectMessage();
             om.setJMSType(action);
             om.setObject((Serializable)receipt);
             sender.send(om);
             }
             catch (Exception e) {
             e.printStackTrace();
             throw e;
             } finally {
             if(sender != null ) try {sender.close();}catch(Exception ex){};
             if(session != null ) try {session.close();}catch(Exception ex){};
             if(conn != null ) try {conn.close();}catch(Exception ex){};
             }
             }
            }
            
            



            The ProvincePostPaymentListener listens on PaymentTopic. This is also deployed in server1.

            
            @MessageDriven(
            activationConfig = {
             @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"),
             @ActivationConfigProperty(propertyName="destination", propertyValue="topic/PaymentTopic"),
             @ActivationConfigProperty(propertyName="acknowledgeMode", propertyValue="Auto-acknowledge")
            }
            )
            public class ProvincePostPaymentMessageListener implements MessageListener {
            
             @Resource
             private MessageDrivenContext mdbContext;
            
             @EJB
             private ICollectionService collectionService;
            
             @TransactionAttribute(TransactionAttributeType.REQUIRED)
             public void onMessage(Message message) {
             try {
             ObjectMessage msg = (ObjectMessage) message;
             Receipt receipt = (Receipt)msg.getObject();
             collectionService.postProvincePayment(receipt);
             }
             catch (Exception ex) {
             mdbContext.setRollbackOnly();
             }
             }
            }
            



            The MunicipalityPostPaymentListener is deployed on the remote server2. This also listens to PaymentTopic.

            @MessageDriven(
            activationConfig = {
             @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"),
             @ActivationConfigProperty(propertyName="destination", propertyValue="topic/PaymentTopic"),
             @ActivationConfigProperty(propertyName="acknowledgeMode", propertyValue="Auto-acknowledge"),
             @ActivationConfigProperty(propertyName="providerAdapterJNDI", propertyValue="java:/ProvinceJMSProvider")
            }
            )
            public class MunicipalityPostPaymentMessageListener implements MessageListener {
             @EJB
             private IRPTCollectionService collectionService;
            
             @Resource
             private MessageDrivenContext context;
            
             @TransactionAttribute(TransactionAttributeType.REQUIRED)
             public void onMessage(Message message) {
             ObjectMessage msg = (ObjectMessage)message;
             Receipt receipt = (Receipt) msg.getObject();
             collectionService.postRemotePayment(receipt);
             throw new Exception("ROLLBACK TEST"); //test error to rollback the transaction
             }
             catch (Exception ex) {
             context.setRollbackOnly();
             }
             }
            
            
            
            }
            
            



            The persistence.xml description.
            <?xml version="1.0" encoding="UTF-8"?>
            <persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">
            
             <persistence-unit name = "defaultPU">
             <provider>org.hibernate.ejb.HibernatePersistence</provider>
             <jta-data-source>java:/defaultDB</jta-data-source>
             <properties>
             <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
             <property name="hibernate.hbm2ddl.auto" value="update"/>
             <property name="hibernate.show_sql" value="false"/>
             <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/>
             <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
             </properties>
             </persistence-unit>
            </persistence>
            


            I suspect there might be JBoss settings thats not done right and hopefully you can assist me with it. Thanks alot

            • 3. Re: Distributed Transaction using JMS, EJB and MDB
              Jessie S. Zamora Newbie

              I found out that I really misunderstood JMS :-( I dedicated a day researching and studying its pros and cons. Currently, I implemented this scenario using durable messages. Its works great.

              Thanks guys.