10 Replies Latest reply on Aug 20, 2008 1:35 PM by timfox

    XA datasource with JBM problem

      Following the advice in the wiki page: http://wiki.jboss.org/wiki/JBMXADataSource,

      I've almost got it working, except for the intended behavior, which I'm not seeing.

      What I want is for a server component, when a certain event occurs, to send a message. However, if the transaction that

      is active when the event occurs is rolled back, the send of the message should be rolled back, as well. I assume that

      this is a legitimate goal.

      Problem is, I am not seeing this behavior. In my test, the originating Tx is rolled back, but the message is still

      delivered.

      Now for the specifics:

      The server component involved is an entity EJB, and more specifically, the code that is doing the messaging is a custom

      Interceptor written for the entity. The purpose is to intercept certain mutator method invocations on the bean, and to

      log them to a message queue. However, if the transaction is rolled back, so are the mutations, and so should the log

      messages.

      The code is using the JMS JCA resource adaptor named java:/JmsXA to create the JMS connection. Is there anything else I

      need to do to get the destination enlisted as an XA resource with the EJB container's TransactionManager?

      -Peris

        • 1. Re: XA datasource with JBM problem
          ataylor

          firstly, what versions are you using. secondly, if you think its not working as required can you provide a test case.

          • 2. Re: XA datasource with JBM problem

            I am on 4.0.2

            Here is the Interceptor:


            package test;

            import org.jboss.invocation.Invocation;
            import org.jboss.ejb.Interceptor;
            import org.jboss.ejb.Container;
            import org.jboss.ejb.EntityContainer;

            import javax.naming.Context;
            import javax.naming.InitialContext;
            import javax.jms.*;
            import javax.ejb.EJBObject;
            import javax.transaction.TransactionManager;
            import java.lang.reflect.Method;
            import java.util.Arrays;

            public
            class TestInterceptor implements Interceptor {

            public
            void setNext(Interceptor next) {
            this.next = next;
            }

            public
            Interceptor getNext() {
            return next;
            }

            public
            void setContainer(Container container) {
            this.container = (EntityContainer)container;
            }

            public
            void create() throws Exception {
            name = container.getBeanMetaData().getEjbName();
            if (!name.equals("Foo")) // only operate on entity Foo
            return;
            Context ctx = new InitialContext();
            QueueConnectionFactory qcf = (QueueConnectionFactory)ctx.lookup("java:/JmsXA");
            conn = qcf.createQueueConnection();
            queue = (Queue)ctx.lookup("queue/DDSListenerQ");
            session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
            conn.start();
            }

            public
            Object invokeHome(Invocation invocation) throws Exception {
            Object returnValue = getNext().invokeHome(invocation);
            return returnValue;
            }

            public
            Object invoke(Invocation invocation) throws Exception {
            Object returnValue = getNext().invoke(invocation);
            if (!name.equals("Foo"))
            return returnValue;
            Method method = invocation.getMethod();
            if (method != null) {
            String mname = method.getName();
            if (mname.startsWith("set")) {
            QueueSender sender = session.createSender(queue);
            TextMessage tm = session.createTextMessage(invocation.getId()+",mname.substring(3),"+invocation.getArguments()[0]);
            sender.send(tm);
            sender.close();
            }
            }
            return returnValue;
            }

            public
            void start() throws Exception {
            }

            public
            void stop() {
            }

            public
            void destroy() {
            //session.close();
            //conn.close();
            }

            private Interceptor next;
            private EntityContainer container;
            private String name;
            private QueueConnection conn;
            private QueueSession session;
            private Queue queue;

            }


            Here is the remote client test driver snippet: (there is an EJB wrapper framework in place; the Context object wraps UserTransaction, FooHomeRemote, etc.)

            Context ctx = ContextRemoteImpl.instance();
            ctx.begin();
            Foo foo = ctx.FooFactory().findByOID(333l);
            foo.setBar("Bat");
            ctx.rollback();

            Finally, here is an MDB that listens to the Queue, and receives a message, even though the client rolls back:

            package test;

            import javax.ejb.MessageDrivenBean;
            import javax.ejb.MessageDrivenContext;
            import javax.ejb.EJBException;
            import javax.jms.MessageListener;
            import javax.jms.Message;

            public
            class TestMDBImpl implements MessageDrivenBean, MessageListener {

            public
            void ejbCreate() {
            }

            public
            void setMessageDrivenContext(MessageDrivenContext mdc) {
            }

            public
            void onMessage(Message message) {
            System.err.println("GOT MESSAGE:"+message);
            }


            public
            void ejbRemove() throws EJBException {\
            }

            }

            • 3. Re: XA datasource with JBM problem
              ataylor

              Which version of JBoss Messaging are you using, can you try with the latest versions (jboss 4.2.2 with JBM 1.4) to make sure it is still a problem.

              • 4. Re: XA datasource with JBM problem
                timfox

                Looks like you're creating a non transacted session.

                There are lots of examples around of doing this correctly. I suggest you find one of those and copy it.

                • 5. Re: XA datasource with JBM problem

                  So can I take it that what I am trying to do should be doable?

                  ataylor: I am using what comes bundled with 4.0.2. I can try moving to 4.2.2 just to know, if you're saying that this pattern is not supported under 4.0.2, but 4.0.2 is still our production environment.

                  timfox: The example I used came from the 4.0.2 admin guide. Since my last post, I noticed the transacted-session problem, said "aha!", and changed the first argument to createQueueSession() to true. This had no effect :{(>

                  Where might I find working examples of this, please? In the forum? I've read the admin guide, the wiki, the users guide, and failed.

                  I didn't really expect to find a working example of an Interceptor, so my first question is "should this work?". The JBMXADataSource wiki entry leads me to believe that can; it just lacks a working example.

                  • 6. Re: XA datasource with JBM problem
                    timfox

                    Ah I just noticed you're using an interceptor, I thought you were using an EJB which is an extremely common pattern.

                    The JMS JCA resource adapter requires a managed environment (read servlet or EJB) otherwise transaction won't get enlisted automatically. But this is app server stuff and not part of JBoss Messaging.

                    I've never seen anyone do what you're doing before so no idea whether it would work or not. Best to ask the JCA/AS guys. As I say, none of this is part of JBM.

                    • 7. Re: XA datasource with JBM problem

                      So your saying the enlistment of the JMS Session as an XA resource has nothing to do with JBM (or is completely orthogonal to it)? If not, is there anything explicit I can do to make this work?

                      Just curious: the connection factory name java:/JmsXA I'm using returns a JmsConnectionFactory. Snooping the source I noticed class JmsManagedConnectionFactory. What would be the purpose of this?

                      • 8. Re: XA datasource with JBM problem
                        timfox

                         

                        "perisb" wrote:
                        So your saying the enlistment of the JMS Session as an XA resource has nothing to do with JBM (or is completely orthogonal to it)?


                        Yes, the resource enlistment is done by the JCA adapter, not JBM.


                        Just curious: the connection factory name java:/JmsXA I'm using returns a JmsConnectionFactory. Snooping the source I noticed class JmsManagedConnectionFactory. What would be the purpose of this?


                        That's a JCA resource adapter. The JCA spec will explain what all those things mean.

                        The JCA adapter is not part of JBM, it's handled by the JCA team (which is part of the AS).

                        • 9. Re: XA datasource with JBM problem
                          timfox
                          • 10. Re: XA datasource with JBM problem
                            timfox

                             

                            "perisb" wrote:
                            If not, is there anything explicit I can do to make this work?


                            If you can get a reference to the transaction, then you can always enlist the resources yourself.

                            I.e. don't use JmsXA, use XAConnectionFactory, create an XAConnection, create an XASession, and enlist the XAResource in the JTA tx manually.

                            The tx should be associated to the current thread. Have a look at the JTA api to see how to do this.