KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > transaction > TransactionImpl


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  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.transaction;
31
32 import com.caucho.jca.UserTransactionImpl;
33 import com.caucho.jca.UserTransactionSuspendState;
34 import com.caucho.log.Log;
35 import com.caucho.transaction.xalog.AbstractXALogStream;
36 import com.caucho.util.Alarm;
37 import com.caucho.util.AlarmListener;
38 import com.caucho.util.CharBuffer;
39 import com.caucho.util.L10N;
40
41 import javax.transaction.*;
42 import javax.transaction.xa.XAException JavaDoc;
43 import javax.transaction.xa.XAResource JavaDoc;
44 import javax.transaction.xa.Xid JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.logging.Level JavaDoc;
48 import java.util.logging.Logger JavaDoc;
49
50 /**
51  * Implementation of the transaction. Transactions are normally
52  * associated with a single thread.
53  */

54 public class TransactionImpl implements Transaction, AlarmListener {
55   private static final Logger JavaDoc log = Log.open(TransactionImpl.class);
56   private static final L10N L = new L10N(TransactionImpl.class);
57
58   private final static long DEFAULT_TIMEOUT = 60000;
59   private final static long EXTRA_TIMEOUT = 60000;
60   private final static long MAX_TIMEOUT = 24 * 3600 * 1000L;
61
62   // flag when the resource is active (between getConnection() and close())
63
private final static int RES_ACTIVE = 0x1;
64   // flag when the resource shares another resource manager
65
private final static int RES_SHARED_RM = 0x2;
66   // flag when the resource is suspended
67
private final static int RES_SUSPENDED = 0x4;
68   // flag when the resource wants to commit
69
private final static int RES_COMMIT = 0x8;
70
71   private TransactionManagerImpl _manager;
72   
73   // state of the transaction
74
private int _status;
75
76   // The transaction id for the resource
77
private XidImpl _xid;
78   
79   // true if the transaction is suspended.
80
private boolean _isSuspended;
81   private boolean _isDead;
82
83   // How many resources are available
84
private int _resourceCount;
85   // The current resources in the transaction
86
private XAResource JavaDoc []_resources;
87   // The xids for the resources
88
private XidImpl []_resourceXid;
89   // Whether the resources are active (between begin/end) or not
90
private int []_resourceState;
91
92   private UserTransactionImpl _userTransaction;
93   private UserTransactionSuspendState _suspendState;
94
95   private HashMap JavaDoc<String JavaDoc,Object JavaDoc> _props;
96
97   private ArrayList JavaDoc<Synchronization> _syncList;
98
99   private Throwable JavaDoc _rollbackException;
100
101   private AbstractXALogStream _xaLog;
102
103   private long _timeout = 0;
104   private Alarm _alarm;
105
106   /**
107    * Creates a new transaction.
108    *
109    * @param manager the owning transaction manager
110    */

111   TransactionImpl(TransactionManagerImpl manager)
112   {
113     _manager = manager;
114     _timeout = _manager.getTimeout();
115     _status = Status.STATUS_NO_TRANSACTION;
116     _alarm = new Alarm("xa-timeout", this, ClassLoader.getSystemClassLoader());
117   }
118
119   /**
120    * Sets the user transaction.
121    */

122   public void setUserTransaction(UserTransactionImpl ut)
123   {
124     _userTransaction = ut;
125   }
126
127   /**
128    * Returns true if the transaction has any associated resources.
129    */

130   boolean hasResources()
131   {
132     return _resourceCount > 0;
133   }
134
135   /**
136    * Returns true if the transaction is currently suspended.
137    */

138   boolean isSuspended()
139   {
140     return _isSuspended;
141   }
142
143   /**
144    * Returns true if the transaction is dead, i.e. failed for some reason.
145    */

146   boolean isDead()
147   {
148     return _isDead;
149   }
150
151   /**
152    * Return true if the transaction has no resources.
153    */

154   public boolean isEmpty()
155   {
156     if (_isDead)
157       return true;
158     else if (_resourceCount > 0)
159       return false;
160     // XXX: ejb/3692 because TransactionContext adds itself
161
else if (_syncList != null && _syncList.size() > 1)
162       return false;
163     else
164       return true;
165   }
166
167   /**
168    * Start a transaction.
169    */

170   void begin()
171     throws SystemException
172   {
173     if (_status != Status.STATUS_NO_TRANSACTION) {
174       try {
175         rollback();
176       } catch (Throwable JavaDoc e) {
177         log.log(Level.WARNING, e.toString(), e);
178       }
179       
180       throw new UnsupportedOperationException JavaDoc(L.l("Nested transactions are not supported. The previous transaction for this thread did not commit() or rollback(). Check that every UserTransaction.begin() has its commit() or rollback() in a finally block."));
181     }
182
183     if (_isDead)
184       throw new IllegalStateException JavaDoc(L.l("Error trying to use dead transaction."));
185     
186     _status = Status.STATUS_ACTIVE;
187     
188     _rollbackException = null;
189
190     if (_xid == null)
191       _xid = _manager.createXID();
192
193     if (log.isLoggable(Level.FINE))
194       log.fine("begin Transaction" + _xid);
195
196     if (_timeout > 0) {
197       _alarm.queue(_timeout + EXTRA_TIMEOUT);
198     }
199   }
200
201   /**
202    * Enlists a resource with the current transaction. Example
203    * resources are database or JMS connections.
204    *
205    * @return true if successful
206    */

207   public boolean enlistResource(XAResource JavaDoc resource)
208     throws RollbackException, SystemException
209   {
210     if (resource == null)
211       throw new IllegalArgumentException JavaDoc(L.l("Resource must not be null in enlistResource"));
212
213     if (_isSuspended)
214       throw new IllegalStateException JavaDoc(L.l("can't enlist with suspended transaction"));
215     if (_status == Status.STATUS_ACTIVE) {
216       // normal
217
}
218     else {
219       // validate the status
220
if (_status != Status.STATUS_MARKED_ROLLBACK) {
221       }
222       else if (_rollbackException != null)
223     throw RollbackExceptionWrapper.create(_rollbackException);
224       else
225     throw new RollbackException(L.l("can't enlist with rollback-only transaction"));
226
227       if (_status == Status.STATUS_NO_TRANSACTION)
228     throw new IllegalStateException JavaDoc(L.l("can't enlist with inactive transaction"));
229
230       throw new IllegalStateException JavaDoc(L.l("can't enlist with transaction in '{0}' state",
231                       xaState(_status)));
232     }
233
234       // creates enough space in the arrays for the resource
235
if (_resources == null) {
236       _resources = new XAResource JavaDoc[16];
237       _resourceState = new int[16];
238       _resourceXid = new XidImpl[16];
239     }
240     else if (_resources.length <= _resourceCount) {
241       int oldLength = _resources.length;
242       int newLength = 2 * oldLength;
243       
244       XAResource JavaDoc []resources = new XAResource JavaDoc[newLength];
245       int []resourceState = new int[newLength];
246       XidImpl []resourceXid = new XidImpl[newLength];
247
248       System.arraycopy(_resources, 0, resources, 0, oldLength);
249       System.arraycopy(_resourceState, 0, resourceState, 0, oldLength);
250       System.arraycopy(_resourceXid, 0, resourceXid, 0, oldLength);
251
252       _resources = resources;
253       _resourceState = resourceState;
254       _resourceXid = resourceXid;
255     }
256
257     int flags = XAResource.TMNOFLAGS;
258
259     // Active transaction will call the XAResource.start() method
260
// to let the resource manager know that the resource is managed.
261
//
262
// If the resource uses the same resource manager as one of the
263
// current resources, issue a TMJOIN message.
264
XidImpl xid = _xid;
265     boolean hasNewResource = true;
266
267     for (int i = 0; i < _resourceCount; i++) {
268       if (_resources[i] != resource) {
269       }
270       else if ((_resourceState[i] & RES_ACTIVE) != 0) {
271     IllegalStateException JavaDoc exn;
272     exn = new IllegalStateException JavaDoc(L.l("Can't enlist same resource twice. Delist is required before calling enlist with an old resource."));
273       
274     setRollbackOnly(exn);
275     throw exn;
276       }
277     
278       try {
279         if (_resources[i].isSameRM(resource)) {
280       flags = XAResource.TMJOIN;
281       xid = _resourceXid[i];
282           
283       if ((_resourceState[i] & RES_ACTIVE) == 0) {
284         _resources[i] = resource;
285         _resourceState[i] |= RES_ACTIVE;
286         hasNewResource = false;
287       }
288       
289       break;
290     }
291       } catch (Exception JavaDoc e) {
292     log.log(Level.FINE, e.toString(), e);
293       }
294     }
295
296     if (_resourceCount > 0 && flags != XAResource.TMJOIN)
297       xid = new XidImpl(_xid, _resourceCount + 1);
298       
299     try {
300       if (_timeout > 0)
301     resource.setTransactionTimeout((int) (_timeout / 1000L));
302
303       if (log.isLoggable(Level.FINER)) {
304     if (flags == XAResource.TMJOIN)
305       log.finer("join-XA " + xid + " " + resource);
306     else
307       log.finer("start-XA " + xid + " " + resource);
308       }
309       
310       resource.start(xid, flags);
311     } catch (XAException JavaDoc e) {
312       setRollbackOnly(e);
313       throw new SystemException(e);
314     }
315
316     if (hasNewResource) {
317       _resources[_resourceCount] = resource;
318       _resourceState[_resourceCount] = RES_ACTIVE;
319
320       if (flags == XAResource.TMJOIN)
321     _resourceState[_resourceCount] |= RES_SHARED_RM;
322     
323       _resourceXid[_resourceCount] = xid;
324       _resourceCount++;
325     }
326
327     return true;
328   }
329
330   /**
331    * Returns true if the local transaction optimization would be allowed.
332    */

333   public boolean allowLocalTransactionOptimization()
334   {
335     // XXX: can also check if all are non-local
336
return _resourceCount == 0;
337   }
338
339   /**
340    * Returns the current number of resources.
341    */

342   public int getEnlistedResourceCount()
343   {
344     return _resourceCount;
345   }
346
347   /**
348    * delists a resource from the current transaction
349    *
350    * @param resource the resource to delist
351    * @param flag XXX: ???
352    *
353    * @return true if successful
354    */

355   public boolean delistResource(XAResource JavaDoc resource, int flag)
356     throws SystemException
357   {
358     if (_isSuspended)
359       throw new IllegalStateException JavaDoc(L.l("transaction is suspended"));
360
361     if (_resourceCount == 0)
362       return true;
363
364     int index;
365
366     for (index = _resourceCount - 1; index >= 0; index--) {
367       if (_resources[index].equals(resource))
368         break;
369     }
370
371     if (index < 0)
372       return false;
373     
374     // If there is no current transaction,
375
// remove it from the resource list entirely.
376
if (_status == Status.STATUS_NO_TRANSACTION) {
377       for (; index + 1 < _resourceCount; index++) {
378         _resources[index] = _resources[index + 1];
379         _resourceState[index] = _resourceState[index + 1];
380         _resourceXid[index] = _resourceXid[index + 1];
381       }
382
383       _resourceCount--;
384       
385       return true;
386     }
387
388     if (_status == Status.STATUS_MARKED_ROLLBACK)
389       flag = XAResource.TMFAIL;
390
391     _resourceState[index] &= ~RES_ACTIVE;
392
393     try {
394       resource.end(_resourceXid[index], flag);
395     } catch (XAException JavaDoc e) {
396       setRollbackOnly(e);
397       throw new SystemException(e);
398     }
399
400     return true;
401   }
402
403   /**
404    * Adds an attribute.
405    */

406   public void setAttribute(String JavaDoc var, Object JavaDoc value)
407   {
408     if (_props == null)
409       _props = new HashMap JavaDoc<String JavaDoc,Object JavaDoc>();
410
411     _props.put(var, value);
412   }
413
414   /**
415    * Gets an attribute.
416    */

417   public Object JavaDoc getAttribute(String JavaDoc var)
418   {
419     if (_props != null)
420       return _props.get(var);
421     else
422       return null;
423   }
424
425   public Xid JavaDoc getXid()
426   {
427     return _xid;
428   }
429
430   /**
431    * Returns the status of this transaction
432    */

433   public int getStatus()
434   {
435     return _status;
436   }
437
438   /**
439    * Suspend the transaction. The timeouts are stopped.
440    */

441   void suspend()
442     throws SystemException
443   {
444     if (_isSuspended)
445       throw new IllegalStateException JavaDoc(L.l("can't suspend already-suspended transaction"));
446
447     // _alarm.dequeue();
448

449     _isSuspended = true;
450
451     for (int i = _resourceCount - 1; i >= 0; i--) {
452       if ((_resourceState[i] & (RES_ACTIVE|RES_SUSPENDED)) == RES_ACTIVE) {
453     try {
454       XAResource JavaDoc resource = _resources[i];
455       
456       resource.end(_resourceXid[i], XAResource.TMSUSPEND);
457     } catch (Exception JavaDoc e) {
458       setRollbackOnly(e);
459     }
460       }
461     }
462
463     if (_userTransaction != null)
464       _suspendState = _userTransaction.suspend();
465     
466     if (log.isLoggable(Level.FINER))
467       log.fine(_xid + " suspended");
468   }
469
470   /**
471    * Resume the transaction and requeue the timeout.
472    */

473   void resume()
474     throws SystemException
475   {
476     if (! _isSuspended)
477       throw new IllegalStateException JavaDoc(L.l("can't resume non-suspended transaction"));
478     
479     _alarm.queue(_timeout + EXTRA_TIMEOUT);
480
481     for (int i = _resourceCount - 1; i >= 0; i--) {
482       if ((_resourceState[i] & (RES_ACTIVE|RES_SUSPENDED)) == RES_ACTIVE) {
483     try {
484       XAResource JavaDoc resource = _resources[i];
485       
486       resource.start(_resourceXid[i], XAResource.TMRESUME);
487     } catch (Exception JavaDoc e) {
488       setRollbackOnly(e);
489     }
490       }
491     }
492
493     if (_userTransaction != null)
494       _userTransaction.resume(_suspendState);
495     
496     _isSuspended = false;
497     
498     if (log.isLoggable(Level.FINE))
499       log.fine(_xid + " resume");
500   }
501
502   /**
503    * Register a synchronization callback
504    */

505   public void registerSynchronization(Synchronization sync)
506   {
507     if (_syncList == null)
508       _syncList = new ArrayList JavaDoc<Synchronization>();
509
510     _syncList.add(sync);
511   }
512   
513   /**
514    * Force any completion to be a rollback.
515    */

516   public void setRollbackOnly()
517     throws SystemException
518   {
519     if (_status != Status.STATUS_ACTIVE &&
520         _status != Status.STATUS_MARKED_ROLLBACK)
521       throw new IllegalStateException JavaDoc(L.l("can't set rollback-only"));
522
523     _status = Status.STATUS_MARKED_ROLLBACK;
524
525     _timeout = 0;
526
527     if (log.isLoggable(Level.FINER))
528       log.finer("setting rollback-only");
529   }
530   
531   /**
532    * Force any completion to be a rollback.
533    */

534   public void setRollbackOnly(Throwable JavaDoc exn)
535   {
536     if (_status != Status.STATUS_ACTIVE &&
537         _status != Status.STATUS_MARKED_ROLLBACK)
538       throw new IllegalStateException JavaDoc(L.l("can't set rollback-only"));
539
540     _status = Status.STATUS_MARKED_ROLLBACK;
541
542     if (_rollbackException == null)
543       _rollbackException = exn;
544     
545     if (log.isLoggable(Level.FINER))
546       log.log(Level.FINER, "setting rollback-only: " + exn.toString(), exn);
547   }
548
549   /**
550    * Commit the transaction.
551    */

552   public void commit()
553     throws RollbackException, HeuristicMixedException,
554        HeuristicRollbackException, SystemException
555   {
556     _alarm.dequeue();
557     
558     Exception JavaDoc heuristicExn = null;
559     
560     try {
561       callBeforeCompletion();
562     } catch (Throwable JavaDoc e) {
563       setRollbackOnly(e);
564     }
565       
566     try {
567       if (_status != Status.STATUS_ACTIVE) {
568         switch (_status) {
569         case Status.STATUS_MARKED_ROLLBACK:
570           rollbackInt();
571           if (_rollbackException != null)
572             throw new RollbackExceptionWrapper(_rollbackException);
573           else
574             throw new RollbackException(L.l("Transaction has been marked rolled back."));
575           
576         case Status.STATUS_NO_TRANSACTION:
577           throw new IllegalStateException JavaDoc(L.l("Can't commit outside of a transaction. Either the UserTransaction.begin() is missing or the transaction has already been committed or rolled back."));
578
579         default:
580           rollbackInt();
581           throw new IllegalStateException JavaDoc(L.l("can't commit {0}", String.valueOf(_status)));
582         }
583       }
584       
585       if (log.isLoggable(Level.FINE))
586     log.fine("committing Transaction" + _xid);
587
588       if (_resourceCount > 0) {
589         _status = Status.STATUS_PREPARING;
590
591     AbstractXALogStream xaLog = _manager.getXALogStream();
592     boolean hasPrepare = false;
593     boolean allowSinglePhase = false;
594
595         for (int i = _resourceCount - 1; i >= 0; i--) {
596           XAResource JavaDoc resource = (XAResource JavaDoc) _resources[i];
597
598       if (i == 0 && (xaLog == null || ! hasPrepare)) {
599         // server/1601
600
_resourceState[0] |= RES_COMMIT;
601                             
602         allowSinglePhase = true;
603         break;
604       }
605
606           if ((_resourceState[i] & RES_SHARED_RM) == 0) {
607             try {
608               int prepare = resource.prepare(_resourceXid[i]);
609
610           if (prepare == XAResource.XA_RDONLY) {
611           }
612           else if (prepare == XAResource.XA_OK) {
613         hasPrepare = true;
614         _resourceState[i] |= RES_COMMIT;
615           }
616           else {
617         log.finer("unexpected prepare result " + prepare);
618         rollbackInt();
619           }
620             } catch (XAException JavaDoc e) {
621               heuristicExn = heuristicException(heuristicExn, e);
622           rollbackInt();
623           throw new RollbackExceptionWrapper(L.l("all commits rolled back"),
624                          heuristicExn);
625             }
626           }
627         }
628
629     if (hasPrepare && xaLog != null) {
630       _xaLog = xaLog;
631
632       xaLog.writeTMCommit(_xid);
633     }
634       
635         _status = Status.STATUS_COMMITTING;
636
637     if (allowSinglePhase) {
638       try {
639         XAResource JavaDoc resource = (XAResource JavaDoc) _resources[0];
640
641         if ((_resourceState[0] & RES_COMMIT) != 0)
642           resource.commit(_xid, true);
643
644         if (_timeout > 0)
645           resource.setTransactionTimeout(0);
646       } catch (XAException JavaDoc e) {
647         log.log(Level.FINE, e.toString(), e);
648
649         heuristicExn = heuristicException(heuristicExn, e);
650       }
651     }
652
653         for (int i = 0; i < _resourceCount; i++) {
654           XAResource JavaDoc resource = (XAResource JavaDoc) _resources[i];
655
656       if (i == 0 && allowSinglePhase)
657         continue;
658       
659           if ((_resourceState[i] & RES_SHARED_RM) != 0)
660             continue;
661           if ((_resourceState[i] & RES_COMMIT) == 0)
662             continue;
663
664           if (heuristicExn == null) {
665             try {
666               resource.commit(_resourceXid[i], false);
667
668           if (_timeout > 0)
669         resource.setTransactionTimeout(0);
670             } catch (XAException JavaDoc e) {
671               heuristicExn = e;
672               log.log(Level.FINE, e.toString(), e);
673             }
674           }
675           else {
676             try {
677               resource.rollback(_resourceXid[i]);
678
679           if (_timeout > 0)
680         resource.setTransactionTimeout(0);
681             } catch (XAException JavaDoc e) {
682               log.log(Level.FINE, e.toString(), e);
683             }
684           }
685         }
686       }
687       
688       if (heuristicExn != null && log.isLoggable(Level.FINE))
689     log.fine("failed Transaction[" + _xid + "]: " + heuristicExn);
690
691       if (heuristicExn == null)
692         _status = Status.STATUS_COMMITTED;
693       else if (heuristicExn instanceof RollbackException) {
694         _status = Status.STATUS_ROLLEDBACK;
695         throw (RollbackException) heuristicExn;
696       }
697       else if (heuristicExn instanceof HeuristicMixedException) {
698         _status = Status.STATUS_ROLLEDBACK;
699         throw (HeuristicMixedException) heuristicExn;
700       }
701       else if (heuristicExn instanceof HeuristicRollbackException) {
702         _status = Status.STATUS_ROLLEDBACK;
703         throw (HeuristicRollbackException) heuristicExn;
704       }
705       else if (heuristicExn instanceof SystemException) {
706         _status = Status.STATUS_ROLLEDBACK;
707         throw (SystemException) heuristicExn;
708       }
709       else {
710         _status = Status.STATUS_ROLLEDBACK;
711         throw RollbackExceptionWrapper.create(heuristicExn);
712       }
713     } finally {
714       callAfterCompletion();
715     }
716   }
717
718   /**
719    * Rollback the transaction.
720    */

721   public void rollback()
722   {
723     _alarm.dequeue();
724
725     try {
726       callBeforeCompletion();
727     } catch (Throwable JavaDoc e) {
728       setRollbackOnly(e);
729     }
730     
731     try {
732       switch (_status) {
733       case Status.STATUS_ACTIVE:
734       case Status.STATUS_MARKED_ROLLBACK:
735         // fall through to normal completion
736
break;
737           
738       case Status.STATUS_NO_TRANSACTION:
739         throw new IllegalStateException JavaDoc(L.l("Can't rollback outside of a transaction. Either the UserTransaction.begin() is missing or the transaction has already been committed or rolled back."));
740
741       default:
742         rollbackInt();
743         throw new IllegalStateException JavaDoc(L.l("Can't rollback in state: {0}", String.valueOf(_status)));
744       }
745
746       _status = Status.STATUS_MARKED_ROLLBACK;
747
748       rollbackInt();
749     } finally {
750       callAfterCompletion();
751     }
752   }
753
754   /**
755    * Calculates the heuristic exception based on the resource manager's
756    * exception.
757    */

758   private Exception JavaDoc heuristicException(Exception JavaDoc oldException,
759                                        XAException JavaDoc xaException)
760   {
761     switch (xaException.errorCode) {
762     case XAException.XA_HEURHAZ:
763     case XAException.XA_HEURCOM:
764       return oldException;
765       
766     case XAException.XA_HEURRB:
767       if (oldException instanceof HeuristicMixedException)
768         return oldException;
769       else if (oldException instanceof HeuristicRollbackException)
770         return oldException;
771       else if (oldException instanceof RollbackException)
772         return oldException;
773       else
774         return new HeuristicRollbackException(getXAMessage(xaException));
775       
776     default:
777       if (oldException instanceof SystemException)
778         return oldException;
779       else
780         return new SystemExceptionWrapper(getXAMessage(xaException),
781                                           xaException);
782     }
783   }
784
785   /**
786    * Rollback the transaction.
787    */

788   private void rollbackInt()
789   {
790     _status = Status.STATUS_ROLLING_BACK;
791     
792     if (log.isLoggable(Level.FINE))
793       log.fine("rollback Transaction[" + _xid + "]");
794
795     for (int i = 0; i < _resourceCount; i++) {
796       XAResource JavaDoc resource = (XAResource JavaDoc) _resources[i];
797
798       if ((_resourceState[i] & RES_SHARED_RM) != 0)
799         continue;
800       
801       try {
802         resource.rollback(_resourceXid[i]);
803
804     if (_timeout > 0)
805       resource.setTransactionTimeout(0);
806       } catch (Throwable JavaDoc e) {
807         log.log(Level.FINE, e.toString(), e);
808       }
809     }
810     
811     _status = Status.STATUS_ROLLEDBACK;
812   }
813
814   /**
815    * Call all the Synchronization listeners before the commit()/rollback()
816    * starts.
817    */

818   private void callBeforeCompletion()
819   {
820     int length = _syncList == null ? 0 : _syncList.size();
821
822     for (int i = 0; i < length; i++) {
823       Synchronization sync = _syncList.get(i);
824
825       try {
826     sync.beforeCompletion();
827       } catch (Throwable JavaDoc e) {
828     log.log(Level.FINE, e.toString(), e);
829       }
830     }
831
832     // tell the resources everything's done
833
for (int i = _resourceCount - 1; i >= 0; i--) {
834       XAResource JavaDoc resource = _resources[i];
835
836       int flag;
837
838       if (_status == Status.STATUS_MARKED_ROLLBACK)
839     flag = XAResource.TMFAIL;
840       else
841     flag = XAResource.TMSUCCESS;
842     
843       try {
844         if ((_resourceState[i] & RES_ACTIVE) != 0)
845           resource.end(_resourceXid[i], flag);
846       } catch (Throwable JavaDoc e) {
847         log.log(Level.FINE, e.toString(), e);
848     setRollbackOnly(e);
849       }
850     }
851   }
852
853   /**
854    * Call all the Synchronization listeners after the commit()/rollback()
855    * complete.
856    */

857   private void callAfterCompletion()
858   {
859     ArrayList JavaDoc<Synchronization> syncList = _syncList;
860     _syncList = null;
861
862     _userTransaction = null;
863
864     XidImpl xid = _xid;
865     _xid = null;
866
867     int status = _status;
868     _status = Status.STATUS_NO_TRANSACTION;
869
870     _rollbackException = null;
871
872     // remove the resources which have officially delisted
873
for (int i = _resourceCount - 1; i >= 0; i--)
874       _resources[i] = null;
875     
876     _resourceCount = 0;
877     
878     AbstractXALogStream xaLog = _xaLog;
879     _xaLog = null;
880
881     if (xaLog != null) {
882       try {
883     xaLog.writeTMFinish(xid);
884       } catch (Throwable JavaDoc e) {
885     log.log(Level.FINER, e.toString(), e);
886       }
887     }
888
889     int length = syncList == null ? 0 : syncList.size();
890     for (int i = 0; i < length; i++) {
891       Synchronization sync = (Synchronization) syncList.get(i);
892
893       try {
894         sync.afterCompletion(status);
895       } catch (Throwable JavaDoc e) {
896         log.log(Level.FINE, e.toString(), e);
897       }
898     }
899
900     if (_props != null)
901       _props.clear();
902   }
903
904   /**
905    * sets the timeout for the transaction
906    */

907   public void setTransactionTimeout(int seconds)
908     throws SystemException
909   {
910     if (seconds == 0)
911       _timeout = _manager.getTimeout();
912     else if (seconds < 0)
913       _timeout = MAX_TIMEOUT;
914     else {
915       _timeout = 1000L * (long) seconds;
916     }
917   }
918
919   /**
920    * sets the timeout for the transaction
921    */

922   public int getTransactionTimeout()
923     throws SystemException
924   {
925     if (_timeout < 0)
926       return -1;
927     else
928       return (int) (_timeout / 1000L);
929   }
930
931   public void handleAlarm(Alarm alarm)
932   {
933     try {
934       log.warning(L.l("{0}: timed out after {1} seconds.",
935               this,
936               String.valueOf(getTransactionTimeout())));
937       
938       setRollbackOnly();
939
940       // should not close at this point because there could be following
941
// statements that also need to be rolled back
942
// server/16a7
943
// close();
944
} catch (Throwable JavaDoc e) {
945       log.log(Level.FINE, e.toString(), e);
946     }
947   }
948
949   /**
950    * Close the transaction, rolling back everything and removing all
951    * enlisted resources.
952    */

953   public void close()
954   {
955     _isDead = true;
956     _alarm.dequeue();
957     
958     try {
959       if (_status != Status.STATUS_NO_TRANSACTION)
960         rollback();
961     } catch (Throwable JavaDoc e) {
962       log.log(Level.FINE, e.toString(), e);
963     }
964     
965     if (_syncList != null)
966       _syncList.clear();
967
968     for (int i = _resourceCount - 1; i >= 0; i--)
969       _resources[i] = null;
970
971     _resourceCount = 0;
972     
973     _xid = null;
974   }
975
976   /**
977    * Printable version of the transaction.
978    */

979   public String JavaDoc toString()
980   {
981     if (_xid == null)
982       return "Transaction[]";
983     
984     CharBuffer cb = new CharBuffer();
985
986     cb.append("Transaction[");
987
988     byte []branch = _xid.getBranchQualifier();
989
990     addByte(cb, branch[0]);
991
992     cb.append(":");
993     
994     byte []global = _xid.getGlobalTransactionId();
995     for (int i = 24; i < 28; i++)
996       addByte(cb, global[i]);
997
998     cb.append("]");
999     
1000    return cb.toString();
1001  }
1002
1003  /**
1004   * Adds hex for debug
1005   */

1006  private void addByte(CharBuffer cb, int b)
1007  {
1008    int h = (b / 16) & 0xf;
1009    int l = b & 0xf;
1010
1011    if (h >= 10)
1012      cb.append((char) ('a' + h - 10));
1013    else
1014      cb.append((char) ('0' + h));
1015    
1016    if (l >= 10)
1017      cb.append((char) ('a' + l - 10));
1018    else
1019      cb.append((char) ('0' + l));
1020  }
1021  
1022  /**
1023   * Converts XA error code to a message.
1024   */

1025  private static String JavaDoc getXAMessage(XAException JavaDoc xaException)
1026  {
1027    if (xaException.getMessage() != null &&
1028        ! xaException.getMessage().equals(""))
1029      return xaException.getMessage();
1030    else
1031      return (xaName(xaException.errorCode) + ": " +
1032              xaMessage(xaException.errorCode));
1033  }
1034
1035  /**
1036   * Converts XA state code to string.
1037   */

1038  private static String JavaDoc xaState(int xaState)
1039  {
1040    switch (xaState) {
1041    case Status.STATUS_ACTIVE:
1042      return "ACTIVE";
1043    case Status.STATUS_MARKED_ROLLBACK:
1044      return "MARKED-ROLLBACK";
1045    case Status.STATUS_PREPARED:
1046      return "PREPARED";
1047    case Status.STATUS_COMMITTED:
1048      return "COMITTED";
1049    case Status.STATUS_ROLLEDBACK:
1050      return "ROLLEDBACK";
1051    case Status.STATUS_PREPARING:
1052      return "PREPARING";
1053    case Status.STATUS_COMMITTING:
1054      return "COMMITTING";
1055    case Status.STATUS_ROLLING_BACK:
1056      return "ROLLING_BACK";
1057    default:
1058      return "XA-STATE(" + xaState + ")";
1059    }
1060  }
1061
1062  /**
1063   * Converts XA error code to string.
1064   */

1065  private static String JavaDoc xaName(int xaCode)
1066  {
1067    switch (xaCode) {
1068      // rollback codes
1069
case XAException.XA_RBROLLBACK:
1070      return "XA_RBROLLBACK";
1071    case XAException.XA_RBCOMMFAIL:
1072      return "XA_RBCOMMFAIL";
1073    case XAException.XA_RBDEADLOCK:
1074      return "XA_RBDEADLOCK";
1075    case XAException.XA_RBINTEGRITY:
1076      return "XA_RBINTEGRITY";
1077    case XAException.XA_RBOTHER:
1078      return "XA_RBOTHER";
1079    case XAException.XA_RBPROTO:
1080      return "XA_RBPROTO";
1081    case XAException.XA_RBTIMEOUT:
1082      return "XA_RBTIMEOUT";
1083    case XAException.XA_RBTRANSIENT:
1084      return "XA_RBTRANSIENT";
1085
1086      // suspension code
1087
case XAException.XA_NOMIGRATE:
1088      return "XA_NOMIGRATE";
1089      
1090      // heuristic completion codes
1091
case XAException.XA_HEURHAZ:
1092      return "XA_HEURHAZ";
1093    case XAException.XA_HEURCOM:
1094      return "XA_HEURCOM";
1095    case XAException.XA_HEURRB:
1096      return "XA_HEURRB";
1097    case XAException.XA_HEURMIX:
1098      return "XA_HEURMIX";
1099    case XAException.XA_RDONLY:
1100      return "XA_RDONLY";
1101
1102      // errors
1103
case XAException.XAER_RMERR:
1104      return "XA_RMERR";
1105    case XAException.XAER_NOTA:
1106      return "XA_NOTA";
1107    case XAException.XAER_INVAL:
1108      return "XA_INVAL";
1109    case XAException.XAER_PROTO:
1110      return "XA_PROTO";
1111    case XAException.XAER_RMFAIL:
1112      return "XA_RMFAIL";
1113    case XAException.XAER_DUPID:
1114      return "XA_DUPID";
1115    case XAException.XAER_OUTSIDE:
1116      return "XA_OUTSIDE";
1117
1118    default:
1119      return "XA(" + xaCode + ")";
1120    }
1121  }
1122
1123  /**
1124   * Converts XA error code to a message.
1125   */

1126  private static String JavaDoc xaMessage(int xaCode)
1127  {
1128    switch (xaCode) {
1129      // rollback codes
1130
case XAException.XA_RBROLLBACK:
1131    case XAException.XA_RBOTHER:
1132      return L.l("Resource rolled back for an unspecified reason.");
1133    case XAException.XA_RBCOMMFAIL:
1134      return L.l("Resource rolled back because of a communication failure.");
1135    case XAException.XA_RBDEADLOCK:
1136      return L.l("Resource rolled back because of a deadlock.");
1137    case XAException.XA_RBINTEGRITY:
1138      return L.l("Resource rolled back because of an integrity check failure.");
1139    case XAException.XA_RBPROTO:
1140      return L.l("Resource rolled back because of a protocol error in the resource manager.");
1141    case XAException.XA_RBTIMEOUT:
1142      return L.l("Resource rolled back because of a timeout.");
1143    case XAException.XA_RBTRANSIENT:
1144      return L.l("Resource rolled back because of transient error.");
1145
1146      // suspension code
1147
case XAException.XA_NOMIGRATE:
1148      return L.l("Resumption must occur where the suspension occurred.");
1149      
1150      // heuristic completion codes
1151
case XAException.XA_HEURHAZ:
1152      return L.l("Resource may have been heuristically completed.");
1153    case XAException.XA_HEURCOM:
1154      return L.l("Resource has been heuristically committed.");
1155    case XAException.XA_HEURRB:
1156      return L.l("Resource has been heuristically rolled back.");
1157    case XAException.XA_HEURMIX:
1158      return L.l("Resource has been heuristically committed and rolled back.");
1159    case XAException.XA_RDONLY:
1160      return L.l("Resource was read-only and has been heuristically committed.");
1161
1162      // errors
1163
case XAException.XAER_RMERR:
1164      return L.l("Resource manager error.");
1165    case XAException.XAER_NOTA:
1166      return L.l("The XID (transaction identifier) was invalid.");
1167    case XAException.XAER_INVAL:
1168      return L.l("Invalid arguments were given.");
1169    case XAException.XAER_PROTO:
1170      return L.l("Method called in an invalid context.");
1171    case XAException.XAER_RMFAIL:
1172      return L.l("Resource manager is unavailable.");
1173    case XAException.XAER_DUPID:
1174      return L.l("Duplicate XID (transaction identifier).");
1175    case XAException.XAER_OUTSIDE:
1176      return L.l("Resource manager called outside of transaction.");
1177
1178    default:
1179      return "";
1180    }
1181  }
1182}
1183
Popular Tags