package org.argeo.util.transaction; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; /** * Simple implementation of an XA transaction manager. */ public class SimpleTransactionManager // implements TransactionManager, UserTransaction implements WorkControl, WorkTransaction { private ThreadLocal> current = new ThreadLocal>(); private Map> knownTransactions = Collections .synchronizedMap(new HashMap>()); private TransactionStatusAdapter tsa = new JtaStatusAdapter(); // private SyncRegistry syncRegistry = new SyncRegistry(); /* * WORK IMPLEMENTATION */ @Override public T required(Callable work) { T res; begin(); try { res = work.call(); commit(); } catch (Exception e) { rollback(); throw new SimpleRollbackException(e); } return res; } @Override public WorkContext getWorkContext() { return new WorkContext() { @Override public void registerXAResource(XAResource resource, String recoveryId) { getTransaction().enlistResource(resource); } }; } /* * WORK TRANSACTION IMPLEMENTATION */ @Override public boolean isNoTransactionStatus() { return tsa.getNoTransactionStatus().equals(getStatus()); } /* * JTA IMPLEMENTATION */ public void begin() // throws NotSupportedException, SystemException { if (getCurrent() != null) throw new UnsupportedOperationException("Nested transactions are not supported"); SimpleTransaction transaction = new SimpleTransaction(this, tsa); knownTransactions.put(transaction.getXid(), transaction); current.set(transaction); } public void commit() // throws RollbackException, HeuristicMixedException, HeuristicRollbackException, // SecurityException, IllegalStateException, SystemException { if (getCurrent() == null) throw new IllegalStateException("No transaction registered with the current thread."); getCurrent().commit(); } public int getStatus() // throws SystemException { if (getCurrent() == null) return tsa.getNoTransactionStatus(); return getTransaction().getStatus(); } public SimpleTransaction getTransaction() // throws SystemException { return getCurrent(); } protected SimpleTransaction getCurrent() // throws SystemException { SimpleTransaction transaction = current.get(); if (transaction == null) return null; Integer status = transaction.getStatus(); if (status.equals(tsa.getCommittedStatus()) || status.equals(tsa.getRolledBackStatus())) { current.remove(); return null; } return transaction; } void unregister(Xid xid) { knownTransactions.remove(xid); } public void resume(SimpleTransaction tobj) // throws InvalidTransactionException, IllegalStateException, SystemException { if (getCurrent() != null) throw new IllegalStateException("Transaction " + current.get() + " already registered"); current.set(tobj); } public void rollback() // throws IllegalStateException, SecurityException, SystemException { if (getCurrent() == null) throw new IllegalStateException("No transaction registered with the current thread."); getCurrent().rollback(); } public void setRollbackOnly() // throws IllegalStateException, SystemException { if (getCurrent() == null) throw new IllegalStateException("No transaction registered with the current thread."); getCurrent().setRollbackOnly(); } public void setTransactionTimeout(int seconds) // throws SystemException { throw new UnsupportedOperationException(); } public SimpleTransaction suspend() // throws SystemException { SimpleTransaction transaction = getCurrent(); current.remove(); return transaction; } // public TransactionSynchronizationRegistry getTsr() { // return syncRegistry; // } // // private class SyncRegistry implements TransactionSynchronizationRegistry { // @Override // public Object getTransactionKey() { // try { // SimpleTransaction transaction = getCurrent(); // if (transaction == null) // return null; // return getCurrent().getXid(); // } catch (SystemException e) { // throw new IllegalStateException("Cannot get transaction key", e); // } // } // // @Override // public void putResource(Object key, Object value) { // throw new UnsupportedOperationException(); // } // // @Override // public Object getResource(Object key) { // throw new UnsupportedOperationException(); // } // // @Override // public void registerInterposedSynchronization(Synchronization sync) { // throw new UnsupportedOperationException(); // } // // @Override // public int getTransactionStatus() { // try { // return getStatus(); // } catch (SystemException e) { // throw new IllegalStateException("Cannot get status", e); // } // } // // @Override // public boolean getRollbackOnly() { // try { // return getStatus() == Status.STATUS_MARKED_ROLLBACK; // } catch (SystemException e) { // throw new IllegalStateException("Cannot get status", e); // } // } // // @Override // public void setRollbackOnly() { // try { // getCurrent().setRollbackOnly(); // } catch (Exception e) { // throw new IllegalStateException("Cannot set rollback only", e); // } // } // // } }