KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > ejb > xa > EjbTransactionManager


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.ejb.xa;
30
31 import com.caucho.amber.manager.AmberConnection;
32 import com.caucho.config.ConfigException;
33 import com.caucho.ejb.EJBExceptionWrapper;
34 import com.caucho.ejb.EnvServerManager;
35 import com.caucho.log.Log;
36 import com.caucho.util.FreeList;
37 import com.caucho.util.L10N;
38
39 import javax.ejb.EJBException JavaDoc;
40 import javax.naming.InitialContext JavaDoc;
41 import javax.naming.NamingException JavaDoc;
42 import javax.transaction.Transaction JavaDoc;
43 import javax.transaction.TransactionManager JavaDoc;
44 import javax.transaction.UserTransaction JavaDoc;
45 import java.util.Hashtable JavaDoc;
46 import java.util.logging.Level JavaDoc;
47 import java.util.logging.Logger JavaDoc;
48
49 /**
50  * Server containing all the EJBs for a given configuration.
51  *
52  * <p>Each protocol will extend the container to override Handle creation.
53  */

54 public class EjbTransactionManager {
55   private static final L10N L = new L10N(EjbTransactionManager.class);
56   private static final Logger JavaDoc log = Log.open(EjbTransactionManager.class);
57
58   public static final int RESIN_DATABASE = 0;
59   public static final int RESIN_READ_ONLY = 1;
60   public static final int RESIN_ROW_LOCKING = 2;
61
62   protected static final ThreadLocal JavaDoc<TransactionContext> _threadTransaction
63     = new ThreadLocal JavaDoc<TransactionContext>();
64
65   private FreeList<TransactionContext> _freeTransactions
66     = new FreeList<TransactionContext>(64);
67
68   private Hashtable JavaDoc<Transaction JavaDoc,TransactionContext> _transactionMap
69     = new Hashtable JavaDoc<Transaction JavaDoc,TransactionContext>();
70
71   private Hashtable JavaDoc<String JavaDoc,TransactionContext> _foreignTransactionMap
72     = new Hashtable JavaDoc<String JavaDoc,TransactionContext>();
73   
74   private final EnvServerManager _ejbManager;
75
76   protected final TransactionManager JavaDoc _transactionManager;
77   protected UserTransaction JavaDoc _userTransaction;
78
79   private int _resinIsolation = -1;
80   private int _jdbcIsolation = -1;
81   
82   private long _transactionTimeout = 0;
83
84   private boolean _isClosed;
85
86   /**
87    * Create a server with the given prefix name.
88    */

89   public EjbTransactionManager(EnvServerManager ejbManager)
90     throws ConfigException
91   {
92     _ejbManager = ejbManager;
93
94     UserTransaction JavaDoc ut = null;
95     TransactionManager JavaDoc tm = null;
96     
97     try {
98       InitialContext JavaDoc ic = new InitialContext JavaDoc();
99       
100       ut = (UserTransaction JavaDoc) ic.lookup("java:comp/UserTransaction");
101       
102       tm = (TransactionManager JavaDoc) ic.lookup("java:comp/TransactionManager");
103     } catch (NamingException JavaDoc e) {
104       log.log(Level.WARNING, e.toString(), e);
105     }
106
107     _userTransaction = ut;
108     _transactionManager = tm;
109
110     if (_transactionManager == null)
111       throw new ConfigException(L.l("Can't load TransactionManager."));
112   }
113
114   /**
115    * Returns the manager.
116    */

117   public EnvServerManager getEJBManager()
118   {
119     return _ejbManager;
120   }
121   
122
123   /**
124    * Sets the Resin isolation.
125    */

126   public void setResinIsolation(int resinIsolation)
127   {
128     _resinIsolation = resinIsolation;
129   }
130
131   /**
132    * Sets the Resin isolation for the container.
133    */

134   public int getResinIsolation()
135   {
136     return _resinIsolation;
137   }
138
139   /**
140    * Sets the JDBC isolation.
141    */

142   public void setJDBCIsolation(int jdbcIsolation)
143   {
144     _jdbcIsolation = jdbcIsolation;
145   }
146
147   /**
148    * Gets the JDBC isolation level.
149    */

150   public int getJDBCIsolation()
151   {
152     return _jdbcIsolation;
153   }
154
155   /**
156    * Gets the transaction timeout
157    */

158   public long getTransactionTimeout()
159   {
160     return _transactionTimeout;
161   }
162
163   /**
164    * Sets the transaction timout.
165    */

166   public void setTransactionTimeout(long transactionTimeout)
167   {
168     _transactionTimeout = transactionTimeout;
169   }
170
171   void setUserTransaction(UserTransaction JavaDoc userTransaction)
172   {
173     _userTransaction = userTransaction;
174   }
175
176   public UserTransaction JavaDoc getUserTransaction()
177   {
178     return _userTransaction;
179   }
180
181   /**
182    * Returns a new AmberConnection.
183    */

184   public AmberConnection getAmberConnection()
185   {
186     TransactionContext xaContext = _threadTransaction.get();
187
188     if (xaContext != null)
189       return xaContext.getAmberConnection();
190     else
191       throw new IllegalStateException JavaDoc("can't get transaction outside of context");
192   }
193
194   public void commitTransaction()
195     throws EJBException JavaDoc
196   {
197     try {
198       if (_transactionManager.getTransaction() != null)
199     _userTransaction.commit();
200     } catch (Exception JavaDoc e) {
201       throw EJBExceptionWrapper.create(e);
202     }
203   }
204
205   public void rollbackTransaction()
206     throws EJBException JavaDoc
207   {
208     try {
209       _userTransaction.rollback();
210     } catch (Exception JavaDoc e) {
211       throw EJBExceptionWrapper.create(e);
212     }
213   }
214
215   TransactionManager JavaDoc getTransactionManager()
216     throws EJBException JavaDoc
217   {
218     return _transactionManager;
219   }
220   
221   public Transaction JavaDoc getTransaction()
222     throws EJBException JavaDoc
223   {
224     try {
225       return _transactionManager.getTransaction();
226     } catch (Exception JavaDoc e) {
227       throw EJBExceptionWrapper.create(e);
228     }
229   }
230
231   public TransactionContext getTransactionContext()
232   {
233     return _threadTransaction.get();
234   }
235
236   /**
237    * Returns a transaction context for the "required" transaction. If
238    * there's already an active transaction, use it. Otherwise create a
239    * new transaction.
240    *
241    * @return the transaction context for the request
242    */

243   public TransactionContext beginRequired()
244     throws EJBException JavaDoc
245   {
246     try {
247       Transaction JavaDoc oldTrans = _transactionManager.getTransaction();
248       TransactionContext oldCxt = _threadTransaction.get();
249
250       // If this is within the same EJB transaction, just bump
251
// the count
252
if (oldCxt != null && oldTrans != null &&
253           oldCxt.getTransaction() == oldTrans) {
254         oldCxt.pushDepth();
255         return oldCxt;
256       }
257
258       // If there's an old transaction, see if there's a transaction context
259
// (only needed to support suspends)
260

261       if (oldTrans != null) {
262         TransactionContext cxt = _transactionMap.get(oldTrans);
263
264         if (cxt != null) {
265           _transactionMap.remove(oldTrans);
266
267           _threadTransaction.set(cxt);
268           cxt.pushDepth();
269         
270           return cxt;
271         }
272       }
273
274       // Link the new context to any old context
275
TransactionContext cxt = createTransaction();
276       cxt.setOld(oldCxt);
277         
278       _threadTransaction.set(cxt);
279       // If there was an old transaction, use it
280
if (oldTrans != null) {
281         setTransaction(cxt, oldTrans);
282         // This context is controlled by a user transaction
283
cxt.setUserTransaction(true);
284     cxt.pushDepth();
285       }
286       else {
287         _userTransaction.setTransactionTimeout((int) (_transactionTimeout / 1000L));
288         _userTransaction.begin();
289         Transaction JavaDoc trans = _transactionManager.getTransaction();
290
291     setTransaction(cxt, trans);
292       }
293       
294       if (_resinIsolation == RESIN_ROW_LOCKING)
295         cxt.setRowLocking(true);
296
297       return cxt;
298     } catch (Exception JavaDoc e) {
299       log.log(Level.WARNING, e.toString(), e);
300
301       throw EJBExceptionWrapper.create(e);
302     }
303   }
304
305   /**
306    * Returns a transaction context for a single read call. The single
307    * read is like supports, but returns a null transaction context
308    * if there's no transaction.
309    *
310    * @return the transaction context for the request
311    */

312   public TransactionContext beginSingleRead()
313     throws EJBException JavaDoc
314   {
315     try {
316       TransactionContext cxt = _threadTransaction.get();
317       Transaction JavaDoc trans = _transactionManager.getTransaction();
318
319       if (trans == null)
320     return null;
321       
322       // If in the same EJB transaction, return it
323
if (cxt != null && cxt.getTransaction() == trans) {
324     cxt.pushDepth();
325         return cxt;
326       }
327
328       // Check to see if there's an old EJB transaction to handle resume()
329
TransactionContext newCxt = _transactionMap.get(trans);
330
331       if (newCxt != null) {
332     newCxt.pushDepth();
333     return newCxt;
334       }
335
336       // Create a new EJB context and link to any old context
337
newCxt = createTransaction();
338       newCxt.pushDepth();
339         
340       _threadTransaction.set(newCxt);
341       setTransaction(newCxt, trans);
342       // The transaction is controlled by a user transaction
343
newCxt.setUserTransaction(true);
344
345       return newCxt;
346     } catch (Exception JavaDoc e) {
347       log.log(Level.WARNING, e.toString(), e);
348
349       throw EJBExceptionWrapper.create(e);
350     }
351   }
352
353   /**
354    * Begins a new transaction, suspending the old one if necessary.
355    *
356    * @return the old transaction context
357    */

358   public TransactionContext beginRequiresNew()
359     throws EJBException JavaDoc
360   {
361     try {
362       TransactionContext oldCxt = _threadTransaction.get();
363       Transaction JavaDoc oldTrans = _transactionManager.suspend();
364
365       TransactionContext newCxt = createTransaction();
366       newCxt.setOld(oldCxt);
367       newCxt.setOldTrans(oldTrans);
368
369       _threadTransaction.set(newCxt);
370       
371       if (_resinIsolation == RESIN_ROW_LOCKING)
372         newCxt.setRowLocking(true);
373
374       _userTransaction.setTransactionTimeout((int) (_transactionTimeout / 1000L));
375       _userTransaction.begin();
376       Transaction JavaDoc trans = _transactionManager.getTransaction();
377       
378       setTransaction(newCxt, trans);
379
380       return newCxt;
381     } catch (Exception JavaDoc e) {
382       log.log(Level.WARNING, e.toString(), e);
383
384       throw EJBExceptionWrapper.create(e);
385     }
386   }
387
388   /**
389    * Begins a new transaction, suspending the old one if necessary.
390    *
391    * @return the old transaction context
392    */

393   public TransactionContext beginSupports()
394     throws EJBException JavaDoc
395   {
396     try {
397       Transaction JavaDoc trans = _transactionManager.getTransaction();
398       TransactionContext cxt = _threadTransaction.get();
399
400       // Create a new EJB transaction if necessary
401
if (cxt == null || cxt.getTransaction() != trans) {
402     // check for a suspended transaction
403
if (trans != null)
404       cxt = _transactionMap.get(trans);
405     else
406       cxt = null;
407
408     if (cxt == null) {
409       cxt = createTransactionNoDepth();
410       setTransaction(cxt, trans);
411     }
412     
413         _threadTransaction.set(cxt);
414
415     if (trans != null) {
416       cxt.setUserTransaction(true);
417       cxt.pushDepth();
418     }
419       }
420
421       cxt.pushDepth();
422       
423       if (_resinIsolation == RESIN_ROW_LOCKING)
424     cxt.setRowLocking(true);
425       
426       return cxt;
427     } catch (Exception JavaDoc e) {
428       log.log(Level.WARNING, e.toString(), e);
429
430       throw EJBExceptionWrapper.create(e);
431     }
432   }
433
434   /**
435    * Suspends the current transaction
436    *
437    * @return the old transaction context
438    */

439   public TransactionContext suspend()
440     throws EJBException JavaDoc
441   {
442     try {
443       TransactionContext oldCxt = _threadTransaction.get();
444       Transaction JavaDoc oldTrans = _transactionManager.suspend();
445
446       if (oldTrans == null && oldCxt != null) {
447         oldCxt.pushDepth();
448         return oldCxt;
449       }
450
451       TransactionContext cxt = createTransaction();
452       _threadTransaction.set(cxt);
453
454       cxt.setOld(oldCxt);
455       cxt.setOldTrans(oldTrans);
456
457       return cxt;
458     } catch (Exception JavaDoc e) {
459       log.log(Level.WARNING, e.toString(), e);
460
461       throw EJBExceptionWrapper.create(e);
462     }
463   }
464
465   /**
466    * Starts a Never transaction, i.e. there is no transaction.
467    *
468    * @return the old transaction context
469    */

470   public TransactionContext beginNever()
471     throws EJBException JavaDoc
472   {
473     try {
474       Transaction JavaDoc oldTrans = _transactionManager.getTransaction();
475
476       if (oldTrans != null)
477         throw new EJBException JavaDoc("Transaction forbidden in 'Never' method");
478
479       TransactionContext cxt = _threadTransaction.get();
480
481       if (cxt == null) {
482         cxt = createTransaction();
483         _threadTransaction.set(cxt);
484       }
485       else
486         cxt.pushDepth();
487
488       return cxt;
489     } catch (Exception JavaDoc e) {
490       log.log(Level.WARNING, e.toString(), e);
491
492       throw EJBExceptionWrapper.create(e);
493     }
494   }
495
496   /**
497    * Begins a new transaction, the old one must exist.
498    *
499    * @return the old transaction context
500    */

501   public TransactionContext beginMandatory()
502     throws EJBException JavaDoc
503   {
504     try {
505       Transaction JavaDoc trans = _transactionManager.getTransaction();
506
507       if (trans == null)
508         throw new EJBException JavaDoc("Transaction required in 'Mandatory' method");
509
510       return beginRequired();
511     } catch (Exception JavaDoc e) {
512       log.log(Level.WARNING, e.toString(), e);
513
514       throw EJBExceptionWrapper.create(e);
515     }
516   }
517
518   /**
519    * Resumes a suspended transaction.
520    *
521    * @return the old transaction context
522    */

523   public void resume(TransactionContext oldCxt,
524              Transaction JavaDoc oldTrans,
525              Transaction JavaDoc completedTransaction)
526     throws EJBException JavaDoc
527   {
528     try {
529       if (completedTransaction != null)
530     _transactionMap.remove(completedTransaction);
531       _threadTransaction.set(oldCxt);
532
533       if (oldTrans != null)
534         _transactionManager.resume(oldTrans);
535     } catch (Exception JavaDoc e) {
536       log.log(Level.WARNING, e.toString(), e);
537
538       throw EJBExceptionWrapper.create(e);
539     }
540   }
541
542   /**
543    * Binds the EJB transaction context to the TM transaction context.
544    */

545   private void setTransaction(TransactionContext cxt, Transaction JavaDoc trans)
546   {
547     if (cxt != null) {
548       Transaction JavaDoc old = cxt.getTransaction();
549
550       if (old != null)
551     _transactionMap.remove(old);
552     }
553     else if (trans != null)
554       _transactionMap.remove(trans);
555     
556     cxt.setTransaction(trans);
557       
558     if (trans != null)
559       _transactionMap.put(trans, cxt);
560   }
561
562   /**
563    * Create a transaction context.
564    */

565   TransactionContext createTransaction()
566   {
567     TransactionContext trans = _freeTransactions.allocate();
568
569     if (trans == null)
570       trans = new TransactionContext(this);
571     trans.init(true);
572
573     return trans;
574   }
575
576   /**
577    * Create a transaction context.
578    */

579   TransactionContext createTransactionNoDepth()
580   {
581     TransactionContext trans = _freeTransactions.allocate();
582
583     if (trans == null)
584       trans = new TransactionContext(this);
585     trans.init(false);
586
587     return trans;
588   }
589
590   /**
591    * Creates a transaction from an external xid.
592    */

593   public TransactionContext startTransaction(String JavaDoc xid)
594   {
595     try {
596       TransactionContext xa = _foreignTransactionMap.get(xid);
597
598       if (xa != null) {
599     resume(xa, xa.getTransaction(), null);
600     return xa;
601       }
602
603       xa = beginRequiresNew();
604
605       _foreignTransactionMap.put(xid, xa);
606
607       return xa;
608     } catch (Throwable JavaDoc e) {
609       log.log(Level.FINE, e.toString(), e);
610
611       _foreignTransactionMap.remove(xid);
612
613       return null;
614     }
615   }
616
617   /**
618    * Creates a transaction from an external xid.
619    */

620   public void finishTransaction(String JavaDoc xid)
621   {
622     try {
623       TransactionContext xa = _foreignTransactionMap.get(xid);
624
625       if (xa == null) {
626       }
627       else if (xa.isEmpty()) {
628     _foreignTransactionMap.remove(xid);
629     xa.commit();
630       }
631       else {
632     suspend();
633     //
634
}
635     } catch (Exception JavaDoc e) {
636       log.log(Level.FINE, e.toString(), e);
637     }
638   }
639
640   /**
641    * Commits a transaction from an external xid.
642    */

643   public void commitTransaction(String JavaDoc xid)
644   {
645     try {
646       TransactionContext xa = _foreignTransactionMap.remove(xid);
647
648       if (xa != null) {
649     resume(xa, xa.getTransaction(), null);
650     xa.commit();
651       }
652     } catch (Throwable JavaDoc e) {
653       log.log(Level.FINE, e.toString(), e);
654     }
655   }
656
657   /**
658    * Rolls-back a transaction from an external xid.
659    */

660   public void rollbackTransaction(String JavaDoc xid)
661   {
662     try {
663       TransactionContext xa = _foreignTransactionMap.remove(xid);
664
665       if (xa != null) {
666     resume(xa, xa.getTransaction(), null);
667     xa.rollback();
668       }
669     } catch (Throwable JavaDoc e) {
670       log.log(Level.FINE, e.toString(), e);
671     }
672   }
673
674   /**
675    * Free a transaction context.
676    */

677   void freeTransaction(TransactionContext trans)
678   {
679     _freeTransactions.free(trans);
680   }
681
682   /**
683    * Closes the container.
684    */

685   public void destroy()
686   {
687     synchronized (this) {
688       if (_isClosed)
689     return;
690
691       _isClosed = true;
692     }
693     
694     _transactionMap = null;
695   }
696 }
697
698
Popular Tags