User: sparre  
  Date: 01/04/29 01:12:52

  Added:       src/main/org/jboss/tm/usertx/client
                        ClientUserTransaction.java
                        ClientUserTransactionObjectFactory.java
  Log:
  Added UserTransaction support for stand-alone clients.
  
  Revision  Changes    Path
  1.1                  
jboss/src/main/org/jboss/tm/usertx/client/ClientUserTransaction.java
  
  Index: ClientUserTransaction.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.tm.usertx.client;
  
  import java.io.Serializable;
  
  import java.rmi.RemoteException;
  
  import java.util.LinkedList;
  
  import javax.naming.InitialContext;
  import javax.naming.Reference;
  import javax.naming.Referenceable;
  import javax.naming.NamingException;
  
  import javax.transaction.UserTransaction;
  import javax.transaction.Transaction;
  import javax.transaction.Status;
  import javax.transaction.NotSupportedException;
  import javax.transaction.SystemException;
  import javax.transaction.RollbackException;
  import javax.transaction.HeuristicMixedException;
  import javax.transaction.HeuristicRollbackException;
  
  import org.jboss.tm.TransactionPropagationContextFactory;
  
  import org.jboss.ejb.plugins.jrmp.interfaces.GenericProxy;
  
  import org.jboss.tm.usertx.interfaces.UserTransactionSession;
  import org.jboss.tm.usertx.interfaces.UserTransactionSessionFactory;
  
  /**
   *  The client-side UserTransaction implementation.
   *  This will delegate all UserTransaction calls to the server.
   *
   *  <em>Warning:</em> This is only for stand-alone clients that do
   *  not have their own transaction service. No local work is done in
   *  the context of transactions started here, only work done in beans
   *  at the server. Instantiating objects of this class outside the server
   *  will change the JRMP GenericProxy so that outgoing calls use the
   *  propagation contexts of the transactions started here.
   *
   *  @author <a href="mailto:[EMAIL PROTECTED]";>Ole Husgaard</a>
   *  @version $Revision: 1.1 $
   */
  public class ClientUserTransaction
     implements UserTransaction,
                TransactionPropagationContextFactory,
                Referenceable,
                Serializable
  {
     // Static --------------------------------------------------------
  
     /**
      *  Our singleton instance.
      */
     private static ClientUserTransaction singleton = null;
  
     /**
      *  Return a reference to the singleton instance.
      */
     public static ClientUserTransaction getSingleton()
     {
        if (singleton == null)
           singleton = new ClientUserTransaction();
        return singleton;
     }
  
  
     // Constructors --------------------------------------------------
  
     /**
      *  Create a new instance.
      */
     private ClientUserTransaction()
     {
        // See if we have a local TM
        try {
           new InitialContext().lookup("java:/TransactionManager");
  
           // This instance lives in the server.
           isInServer = true;
        } catch (NamingException ex) {
           // This instance lives in a stand-alone client.
           isInServer = false;
  
           // No local TM: Set TPC Factory on GenericProxy.
           GenericProxy.setTPCFactory(this);
        }
     }
  
     // Public --------------------------------------------------------
  
     //
     // implements interface UserTransaction
     //
  
     public void begin()
        throws NotSupportedException, SystemException
     {
        if (isInServer)
           throw new SystemException("Cannot use this in the server.");
  
        ThreadInfo info = getThreadInfo();
  
        try {
           Object tpc = getSession().begin(info.getTimeout());
           info.push(tpc);
        } catch (SystemException e) {
           throw e;
        } catch (RemoteException e) {
           // destroy session gone bad.
           destroySession();
           throw new SystemException(e.toString());
        } catch (Exception e) {
           throw new SystemException(e.toString());
        }
     }
  
     public void commit()
        throws RollbackException,
               HeuristicMixedException,
               HeuristicRollbackException,
               SecurityException,
               IllegalStateException,
               SystemException
     {
        if (isInServer)
           throw new SystemException("Cannot use this in the server.");
  
        ThreadInfo info = getThreadInfo();
  
        try {
           getSession().commit(info.getTpc());
           info.pop();
        } catch (RollbackException e) {
           info.pop();
           throw e;
        } catch (HeuristicMixedException e) {
           throw e;
        } catch (HeuristicRollbackException e) {
           throw e;
        } catch (SecurityException e) {
           throw e;
        } catch (SystemException e) {
           throw e;
        } catch (IllegalStateException e) {
           throw e;
        } catch (RemoteException e) {
           // destroy session gone bad.
           destroySession();
           throw new SystemException(e.toString());
        } catch (Exception e) {
           throw new SystemException(e.toString());
        }
     }
  
     public void rollback()
        throws SecurityException,
               IllegalStateException,
               SystemException
     {
        if (isInServer)
           throw new SystemException("Cannot use this in the server.");
  
        ThreadInfo info = getThreadInfo();
  
        try {
           getSession().rollback(info.getTpc());
           info.pop();
        } catch (SecurityException e) {
           throw e;
        } catch (SystemException e) {
           throw e;
        } catch (IllegalStateException e) {
           throw e;
        } catch (RemoteException e) {
           // destroy session gone bad.
           destroySession();
           throw new SystemException(e.toString());
        } catch (Exception e) {
           throw new SystemException(e.toString());
        }
     }
  
     public void setRollbackOnly()
        throws IllegalStateException,
               SystemException
     {
        if (isInServer)
           throw new SystemException("Cannot use this in the server.");
  
        ThreadInfo info = getThreadInfo();
  
        try {
           getSession().setRollbackOnly(info.getTpc());
        } catch (SystemException e) {
           throw e;
        } catch (IllegalStateException e) {
           throw e;
        } catch (RemoteException e) {
           // destroy session gone bad.
           destroySession();
           throw new SystemException(e.toString());
        } catch (Exception e) {
           throw new SystemException(e.toString());
        }
     }
  
     public int getStatus()
        throws SystemException
     {
        if (isInServer)
           throw new SystemException("Cannot use this in the server.");
  
        ThreadInfo info = getThreadInfo();
        Object tpc = info.getTpc();
  
        if (tpc == null)
           return Status.STATUS_NO_TRANSACTION;
  
        try {
           return getSession().getStatus(tpc);
        } catch (SystemException e) {
           throw e;
        } catch (RemoteException e) {
           // destroy session gone bad.
           destroySession();
           throw new SystemException(e.toString());
        } catch (Exception e) {
           throw new SystemException(e.toString());
        }
     }
  
     public void setTransactionTimeout(int seconds)
        throws SystemException
     {
        if (isInServer)
           throw new SystemException("Cannot use this in the server.");
  
        getThreadInfo().setTimeout(seconds);
     }
  
  
     //
     // implements interface TransactionPropagationContextFactory
     //
  
     public Object getTransactionPropagationContext()
     {
        return getThreadInfo().getTpc();
     }
   
     public Object getTransactionPropagationContext(Transaction tx)
     {
        // No need to implement in a stand-alone client.
        throw new InternalError("Should not have been used.");
     }
   
  
     //
     // implements interface Referenceable
     //
  
     public Reference getReference()
        throws NamingException
     {
        Reference ref = new 
Reference("org.jboss.tm.usertx.client.ClientUserTransaction",
                                      
"org.jboss.tm.usertx.client.ClientUserTransactionObjectFactory", 
                                      null);
  
        return ref;
     }
  
  
     // Private -------------------------------------------------------
  
     /**
      *  Flag that this instance is living in the server.
      *  Instances living in the server VM cannot be used.
      */
     private boolean isInServer;
  
     /**
      *  The RMI remote interface to the real tx service
      *  session at the server.
      */
     private UserTransactionSession session = null;
  
     /**
      *  Storage of per-thread information used here.
      */
     private transient ThreadLocal threadInfo = new ThreadLocal();
  
  
     /**
      *  Create a new session.
      */
     private synchronized void createSession()
     {
        // Destroy any old session.
        if (session != null)
           destroySession();
  
        try {
           // Get a reference to the UT session factory.
           UserTransactionSessionFactory factory;
           factory = (UserTransactionSessionFactory)new 
InitialContext().lookup("UserTransactionSessionFactory");
           // Call factory to get a UT session.
           session = factory.newInstance();
        } catch (Exception ex) {
           throw new RuntimeException("UT factory lookup failed: " + ex);
        }
     }
  
     /**
      *  Destroy the current session.
      */
     private synchronized void destroySession()
     {
        if (session != null) {
           try {
              session.destroy();
           } catch (RemoteException ex) {
             // Ignore.
           }
           session = null;
        }
     }
  
     /**
      *  Get the session. This will create a session,
      *  if one does not already exist.
      */
     private synchronized UserTransactionSession getSession()
     {
        if (session == null)
           createSession();
        return session;
     }
  
  
     /**
      *  Return the per-thread information, possibly creating it if needed.
      */
     private ThreadInfo getThreadInfo()
     {
        ThreadInfo ret = (ThreadInfo)threadInfo.get();
  
        if (ret == null) {
           ret = new ThreadInfo();
           threadInfo.set(ret);
        }
  
        return ret;
     }
  
  
     // Inner classes -------------------------------------------------
  
     /**
      *  Per-thread data holder class.
      *  This stores the stack of TPCs for the transactions started by
      *  this thread.
      */
     private class ThreadInfo
     {
        /**
         *  A stack of TPCs for transactions started by this thread.
         *  If the underlying service does not support nested
         *  transactions, its size is never greater than 1.
         *  Last element of the list denotes the stack top.
         */
        private LinkedList tpcStack = new LinkedList();
  
        /**
         *  The timeout value (in seconds) for new transactions started
         *  by this thread.
         */
        private int timeout = 0;
  
        /**
         *  Override to terminate any transactions that the
         *  thread may have forgotten.
         */
        protected void finalize()
           throws Throwable
        {
           try {
              while (!tpcStack.isEmpty()) {
                 Object tpc = getTpc();
                 pop();
  
                 try {
                    getSession().rollback(tpc);
                 } catch (Exception ex) {
                    // ignore
                 }
              }
           } catch (Throwable t) {
              // ignore
           }
           super.finalize();
        }
  
        /**
         *  Push the TPC of a newly started transaction on the stack.
         */
        void push(Object tpc)
        {
           tpcStack.addLast(tpc);
        }
  
        /**
         *  Pop the TPC of a newly terminated transaction from the stack.
         */
        void pop()
        {
           tpcStack.removeLast();
        }
  
        /**
         *  Get the TPC at the top of the stack.
         */
        Object getTpc()
        {
           return (tpcStack.isEmpty()) ? null : tpcStack.getLast();
        }
  
        /**
         *  Return the default transaction timeout in seconds to use for
         *  new transactions started by this thread.
         *  A value of <code>0</code> means that a default timeout value
         *  should be used.
         */
        int getTimeout()
        {
           return timeout;
        }
  
        /**
         *  Set the default transaction timeout in seconds to use for
         *  new transactions started by this thread.
         */
        void setTimeout(int seconds)
        {
           timeout = seconds;
        }
     }
  
  }
  
  
  
  1.1                  
