KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > rift > coad > util > transaction > TransactionManager


1 /*
2  * CoadunationLib: The coaduntion library.
3  * Copyright (C) 2006 Rift IT Contracting
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * TransactionManager.java
20  */

21
22 // package path
23
package com.rift.coad.util.transaction;
24
25 // java imports
26
import java.util.Iterator JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.LinkedHashMap JavaDoc;
29 import java.util.Vector JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.concurrent.ConcurrentHashMap JavaDoc;
32 import javax.naming.Context JavaDoc;
33 import javax.naming.InitialContext JavaDoc;
34 import javax.transaction.xa.XAException JavaDoc;
35 import javax.transaction.xa.XAResource JavaDoc;
36 import javax.transaction.xa.Xid JavaDoc;
37
38 // logging import
39
import org.apache.log4j.Logger;
40
41 // coadunation imports
42
import com.rift.coad.lib.configuration.Configuration;
43 import com.rift.coad.lib.configuration.ConfigurationFactory;
44 import com.rift.coad.util.lock.LockRef;
45 import com.rift.coad.util.lock.ObjectLockFactory;
46
47 /**
48  * This object is responsible for managing the transactions for a group of
49  * objects.
50  *
51  * @author Brett Chaldecott
52  */

53 public class TransactionManager implements XAResource JavaDoc {
54     
55     /**
56      * The transaction object, responsible for managing an individual
57      * transaction.
58      */

59     public class Transaction {
60         
61         // private member variables
62
private Xid JavaDoc xid = null;
63         private Map JavaDoc transactionEntries = new LinkedHashMap JavaDoc();
64         private Vector JavaDoc transactionQueue = new Vector JavaDoc();
65         
66         /**
67          * The constructor of the transaction object.
68          *
69          * @param xid The id of this transaction.
70          */

71         public Transaction(Xid JavaDoc xid) {
72             this.xid = xid;
73         }
74         
75         
76         /**
77          * This method adds a resource to the transaction for tracking.
78          *
79          * @param xaResource The reference to the resource to add to this
80          * transaction for tracking.
81          * @param writeLock If true a write lock must be aquired
82          * @exception TransactionException
83          */

84         public void addResource(XAResource JavaDoc xaResource, boolean writeLock) throws
85                 TransactionException {
86             try {
87                 LockRef lockRef = (LockRef)transactionEntries.get(xaResource);
88                 int flags = XAResource.TMRESUME;
89                 if (lockRef == null) {
90                     if (writeLock) {
91                         lockRef = ObjectLockFactory.getInstance().acquireWriteLock(
92                                 xaResource,xid,ObjectLockFactory.WAIT_ON_NAMED);
93                     } else {
94                         lockRef = ObjectLockFactory.getInstance().acquireReadLock(
95                                 xaResource,xid);
96                     }
97                     transactionEntries.put(xaResource,lockRef);
98                     transactionQueue.add(xaResource);
99                     flags = XAResource.TMJOIN;
100                 } else if (writeLock && (lockRef.getLockType() == LockRef.READ)) {
101                     throw new TransactionException("Lock Conflict: There is a " +
102                             "read lock in place on this object.");
103                 } else if (!writeLock && (lockRef.getLockType() == LockRef.WRITE)) {
104                     throw new TransactionException("Lock Conflict: There is a " +
105                             "write lock in place on this object.");
106                 }
107                 xaResource.start(xid,flags);
108             } catch (TransactionException ex) {
109                 throw ex;
110             } catch (Exception JavaDoc ex) {
111                 log.error("Failed to add a new resource : " + ex.getMessage(),
112                         ex);
113                 throw new TransactionException(
114                         "Failed to add a new resource : " + ex.getMessage(),ex);
115             }
116         }
117         
118         
119         /**
120          * This method is responsible for commiting this transaction
121          *
122          * @param onePhase If true this transaction must commit in a single
123          * phase.
124          * @exception TransactionException
125          */

126         public void commit(boolean onePhase) throws TransactionException {
127             try {
128                 for (int index = 0; index < transactionQueue.size(); index++) {
129                     Object JavaDoc ref = transactionQueue.get(index);
130                     if (ref instanceof XAResource JavaDoc) {
131                         ((XAResource JavaDoc)ref).commit(xid,onePhase);
132                     }
133                 }
134                 for (int index = 0; index < transactionQueue.size(); index++) {
135                     LockRef lockRef = (LockRef)transactionEntries.get(
136                             transactionQueue.get(index));
137                     lockRef.release();
138                 }
139                 
140             } catch (Exception JavaDoc ex) {
141                 log.error("Failed to commit the resource transaction : " +
142                         ex.getMessage(),ex);
143                 throw new TransactionException(
144                         "Failed to commit the resource transaction : " +
145                         ex.getMessage(),ex);
146             }
147         }
148         
149         
150         /**
151          * This method is responsible for commiting this transaction
152          *
153          * @exception TransactionException
154          */

155         public void forget() throws TransactionException {
156             try {
157                 for (int index = 0; index < transactionQueue.size(); index++) {
158                     Object JavaDoc ref = transactionQueue.get(index);
159                     if (ref instanceof XAResource JavaDoc) {
160                         ((XAResource JavaDoc)ref).forget(xid);
161                     }
162                 }
163                 for (int index = 0; index < transactionQueue.size(); index++) {
164                     LockRef lockRef = (LockRef)transactionEntries.get(
165                             transactionQueue.get(index));
166                     lockRef.release();
167                 }
168                 
169             } catch (Exception JavaDoc ex) {
170                 log.error("Failed to forget the resource transaction: "
171                         + ex.getMessage(),ex);
172                 throw new TransactionException(
173                         "Failed to forget the resource transaction : " +
174                         ex.getMessage(),ex);
175             }
176         }
177         
178         
179         /**
180          * This method is called to roll back the specified transaction.
181          *
182          * @param xid The id of the transaction to roll back.
183          * @exception XAException
184          */

185         public void rollback() throws TransactionException {
186             try {
187                 for (int index = 0; index < transactionQueue.size(); index++) {
188                     int pos = transactionQueue.size() - (index + 1);
189                     Object JavaDoc ref = transactionQueue.get(pos);
190                     if (ref instanceof XAResource JavaDoc) {
191                         ((XAResource JavaDoc)ref).rollback(xid);
192                     }
193                 }
194                 for (int index = 0; index < transactionQueue.size(); index++) {
195                     int pos = transactionQueue.size() - (index + 1);
196                     LockRef lockRef = (LockRef)transactionEntries.get(
197                             transactionQueue.get(pos));
198                     lockRef.release();
199                 }
200                 
201             } catch (Exception JavaDoc ex) {
202                 log.error("Failed to forget the resource transaction: "
203                         + ex.getMessage(),ex);
204                 throw new TransactionException(
205                         "Failed to forget the resource transaction : " +
206                         ex.getMessage(),ex);
207             }
208         }
209     }
210     
211     // class constants
212
private final static String JavaDoc TIMEOUT = "transaction_timeout";
213     private final static long DEFAULT_TIMEOUT = 180000;
214     
215     // private member variables
216
protected static Logger log =
217             Logger.getLogger(TransactionManager.class.getName());
218     
219     // the singleton object.
220
private static Map JavaDoc singletonMap = new HashMap JavaDoc();
221     
222     // private member variables
223
private Context JavaDoc context = null;
224     private int timeout = 0;
225     private javax.transaction.TransactionManager JavaDoc jtaTransManager = null;
226     private ThreadLocal JavaDoc threadXID = new ThreadLocal JavaDoc();
227     private Map JavaDoc transactions = new ConcurrentHashMap JavaDoc();
228     
229     
230     /**
231      * Creates a new instance of TransactionManager
232      */

233     private TransactionManager() throws TransactionException {
234         try {
235             context = new InitialContext JavaDoc();
236             jtaTransManager = (javax.transaction.TransactionManager JavaDoc)context.
237                     lookup("java:comp/TransactionManager");
238             Configuration config = ConfigurationFactory.getInstance().getConfig(
239                     this.getClass());
240             timeout = (int)config.getLong(TIMEOUT,DEFAULT_TIMEOUT);
241         } catch (Exception JavaDoc ex) {
242             log.error("Failed to log init the transaction manager because : " +
243                     ex.getMessage(),ex);
244             throw new TransactionException(
245                     "Failed to log init the transaction manager because : " +
246                     ex.getMessage(),ex);
247         }
248     }
249     
250     
251     /**
252      * This method creates a new object lock factory singleton for a class
253      * loader.
254      *
255      * @exception TransactionException
256      */

257     public synchronized static void init() throws TransactionException {
258         ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
259         if (!singletonMap.containsKey(loader)) {
260             singletonMap.put(loader,new TransactionManager());
261         }
262     }
263     
264     
265     /**
266      * This method returns an instance of the transaction manager singleton.
267      *
268      * @return An instance of the transaction manager singleton.
269      */

270     public synchronized static TransactionManager getInstance() throws
271             TransactionException {
272         ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
273         TransactionManager singleton = null;
274         if (singletonMap.containsKey(loader)) {
275             singleton = (TransactionManager)singletonMap.get(loader);
276         } else {
277             throw new TransactionException("There is no transaction manager " +
278                     "for this class loader");
279         }
280         return singleton;
281     }
282     
283     
284     /**
285      * This method removes the object lock factory associated with a class
286      * loader.
287      *
288      * @exception TransactionException
289      */

290     public synchronized static void fin() throws TransactionException {
291         ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
292         if (singletonMap.containsKey(loader)) {
293             singletonMap.remove(loader);
294         }
295     }
296     
297     
298     /**
299      * This method binds a resource to the current transaction bound to this
300      * thread.
301      *
302      * @param xaResource The reference to the xaResource.
303      * @param writeLock If true the object must aquire a write lock.
304      * @exception TransactionException
305      */

306     public void bindResource(XAResource JavaDoc xaResource, boolean writeLock) throws
307             TransactionException {
308         try {
309             jtaTransManager.getTransaction().enlistResource(this);
310             Xid JavaDoc currentTransactionId = (Xid JavaDoc)threadXID.get();
311             Transaction transaction = (Transaction)transactions.get(
312                     currentTransactionId);
313             if (transaction == null) {
314                 transaction = new Transaction(currentTransactionId);
315                 transactions.put(currentTransactionId,transaction);
316             }
317             transaction.addResource(xaResource,writeLock);
318         } catch (Exception JavaDoc ex) {
319             log.error("Failed to bind the resource to the transaction " +
320                     "manager : " + ex.getMessage(),ex);
321             throw new TransactionException(
322                     "Failed to bind the resource to the transaction " +
323                     "manager : " + ex.getMessage(),ex);
324         }
325     }
326     
327     
328     /**
329      * This method is responsible for handling the committing of a transaction
330      * identified by the xid.
331      *
332      * @param xid The id of the transaction to commit.
333      * @param onePhase If true a one phase commit should be used.
334      * @exception XAException
335      */

336     public void commit(Xid JavaDoc xid, boolean onePhase) throws XAException JavaDoc {
337         try {
338             Transaction transaction = (Transaction)transactions.get(xid);
339             if (transaction != null) {
340                 transaction.commit(onePhase);
341                 transactions.remove(xid);
342             }
343         } catch (Exception JavaDoc ex) {
344             log.error("Failed to commit the transaction :" + ex.getMessage(),ex);
345             throw new XAException JavaDoc("Failed to commit the transaction :" +
346                     ex.getMessage());
347         }
348     }
349     
350     
351     /**
352      * The resource manager has dissociated this object from the transaction.
353      *
354      * @param xid The id of the transaction that is getting ended.
355      * @param flags The flags associated with this operation.
356      * @exception XAException
357      */

358     public void end(Xid JavaDoc xid, int flags) throws XAException JavaDoc {
359     }
360     
361     
362     /**
363      * The transaction has been completed and must be forgotten.
364      *
365      * @param xid The id of the transaction to forget.
366      * @exception XAException
367      */

368     public void forget(Xid JavaDoc xid) throws XAException JavaDoc {
369         try {
370             Transaction transaction = (Transaction)transactions.get(xid);
371             if (transaction != null) {
372                 transaction.forget();
373                 transactions.remove(xid);
374             }
375         } catch (Exception JavaDoc ex) {
376             log.error("Failed to forget the transaction :" + ex.getMessage(),ex);
377             throw new XAException JavaDoc("Failed to forget the transaction :" +
378                     ex.getMessage());
379         }
380     }
381     
382     
383     /**
384      * This method returns the transaction timeout for this object.
385      *
386      * @return The int containing the transaction timeout.
387      * @exception XAException
388      */

389     public int getTransactionTimeout() throws XAException JavaDoc {
390         return timeout;
391     }
392     
393     
394     /**
395      * This method returns true if this object is the resource manager getting
396      * queried.
397      *
398      * @return TRUE if this is the resource manager, FALSE if not.
399      * @param xaResource The resource to perform the check against.
400      * @exception XAException
401      */

402     public boolean isSameRM(XAResource JavaDoc xAResource) throws XAException JavaDoc {
403         return this == xAResource;
404     }
405     
406     
407     /**
408      * This is called before a transaction is committed.
409      *
410      * @return The results of the transaction.
411      * @param xid The id of the transaction to check against.
412      * @exception XAException
413      */

414     public int prepare(Xid JavaDoc xid) throws XAException JavaDoc {
415         return XAResource.XA_OK;
416     }
417     
418     
419     /**
420      * This method returns the list of transaction branches for this resource
421      * manager.
422      *
423      * @return The list of resource branches.
424      * @param flags The flags
425      * @exception XAException
426      */

427     public Xid JavaDoc[] recover(int flags) throws XAException JavaDoc {
428         return null;
429     }
430     
431     
432     /**
433      * This method is called to roll back the specified transaction.
434      *
435      * @param xid The id of the transaction to roll back.
436      * @exception XAException
437      */

438     public void rollback(Xid JavaDoc xid) throws XAException JavaDoc {
439         try {
440             Transaction transaction = (Transaction)transactions.get(xid);
441             if (transaction != null) {
442                 transaction.rollback();
443                 transactions.remove(xid);
444             }
445         } catch (Exception JavaDoc ex) {
446             log.error("Failed to rollback the transaction :" +
447                     ex.getMessage(),ex);
448             throw new XAException JavaDoc("Failed to rollback the transaction :" +
449                     ex.getMessage());
450         }
451     }
452     
453     
454     /**
455      * This method sets the transaction timeout for this resource manager.
456      *
457      * @return TRUE if the transaction timeout can be set successfully.
458      * @param transactionTimeout The new transaction timeout value.
459      * @exception XAException
460      */

461     public boolean setTransactionTimeout(int transactionTimeout) throws
462             XAException JavaDoc {
463         this.timeout = transactionTimeout;
464         return true;
465     }
466     
467     
468     /**
469      * This method is called to start a transaction on a resource manager.
470      *
471      * @param xid The id of the new transaction.
472      * @param flags The flags associated with the transaction.
473      * @exception XAException
474      */

475     public void start(Xid JavaDoc xid, int flags) throws XAException JavaDoc {
476         threadXID.set(xid);
477     }
478     
479     
480 }
481
Popular Tags