package org.opensource.clearpool.jta;
import java.util.HashSet;
import java.util.Set;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.opensource.clearpool.exception.TransactionException;
/**
* This is a bridge of UserTransaction and Transaction.
*
* @author xionghui
* @date 16.08.2014
* @version 1.0
*/
public class TransactionManagerImpl implements TransactionManager {
// the INSTANCE should be the front of the SINGLETON_MARK
private static final TransactionManagerImpl MANAGER = new TransactionManagerImpl();
// the SINGLETON_MARK make sure the TransactionManagerImpl is a singleton
private final static boolean SINGLETON_MARK;
static {
SINGLETON_MARK = true;
}
/**
* we should know that ThreadLocal is a WeakReference,so we should always set ThreadLocal in a
* field to in case it be collected.
*/
private static ThreadLocal<Transaction> txHolder = new ThreadLocal<Transaction>();
private Set<Transaction> suspendTx;
private int transactionTimeout;
private TransactionManagerImpl() {
// whenever we invoke the constructor by reflection,we throw a
// exception.
if (SINGLETON_MARK) {
throw new TransactionException("create TransactionManager illegal");
}
}
public static TransactionManagerImpl getManager() {
return MANAGER;
}
@Override
public void begin() throws NotSupportedException, SystemException {
Transaction action = txHolder.get();
if (action != null) {
throw new NotSupportedException("nested transaction is not supported");
}
action = new TransactionImpl(transactionTimeout);
txHolder.set(action);
}
@Override
public void commit() throws RollbackException, HeuristicMixedException,
HeuristicRollbackException, SecurityException, SystemException {
Transaction action = txHolder.get();
if (action == null) {
throw new IllegalStateException("this is no transaction held");
}
try {
action.commit();
} finally {
txHolder.set(null);
}
}
@Override
public int getStatus() throws SystemException {
Transaction action = txHolder.get();
if (action == null) {
return Status.STATUS_NO_TRANSACTION;
}
return action.getStatus();
}
@Override
public Transaction getTransaction() throws SystemException {
Transaction tx = txHolder.get();
if (tx != null) {
return new TransactionAdapter(tx);
}
return null;
}
@Override
public void resume(Transaction transaction) throws InvalidTransactionException, SystemException {
if (!(transaction instanceof TransactionAdapter) || this.suspendTx == null
|| !this.suspendTx.remove(transaction)) {
throw new InvalidTransactionException("the transaction is invalid");
}
Transaction tx = ((TransactionAdapter) transaction).getTx();
Transaction current = txHolder.get();
if (current != null) {
throw new IllegalStateException("the thread already has a transaction");
}
((TransactionImpl) tx).resume();
txHolder.set(tx);
}
@Override
public void rollback() throws SecurityException, SystemException {
Transaction action = txHolder.get();
if (action == null) {
throw new TransactionException("this is no transaction holding");
}
try {
action.rollback();
} finally {
txHolder.set(null);
}
}
@Override
public void setRollbackOnly() throws SystemException {
Transaction action = txHolder.get();
if (action == null) {
throw new IllegalStateException("this is no transaction started");
}
action.setRollbackOnly();
}
@Override
public void setTransactionTimeout(int i) throws SystemException {
if (i < 0) {
throw new SystemException("the parameter shouldn't be nagative");
}
this.transactionTimeout = i;
Transaction action = txHolder.get();
if (action != null && action instanceof TransactionImpl) {
((TransactionImpl) action).setTransactionTimeout(i);
}
}
@Override
public Transaction suspend() throws SystemException {
Transaction tx = txHolder.get();
if (tx != null) {
if (this.suspendTx == null) {
this.suspendTx = new HashSet<Transaction>();
}
((TransactionImpl) tx).suspend();
TransactionAdapter adapter = new TransactionAdapter(tx);
this.suspendTx.add(adapter);
txHolder.set(null);
return adapter;
}
return null;
}
}