1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.transaction;
18
19 import java.util.concurrent.TimeUnit;
20
21 import org.apache.commons.transaction.locking.LockException;
22 import org.apache.commons.transaction.locking.LockManager;
23
24 /**
25 * Abstract base class for transactional resource managers.
26 * <p>
27 * This implementation takes care of most administrative tasks a transactional
28 * resource manager has to perform. Sublcass
29 * {@link AbstractTransactionalResourceManager.AbstractTxContext} to hold all
30 * information necessary for each transaction. Additionally, you have to
31 * implement {@link #createContext()} to create an object of that type, and
32 * {@link #commitCanFail()}.
33 *
34 * <p>
35 * This implementation is <em>thread-safe</em>.
36 */
37 public abstract class AbstractTransactionalResourceManager<T extends AbstractTransactionalResourceManager.AbstractTxContext>
38 implements ManageableResourceManager {
39 protected ThreadLocal<T> activeTx = new ThreadLocal<T>();
40
41 private LockManager<Object, Object> lm;
42
43 private String name;
44
45 private boolean partofComplexTransaction = false;
46
47 protected abstract T createContext();
48
49 public AbstractTransactionalResourceManager(String name) {
50 this.name = name;
51 }
52
53
54
55 public AbstractTransactionalResourceManager(String name, LockManager<Object, Object> lm) {
56 this.name = name;
57 this.lm = lm;
58 }
59
60 @Override
61 public boolean isRollbackOnly() {
62 T txContext = getCheckedActiveTx();
63
64 return (txContext.isMarkedForRollback());
65 }
66
67 @Override
68 public void startTransaction(long timeout, TimeUnit unit) {
69 if (getActiveTx() != null) {
70 throw new IllegalStateException("Active thread " + Thread.currentThread()
71 + " already associated with a transaction!");
72 }
73 T txContext = createContext();
74 txContext.start(timeout, unit);
75 setActiveTx(txContext);
76
77 }
78
79 @Override
80 public void rollbackTransaction() {
81 T txContext = getCheckedActiveTx();
82
83 txContext.rollback();
84 forgetTransaction();
85 }
86
87 @Override
88 public void forgetTransaction() {
89 T txContext = getCheckedActiveTx();
90
91 txContext.dispose();
92 setActiveTx(null);
93 partofComplexTransaction = false;
94 }
95
96 @Override
97 public boolean commitTransaction() {
98 T txContext = getCheckedActiveTx();
99
100 if (txContext.isMarkedForRollback()) {
101 throw new IllegalStateException("Active thread " + Thread.currentThread()
102 + " is marked for rollback!");
103 }
104
105 txContext.commit();
106 forgetTransaction();
107 return true;
108 }
109
110 protected T getActiveTx() {
111 return activeTx.get();
112 }
113
114 protected T getCheckedActiveTx() {
115 T txContext = getActiveTx();
116
117 if (txContext == null) {
118 throw new IllegalStateException("Active thread " + Thread.currentThread()
119 + " not associated with a transaction!");
120 }
121 return txContext;
122 }
123
124 protected void setActiveTx(T txContext) {
125 activeTx.set(txContext);
126 }
127
128 public boolean isReadOnly() {
129 T txContext = getCheckedActiveTx();
130 return (txContext.isReadOnly());
131 }
132
133 public abstract class AbstractTxContext {
134 private boolean readOnly = true;
135
136 private boolean markedForRollback = false;
137
138 public void join() {
139 }
140
141 public void start(long timeout, TimeUnit unit) {
142 getLm().startWork(timeout, unit);
143 }
144
145 public boolean isReadOnly() {
146 return readOnly;
147 }
148
149 public void setReadOnly(boolean readOnly) {
150 this.readOnly = readOnly;
151 }
152
153 public void readLock(Object id) throws LockException {
154 getLm().lock(getName(), id, false);
155 }
156
157 public void writeLock(Object id) throws LockException {
158 getLm().lock(getName(), id, true);
159 }
160
161 public boolean isMarkedForRollback() {
162 return markedForRollback;
163 }
164
165 public void markForRollback() {
166 markedForRollback = true;
167 }
168
169 public void dispose() {
170 if (!isPartofComplexTransaction())
171 getLm().endWork();
172 }
173
174 public void commit() {
175
176 }
177
178 public void rollback() {
179
180 }
181
182 public boolean prepare() {
183 return !isMarkedForRollback();
184 }
185
186 }
187
188 protected LockManager<Object, Object> getLm() {
189 return lm;
190 }
191
192 public void setLm(LockManager<Object, Object> lm) {
193 this.lm = lm;
194 }
195
196 public String getName() {
197 return name;
198 }
199
200 public void setName(String name) {
201 this.name = name;
202 }
203
204 public abstract boolean commitCanFail();
205
206 @Override
207 public void joinTransaction(LockManager<Object, Object> lm) {
208 if (getActiveTx() != null) {
209 throw new IllegalStateException("Active thread " + Thread.currentThread()
210 + " already associated with a transaction!");
211 }
212 setLm(lm);
213 T txContext = createContext();
214 txContext.join();
215 setActiveTx(txContext);
216 partofComplexTransaction = true;
217 }
218
219 @Override
220 public boolean prepareTransaction() {
221 T txContext = getCheckedActiveTx();
222 return txContext.prepare();
223
224 }
225
226 public boolean isPartofComplexTransaction() {
227 return partofComplexTransaction;
228 }
229
230 }