KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jodd > jtx > JtxTransactionManager


1 // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
2

3 package jodd.jtx;
4
5 import java.util.LinkedList JavaDoc;
6 import java.util.Map JavaDoc;
7 import java.util.HashMap JavaDoc;
8 import java.util.Iterator JavaDoc;
9
10 /**
11  * Simple {@link JtxTransaction} manager that creates one or more
12  * transactions depending on propagation and associate them to current thread.
13  *
14  */

15 public class JtxTransactionManager {
16
17     private boolean nestedTransactions;
18     private boolean singleResourceTransaction;
19     private Map JavaDoc resProviders;
20
21     public JtxTransactionManager() {
22         this.nestedTransactions = true;
23         this.singleResourceTransaction = false;
24         this.resProviders = new HashMap JavaDoc();
25     }
26
27     public boolean isNestedTransactions() {
28         return nestedTransactions;
29     }
30
31     /**
32      * Specifies if nested transactions are allwed by this transaction manager.
33      */

34     public void setNestedTransactions(boolean nestedTransactions) {
35         this.nestedTransactions = nestedTransactions;
36     }
37
38     public boolean isSingleResourceTransaction() {
39         return singleResourceTransaction;
40     }
41
42     /**
43      * Specifies if transactions created by this transaction manager
44      * may have only one resource attached. Having multiple resources
45      * per transaction may be a problem when committing a transactions and when
46      * only few resources committed successfully.
47      */

48     public void setSingleResourceTransaction(boolean singleResourceTransaction) {
49         this.singleResourceTransaction = singleResourceTransaction;
50     }
51
52     // ---------------------------------------------------------------- core management
53

54
55     private static final ThreadLocal JavaDoc TXSTACK = new ThreadLocal JavaDoc() {
56         protected synchronized Object JavaDoc initialValue() {
57             return new LinkedList JavaDoc();
58         }
59      };
60
61     /**
62      * Creates a new transaction and associate it with the current thread.
63      *
64      * @see #requestTransaction(JtxTransactionMode)
65      */

66     public JtxTransaction createTransaction(JtxTransactionMode tm) {
67         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
68         if (nestedTransactions == false) {
69             if (txlist.isEmpty() == false) {
70                 throw new JtxException("Nested transaction are not allowed by current JTX transaction manager.");
71             }
72         }
73         JtxTransaction tx = new JtxTransaction(this, tm);
74         txlist.addLast(tx);
75         return tx;
76     }
77
78     /**
79      * Get the transaction object that represents the transaction context of the calling thread.
80      * If the calling thread is not associated with a transaction, a <code>null</code> is returned.
81      */

82     public JtxTransaction getTransaction() {
83         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
84         if (txlist.isEmpty() == true) {
85             return null;
86         }
87         return (JtxTransaction) txlist.getLast();
88     }
89
90     /**
91      * Returns <code>true</code> if current thread is associated to at least one transaction.
92      * Transaction still may be not started yet, but can not be finished.
93      * Similar as checking if {@link #getTransaction()} returns <code>null</code>
94      * @see #isUnderActiveTransaction()
95      */

96     public boolean isUnderTransaction() {
97         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
98         return (txlist.isEmpty() != true);
99     }
100
101     /**
102      * Returns <code>true</code> if current thread is associated to a transaction and if
103      * transaction is active and started.
104      * @see #isUnderTransaction()
105      */

106     public boolean isUnderActiveTransaction() {
107         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
108         if (txlist.isEmpty() == true) {
109             return false;
110         }
111         return ((JtxTransaction) txlist.getLast()).isActive();
112         
113     }
114
115
116
117     /**
118      * Removes transaction association from current thread.
119      */

120     void removeTransaction(JtxTransaction tx) {
121         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
122         txlist.remove(tx);
123     }
124
125
126     /**
127      * Returns total number of transactions associated with current thread.
128      */

129     public int totalTransactions() {
130         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
131         return txlist.size();
132     }
133
134     /**
135      * Returns total number of active transactions associated with current thread.
136      */

137     public int totalActiveTransactions() {
138         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
139         int count = 0;
140         for (int i = 0; i < txlist.size(); i++) {
141             JtxTransaction tx = (JtxTransaction) txlist.get(i);
142             if (tx.isActive() == true) {
143                 count++;
144             }
145         }
146         return count;
147     }
148
149
150     /**
151      * Commit all transactions associated with current thread.
152      */

153     public void commitAll() {
154         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
155         while (txlist.isEmpty() == false) {
156             JtxTransaction tx = (JtxTransaction) txlist.removeLast();
157             tx.commit();
158         }
159     }
160
161     /**
162      * Roll back all transactions associated with current thread.
163      */

164     public void rollbackAll() {
165         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
166         while (txlist.isEmpty() == false) {
167             JtxTransaction tx = (JtxTransaction) txlist.removeLast();
168             tx.rollback();
169         }
170     }
171
172
173     // ---------------------------------------------------------------- propagation
174

175
176
177     /**
178      * Obtain transaction depending on propagation mode.
179      *
180      * Differences from the {@link #createTransaction(JtxTransactionMode)}:
181      * <ul>
182      * <li>all created transactions are active, i.e. {@link jodd.jtx.JtxTransaction#begin()}
183      * is invoked before returning;</li>
184      * <li>not supported transactions doesn't return <code>null</code>, but an
185      * autocommited transaction.</li>
186      * </ul>
187      */

188     public JtxTransaction requestTransaction(JtxTransactionMode mode) {
189         switch (mode.getPropagation()) {
190             case JtxTransactionMode.PROPAGATION_REQUIRED: return propRequired(mode);
191             case JtxTransactionMode.PROPAGATION_SUPPORTS: return propSupports();
192             case JtxTransactionMode.PROPAGATION_MANDATORY: return propMandatory();
193             case JtxTransactionMode.PROPAGATION_REQUIRES_NEW: return propRequiresNew(mode);
194             case JtxTransactionMode.PROPAGATION_NOT_SUPPORTED: return propNotSupported(mode);
195             case JtxTransactionMode.PROPAGATION_NEVER: return propNever(mode);
196             default:
197                 throw new JtxException("Invalid transaction propagation value (" + mode.getPropagation() + ')');
198         }
199     }
200
201     /**
202      * None -> T2
203      * T1 -> T1
204      */

205     private JtxTransaction propRequired(JtxTransactionMode mode) {
206         JtxTransaction currentTx = getTransaction();
207         if ((currentTx == null) || (currentTx.isAutocommit() == true)) {
208             currentTx = createTransaction(mode);
209             currentTx.begin();
210         }
211         return currentTx;
212     }
213
214     /**
215      * None -> T2
216      * T1 -> T2
217      */

218     private JtxTransaction propRequiresNew(JtxTransactionMode mode) {
219         JtxTransaction tx = createTransaction(mode);
220         tx.begin();
221         return tx;
222     }
223
224     /**
225      * None -> None
226      * T1 -> T1
227      */

228     private JtxTransaction propSupports() {
229         return getTransaction();
230     }
231
232     /**
233      * None -> Error
234      * T1 -> T1
235      */

236     private JtxTransaction propMandatory() {
237         JtxTransaction currentTx = getTransaction();
238         if ((currentTx == null) || (currentTx.isAutocommit() == true)) {
239             throw new JtxException("Transaction is mandatory.");
240         }
241         return currentTx;
242     }
243
244     /**
245      * None -> None
246      * T1 -> None
247      */

248     private JtxTransaction propNotSupported(JtxTransactionMode mode) {
249         JtxTransaction currentTx = getTransaction();
250         if (currentTx == null) {
251             return createTransaction(mode);
252         }
253         if (currentTx.isAutocommit() == true) {
254             return currentTx;
255         }
256         return createTransaction(mode);
257     }
258
259     /**
260      * None -> None
261      * T1 -> Error
262      */

263     private JtxTransaction propNever(JtxTransactionMode mode) {
264         JtxTransaction currentTx = getTransaction();
265         if ((currentTx != null) && (currentTx.isAutocommit() == false)) {
266             throw new JtxException("Transaction is not allowed.");
267         }
268         if (currentTx == null) {
269             currentTx = createTransaction(mode);
270         }
271         return currentTx;
272     }
273
274     // ---------------------------------------------------------------- resources
275

276     /**
277      * Registeres {@link JtxResourceManager}.
278      */

279     public void registerResourceManager(JtxResourceManager resourceManager) {
280         resProviders.put(resourceManager.getResourceType(), resourceManager);
281     }
282
283     /**
284      * Lookup for resource provider. Throws an exception if provider doesn't exists.
285      */

286     JtxResourceManager lookupResourceManager(String JavaDoc resourceType) {
287         JtxResourceManager resourceManager = (JtxResourceManager) resProviders.get(resourceType);
288         if (resourceManager == null) {
289             throw new JtxException("Unable to find resource manager for resource type: '" + resourceType + "'.");
290         }
291         return resourceManager;
292     }
293
294     /**
295      * Returns transaction resource and attaches it to the latest transaction.
296      * It may be called several times during one transaction,
297      * and always the same instance of resource will be returned.
298      *
299      * If there are no active transaction, resource will be returned
300      * in non-transactional mode.
301      */

302     public JtxResource getResource(String JavaDoc resourceType) {
303         LinkedList JavaDoc txlist = (LinkedList JavaDoc) TXSTACK.get();
304         if (txlist.isEmpty() == true) {
305             JtxResourceManager resourceManager = lookupResourceManager(resourceType);
306             return resourceManager.createResource();
307         }
308         JtxTransaction tx = (JtxTransaction) txlist.getLast();
309         return tx.getResource(resourceType);
310     }
311
312
313     // ---------------------------------------------------------------- close
314

315     /**
316      * Closes all assigned {@link JtxResourceManager}. Note that resources
317      * are <b>not</b> closed and they must be closed manually.
318      */

319     public void close() {
320         Iterator JavaDoc it = resProviders.values().iterator();
321         while (it.hasNext()) {
322             JtxResourceManager resourceManager = (JtxResourceManager) it.next();
323             resourceManager.close();
324         }
325         resProviders.clear();
326     }
327
328 }
329
330
Popular Tags