View Javadoc
1   package org.argeo.transaction.simple;
2   
3   import java.util.Collections;
4   import java.util.HashMap;
5   import java.util.Map;
6   
7   import javax.transaction.HeuristicMixedException;
8   import javax.transaction.HeuristicRollbackException;
9   import javax.transaction.InvalidTransactionException;
10  import javax.transaction.NotSupportedException;
11  import javax.transaction.RollbackException;
12  import javax.transaction.Status;
13  import javax.transaction.Synchronization;
14  import javax.transaction.SystemException;
15  import javax.transaction.Transaction;
16  import javax.transaction.TransactionManager;
17  import javax.transaction.TransactionSynchronizationRegistry;
18  import javax.transaction.UserTransaction;
19  import javax.transaction.xa.Xid;
20  
21  /**
22   * Simple implementation of an XA {@link TransactionManager} and
23   * {@link UserTransaction}.
24   */
25  public class SimpleTransactionManager implements TransactionManager, UserTransaction {
26  	private ThreadLocal<SimpleTransaction> current = new ThreadLocal<SimpleTransaction>();
27  
28  	private Map<Xid, SimpleTransaction> knownTransactions = Collections
29  			.synchronizedMap(new HashMap<Xid, SimpleTransaction>());
30  	private SyncRegistry syncRegistry = new SyncRegistry();
31  
32  	@Override
33  	public void begin() throws NotSupportedException, SystemException {
34  		if (getCurrent() != null)
35  			throw new NotSupportedException("Nested transactions are not supported");
36  		SimpleTransaction transaction = new SimpleTransaction(this);
37  		knownTransactions.put(transaction.getXid(), transaction);
38  		current.set(transaction);
39  	}
40  
41  	@Override
42  	public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
43  			SecurityException, IllegalStateException, SystemException {
44  		if (getCurrent() == null)
45  			throw new IllegalStateException("No transaction registered with the current thread.");
46  		getCurrent().commit();
47  	}
48  
49  	@Override
50  	public int getStatus() throws SystemException {
51  		if (getCurrent() == null)
52  			return Status.STATUS_NO_TRANSACTION;
53  		return getTransaction().getStatus();
54  	}
55  
56  	@Override
57  	public Transaction getTransaction() throws SystemException {
58  		return getCurrent();
59  	}
60  
61  	protected SimpleTransaction getCurrent() throws SystemException {
62  		SimpleTransaction transaction = current.get();
63  		if (transaction == null)
64  			return null;
65  		int status = transaction.getStatus();
66  		if (Status.STATUS_COMMITTED == status || Status.STATUS_ROLLEDBACK == status) {
67  			current.remove();
68  			return null;
69  		}
70  		return transaction;
71  	}
72  
73  	void unregister(Xid xid) {
74  		knownTransactions.remove(xid);
75  	}
76  
77  	@Override
78  	public void resume(Transaction tobj) throws InvalidTransactionException, IllegalStateException, SystemException {
79  		if (getCurrent() != null)
80  			throw new IllegalStateException("Transaction " + current.get() + " already registered");
81  		current.set((SimpleTransaction) tobj);
82  	}
83  
84  	@Override
85  	public void rollback() throws IllegalStateException, SecurityException, SystemException {
86  		if (getCurrent() == null)
87  			throw new IllegalStateException("No transaction registered with the current thread.");
88  		getCurrent().rollback();
89  	}
90  
91  	@Override
92  	public void setRollbackOnly() throws IllegalStateException, SystemException {
93  		if (getCurrent() == null)
94  			throw new IllegalStateException("No transaction registered with the current thread.");
95  		getCurrent().setRollbackOnly();
96  	}
97  
98  	@Override
99  	public void setTransactionTimeout(int seconds) throws SystemException {
100 		throw new UnsupportedOperationException();
101 	}
102 
103 	@Override
104 	public Transaction suspend() throws SystemException {
105 		Transaction transaction = getCurrent();
106 		current.remove();
107 		return transaction;
108 	}
109 
110 	public TransactionSynchronizationRegistry getTsr() {
111 		return syncRegistry;
112 	}
113 
114 	private class SyncRegistry implements TransactionSynchronizationRegistry {
115 		@Override
116 		public Object getTransactionKey() {
117 			try {
118 				SimpleTransaction transaction = getCurrent();
119 				if (transaction == null)
120 					return null;
121 				return getCurrent().getXid();
122 			} catch (SystemException e) {
123 				throw new IllegalStateException("Cannot get transaction key", e);
124 			}
125 		}
126 
127 		@Override
128 		public void putResource(Object key, Object value) {
129 			throw new UnsupportedOperationException();
130 		}
131 
132 		@Override
133 		public Object getResource(Object key) {
134 			throw new UnsupportedOperationException();
135 		}
136 
137 		@Override
138 		public void registerInterposedSynchronization(Synchronization sync) {
139 			throw new UnsupportedOperationException();
140 		}
141 
142 		@Override
143 		public int getTransactionStatus() {
144 			try {
145 				return getStatus();
146 			} catch (SystemException e) {
147 				throw new IllegalStateException("Cannot get status", e);
148 			}
149 		}
150 
151 		@Override
152 		public boolean getRollbackOnly() {
153 			try {
154 				return getStatus() == Status.STATUS_MARKED_ROLLBACK;
155 			} catch (SystemException e) {
156 				throw new IllegalStateException("Cannot get status", e);
157 			}
158 		}
159 
160 		@Override
161 		public void setRollbackOnly() {
162 			try {
163 				getCurrent().setRollbackOnly();
164 			} catch (Exception e) {
165 				throw new IllegalStateException("Cannot set rollback only", e);
166 			}
167 		}
168 
169 	}
170 }