users@glassfish.java.net

JMS, JPA, XA, rollback and all the rest

From: <glassfish_at_javadesktop.org>
Date: Fri, 15 Jan 2010 07:04:56 PST

Hi,

I'm asking for a verification of my understanding of XA, especially in Glassfish.

I think the use of XA is to span several systems and commit or rollback all operations within the XA transaction, right? So even spanning a JMS call and DB operations on the client and server side, right?

So, suppose I have a SessionBean:

[i]
@Stateless()
@Local({SimpleSessionBeanLocal.class})
public class SimpleSessionBean implements SimpleSessionBeanLocal{

        @EJB
        LoggingBeanLocal loggingBean;

        @Resource(mappedName = "jms/SimpleConnectionFactory")
        private ConnectionFactory connectionFactory;

        @Resource(mappedName = "jms/SimpleQueue")
        private Queue queue;
        
        @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
        public void sendMessage(String message) throws JMSException
        {
                String sessionID=new Date().toString();
                System.out.println("called putMessage @" + sessionID);
                
                [b]loggingBean.addLoggingMessage[/b]("Hi from putMessage 1 @" + sessionID);
        javax.jms.Connection connection;
                connection = connectionFactory.createConnection();
        javax.jms.Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);
        MessageProducer messageProducer = session.createProducer(queue);
        [b]loggingBean.addLoggingMessage[/b]("Message: " + message + "@" + sessionID);
        TextMessage txtMessage = session.createTextMessage();
        txtMessage.setText("Hello, simple JMS! @" + sessionID);
        [b]messageProducer.send(txtMessage);[/b]
                loggingBean.addLoggingMessage("Hi from putMessage 2 @" + sessionID);
        }
}
[/i]

As you can see, the sendMessage method is calling another SessionBean's method
[i]
        @TransactionAttribute(TransactionAttributeType.MANDATORY)
        public void addLoggingMessage(String message)
[/i]
which constructs a Enity and calls em.persist(...).
sendMessag() is also sending a TextMessage to a MDB:

[i]
@MessageDriven(mappedName = "jms/SimpleQueue")
public class SimpleMessageDrivenBean implements MessageListener {

        @EJB
        LoggingBeanLocal loggingBean;
        
    public SimpleMessageDrivenBean() {
    }
        
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void onMessage(Message message) {
        try {
                        System.out.println("[MDB] Got simple message: " + ((TextMessage)message).getText() + " @" + System.currentTimeMillis());
                        
                        [b]loggingBean.addLoggingMessage[/b]("Hi from simple MDB: " + ((TextMessage)message).getText());
                        //throw new NullPointerException("die!");
                } catch (JMSException e) {
                        e.printStackTrace();
                }
    }

}
[/i]

The queue and CF are configured as a local (embedded OpenMQ) and transacctionsupport=XATransaction.

So I'd expect that when an Exception is thrown either in the Session Bean or hte MDB, [b]everything[/b] is rolled back.

But what happens is that
- when I throw an exception in the SimpleSessionBean, the message is not sent to the MDB, and all database operations are rolled back
- when I throw an exception in the MDB, the database operations of the MDB are rolled back, but the database operations of the SimpleSessionBean are committed to the database. To be precise, they're already there when the MDBs onMessage is called.

What am I doing wrong?
Or do I expect too much of XA?

Best regards,

Matthias
[Message sent by forum member 'matthiasfraass' (matthias.fraass_at_tricoder.net)]

http://forums.java.net/jive/thread.jspa?messageID=381184