9 Replies Latest reply on Jul 3, 2003 3:02 AM by adrian.brock

    Third party transaction manager

    halldori

      Hello

      I want to use third party transaction manager (JOTM) as well as JBoss message queue , participating in a XATransaction. I am wondering how to do that. Do I simply look up the XAConnection factory and create a connection? How does the Transaction manager in that case know of the queue?

      Should I perhaps be using the JMS XA resource adapter, or is that used internally by JBoss?

      Regards, Halldor

        • 1. Re: Third party transaction manager
          halldori

          I also seem to have problem with getting XATransactions to work for a simple Java Application. I simply get a UserTransaction, start transaction, get the XAConnectionFactory, create the sessions/senders and send the message. At that point I get a JMS Exception with the message "Invalid transaction ID". What seems to be the problem is that when the addMessage method of SpyXAResourceManager is called there is no state for the transaction. So in effect the method startTx is never called in SpyXAResourceManager. That is because by default the SpyXASession does not do so:

          SpySession( Connection conn, boolean trans, int acknowledge, boolean xaSession )
          {
          connection = conn;
          transacted = trans;
          acknowledgeMode = acknowledge;
          if ( xaSession )
          {
          spyXAResource = new SpyXAResource( this );
          }

          running = true;
          closed = false;
          consumers = new HashSet();

          //Have a TX ready with the resource manager.
          if ( spyXAResource == null && transacted )
          {
          currentTransactionId = connection.spyXAResourceManager.startTx();
          if (log.isTraceEnabled())
          {
          log.trace("Current transaction id: " + currentTransactionId);
          }
          }
          }

          Anyway has anybody got a clue. I appended the code:

          public static void main(String[] args)
          {
          UserTransaction tx = null;
          try
          {
          TestBookingFactory.initializeForTest();
          log.info("JMSConnectionHelper.JMSConnectionHelper");
          log.debug("JMSConnectionHelper.JMSConnectionHelper");
          Hashtable env = new Hashtable();
          String timeout = System.getProperties().getProperty("jnp.timeout");
          if (timeout == null)
          {
          log.fatal("JMSConnectionHelper:JMSConnectionHelper: jnp.timeout property missing");
          }
          String sotimeout = System.getProperties().getProperty("jnp.sotimeout");
          if (sotimeout == null)
          {
          log.fatal("JMSConnectionHelper:JMSConnectionHelper: jnp.sotimeout property missing");
          }
          String host = System.getProperties().getProperty("JMS.PROVIDER_URL");
          if (host == null)
          {
          log.fatal("JMSConnectionHelper:JMSConnectionHelper: JMS.PROVIDER_URL property missing");
          }
          String contextFactory = System.getProperties().getProperty("JMS.INITIAL_CONTEXT_FACTORY");
          if (contextFactory == null)
          {
          log.fatal("JMSConnectionHelper:JMSConnectionHelper: JMS.INITIAL_CONTEXT_FACTORY property missing");
          }
          String queueFactory = System.getProperties().getProperty("JMS.ConnectionFactoryName");
          log.debug(queueFactory);
          if (queueFactory == null)
          {
          log.fatal("JMSConnectionHelper:JMSConnectionHelper: JMS.ConnectionFactoryName property missing");
          }
          String queueName = System.getProperties().getProperty("JMS.CalidrisQueue");
          if (queueName == null)
          {
          log.fatal("JMSConnectionHelper:JMSConnectionHelper: JMS.CalidrisQueue property missing");
          }
          env.put("jnp.timeout", timeout);
          env.put("jnp.sotimeout", sotimeout);
          env.put(Context.PROVIDER_URL, host);
          env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
          InitialContext iniCtx = new InitialContext(env);
          tx = (UserTransaction) iniCtx.lookup("UserTransaction");

          tx.begin();

          Object tmp = iniCtx.lookup("XAConnectionFactory");
          XAQueueConnectionFactory qcf = (XAQueueConnectionFactory) tmp;
          JMSHashMapEntry defaultJMSQueue = new JMSHashMapEntry();
          defaultJMSQueue.connection = qcf.createXAQueueConnection();
          defaultJMSQueue.queue = (Queue) iniCtx.lookup(queueName);
          defaultJMSQueue.session = defaultJMSQueue.connection.createXAQueueSession();
          defaultJMSQueue.sender = defaultJMSQueue.session.getQueueSession().createSender(defaultJMSQueue.queue);
          defaultJMSQueue.connection.start();

          Message m = defaultJMSQueue.session.createTextMessage("Kalli Halli");
          defaultJMSQueue.sender.send(m);

          }
          catch (Exception ne)
          {
          log.error("TestClass.main:", ne);
          ne.printStackTrace();
          }
          System.out.println("success!");
          try
          {
          tx.commit();
          }
          catch (RollbackException e)
          {
          log.error("TestClass.main:", e);
          }
          catch (HeuristicMixedException e)
          {
          log.error("TestClass.main:", e);
          }
          catch (HeuristicRollbackException e)
          {
          log.error("TestClass.main:", e);
          }
          catch (SecurityException e)
          {
          log.error("TestClass.main:", e);
          }
          catch (IllegalStateException e)
          {
          log.error("TestClass.main:", e);
          }
          catch (SystemException e)
          {
          log.error("TestClass.main:", e);
          }
          }

          • 2. Re: Third party transaction manager

            You have to tell jboss about the TM.
            The basic mechanism is to bind it java:/TransactionManager.

            For 3.2 you will also need to provide an MBean at
            jboss.org:service=TransactionManager with an attribute
            which is the TM instance.

            Similar things are required for the transaction propagation contexts of UserTransactions.

            Regards,
            Adrian

            • 3. Re: Third party transaction manager
              halldori

              ok, but I still haven't figured out how to to a XATransaction in the java application, still get the same error!... any clue?

              • 4. Re: Third party transaction manager

                You cannot use UserTranscations to enlist XAResources.
                You need a full transaction from a transaction manager.
                Then you get into the domain of DTMs.

                Regards,
                Adrian

                • 5. Re: Third party transaction manager
                  ioparra

                  Try your code, but don't assume XA exists(except for the XAConnection). IE.

                  XAConnection.createQueueSession(true,..);

                  See if that does the trick. Just a guess really. I remember making this work... somehow.

                  -Ivan

                  • 6. Re: Third party transaction manager
                    halldori

                    Thanks for your answer.

                    Your tip did work if I additionally call the createQueueConnection on the XAConnectionFactory, but not the createXAQueueConnection.

                    The only thing I am wondering is if the transaction is really using the two-phase commit.

                    Maybe it is, in which case these createXAQueueConnection are just middleware methods, not to be used by applications. Is any expert on JMS here?

                    • 7. Re: Third party transaction manager
                      halldori

                      I just saw approxmately the same question on forum.java.sun.com:

                      http://forum.java.sun.com/thread.jsp?forum=29&thread=337323

                      Does the JMS resource adapter have anything to do with it...

                      • 8. Re: Third party transaction manager
                        ioparra

                        You are right to say that the XA calls are not for the application developer. For my understanding, JMS to JBoss is just another JCA Adaptor. Because of that, it is the TransactionManager/Security Manager that are doing the xa calls. When you Call UserTransaction.begin, you have a handle to the TM. When you call createQueueSession on your connection, the TM/SM uses your context to grab the correct connection. In your example, createConnection should:

                        1)Go to the ConnectionFactory and grab an XAConnection
                        2)From that XAConnection, grab the XAResource and enlist that resource with the current transaction
                        3)return the Connection from XAConnection.getConnection.

                        It would make sense that your getXAConnection would fail because the TM never had an opportunity to enlist that connection to the transaction.

                        Fun stuff. To answer your question, the JMXResourceAdapter is the JCA Adapter. It is the one that provides the ManagedConnection to the JCA framework. In short, you shouldn't need direct access to XAstuff. If you want to make your code even cleaner, remove the XAConnectionFactory/XAConnection dependence and allow the JNDI name decide to use XA or not. This way you can switch from XA to non-XA by simply grabbing a a different factory.

                        Cheers!
                        -Ivan


                        • 9. Re: Third party transaction manager

                          The JCA Adaptor is just doing what you can do
                          programatically, but it is not recommended outside
                          an application server.

                          You need a transaction manager.
                          1) begin a transaction
                          2) start an XASession
                          3) enlist the session's xaresource in the transaction

                          Regards,
                          Adrian