jboss/src/main/org/jboss/tm/usertx/client/ClientUserTransactionObjectFactory.java
  
  Index: ClientUserTransactionObjectFactory.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
   
  package org.jboss.tm.usertx.client;
  
  import java.util.Hashtable;
  
  import javax.naming.Context;
  import javax.naming.Reference;
  import javax.naming.Name;
  import javax.naming.spi.ObjectFactory;
  
  
  /**
   *  This is an object factory for producing client
   *  UserTransactions.
   *  usage for standalone clients.
   *      
   *  @author <a href="mailto:[EMAIL PROTECTED]";>Ole Husgaard</a>
   *  @version $Revision: 1.1 $
   */
  public class ClientUserTransactionObjectFactory
     implements ObjectFactory
  {
     public Object getObjectInstance(Object obj, Name name,
                                     Context nameCtx, Hashtable environment)
        throws Exception
     {
  System.err.println("ClientUserTransactionServiceFactory.getObjectInstance() 
entered.");
        Reference ref = (Reference)obj;
   
        if (ref.getClassName().equals(ClientUserTransaction.class.getName())) {
  System.err.println("ClientUserTransactionServiceFactory.getObjectInstance() #1.");
           return ClientUserTransaction.getSingleton();
        }
  System.err.println("ClientUserTransactionServiceFactory.getObjectInstance() 
returning null.");
        return null;
     }
  }
  
  
  
  

_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to