package org.jboss.tm.usertx.client;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.LinkedList;
import java.util.Hashtable;
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.tm.usertx.interfaces.UserTransactionSession;
import org.jboss.tm.usertx.interfaces.UserTransactionSessionFactory;
import org.jboss.naming.NamingContextFactory;
public class ClientUserTransaction
implements UserTransaction,
TransactionPropagationContextFactory,
Referenceable,
Serializable
{
private static final long serialVersionUID = 1747989355209242872L;
private static ClientUserTransaction singleton = null;
public static ClientUserTransaction getSingleton()
{
if (singleton == null)
singleton = new ClientUserTransaction();
return singleton;
}
private ClientUserTransaction()
{
}
public void begin()
throws NotSupportedException, SystemException
{
ThreadInfo info = getThreadInfo();
try
{
Object tpc = getSession().begin(info.getTimeout());
info.push(tpc);
}
catch (SystemException e)
{
throw e;
}
catch (RemoteException e)
{
destroySession();
throw new SystemException(e.toString());
}
catch (Exception e)
{
throw new SystemException(e.toString());
}
}
public void commit()
throws RollbackException,
HeuristicMixedException,
HeuristicRollbackException,
SecurityException,
IllegalStateException,
SystemException
{
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)
{
destroySession();
throw new SystemException(e.toString());
}
catch (Exception e)
{
throw new SystemException(e.toString());
}
}
public void rollback()
throws SecurityException,
IllegalStateException,
SystemException
{
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)
{
destroySession();
throw new SystemException(e.toString());
}
catch (Exception e)
{
throw new SystemException(e.toString());
}
}
public void setRollbackOnly()
throws IllegalStateException,
SystemException
{
ThreadInfo info = getThreadInfo();
try
{
getSession().setRollbackOnly(info.getTpc());
}
catch (SystemException e)
{
throw e;
}
catch (IllegalStateException e)
{
throw e;
}
catch (RemoteException e)
{
destroySession();
throw new SystemException(e.toString());
}
catch (Exception e)
{
throw new SystemException(e.toString());
}
}
public int getStatus()
throws SystemException
{
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)
{
destroySession();
throw new SystemException(e.toString());
}
catch (Exception e)
{
throw new SystemException(e.toString());
}
}
public void setTransactionTimeout(int seconds)
throws SystemException
{
getThreadInfo().setTimeout(seconds);
}
public Object getTransactionPropagationContext()
{
return getThreadInfo().getTpc();
}
public Object getTransactionPropagationContext(Transaction tx)
{
throw new InternalError("Should not have been used.");
}
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 UserTransactionSession session = null;
private transient ThreadLocal threadInfo = new ThreadLocal();
private synchronized void createSession()
{
if (session != null)
destroySession();
try
{
UserTransactionSessionFactory factory;
Hashtable env = (Hashtable) NamingContextFactory.lastInitialContextEnv.get();
InitialContext ctx = new InitialContext(env);
factory = (UserTransactionSessionFactory) ctx.lookup("UserTransactionSessionFactory");
session = factory.newInstance();
}
catch (Exception ex)
{
throw new RuntimeException("UT factory lookup failed", ex);
}
}
private synchronized void destroySession()
{
if (session != null)
{
try
{
session.destroy();
}
catch (RemoteException ex)
{
}
session = null;
}
}
private synchronized UserTransactionSession getSession()
{
if (session == null)
createSession();
return session;
}
private ThreadInfo getThreadInfo()
{
ThreadInfo ret = (ThreadInfo) threadInfo.get();
if (ret == null)
{
ret = new ThreadInfo();
threadInfo.set(ret);
}
return ret;
}
private class ThreadInfo
{
private LinkedList tpcStack = new LinkedList();
private int timeout = 0;
protected void finalize()
throws Throwable
{
try
{
while (!tpcStack.isEmpty())
{
Object tpc = getTpc();
pop();
try
{
getSession().rollback(tpc);
}
catch (Exception ex)
{
}
}
}
catch (Throwable t)
{
}
super.finalize();
}
void push(Object tpc)
{
tpcStack.addLast(tpc);
}
void pop()
{
tpcStack.removeLast();
}
Object getTpc()
{
return (tpcStack.isEmpty()) ? null : tpcStack.getLast();
}
int getTimeout()
{
return timeout;
}
void setTimeout(int seconds)
{
timeout = seconds;
}
}
}