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