KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jotm > SubCoordinator


1 /*
2  * @(#) SubCoordinator.java
3  *
4  * JOTM: Java Open Transaction Manager
5  *
6  *
7  * This module was originally developed by
8  *
9  * - Bull S.A. as part of the JOnAS application server code released in
10  * July 1999 (www.bull.com)
11  *
12  * --------------------------------------------------------------------------
13  * The original code and portions created by Bull SA are
14  * Copyright (c) 1999 BULL SA
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are met:
19  *
20  * -Redistributions of source code must retain the above copyright notice, this
21  * list of conditions and the following disclaimer.
22  *
23  * -Redistributions in binary form must reproduce the above copyright notice,
24  * this list of conditions and the following disclaimer in the documentation
25  * and/or other materials provided with the distribution.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  *
39  * --------------------------------------------------------------------------
40  * Contributor(s):
41  * 01/11/06 Christophe Ney cney@batisseurs.com
42  * Added ResourceManagerListener mechanism to remove ThreadData
43  * dependency.
44  *
45  * 02/06/18 Marek Prochazka
46  * In addSynchronization() synchronizations are processed the
47  * same way as resources. We add synchro although transaction is
48  * marked rollback-only to be able to send beforeCompletion
49  *
50  * --------------------------------------------------------------------------
51  * $Id: SubCoordinator.java,v 1.37 2005/05/10 22:50:54 tonyortiz Exp $
52  * --------------------------------------------------------------------------
53  */

54
55 package org.objectweb.jotm;
56
57 import java.rmi.RemoteException JavaDoc;
58
59 import java.util.List JavaDoc;
60 import java.util.Vector JavaDoc;
61 import java.nio.ByteBuffer JavaDoc;
62 import javax.transaction.*;
63 import javax.transaction.xa.XAException JavaDoc;
64 import javax.transaction.xa.XAResource JavaDoc;
65 // import javax.transaction.xa.Xid;
66
import javax.rmi.PortableRemoteObject JavaDoc;
67
68 import org.objectweb.howl.log.xa.XACommittingTx;
69
70 /**
71  * Log associated to this transaction coordinator
72  */

73 class SLog {
74
75     private Vector JavaDoc loggedResources = new Vector JavaDoc();
76
77     private Vector JavaDoc loggedXids = new Vector JavaDoc();
78
79     int decision;
80     static final int DECISION_TO_COMMIT = 1;
81     static final int DECISION_TO_ROLLBACK = 2;
82
83     public void addResource( XAResource JavaDoc res, Xid xid )
84     {
85         if (TraceTm.jta.isDebugEnabled()) {
86             TraceTm.jta.debug("res= "+ res);
87             TraceTm.jta.debug("xid= "+ xid);
88         }
89         loggedResources.addElement(res);
90         loggedXids.addElement(xid);
91     }
92
93     /**
94      * @return a List of logged Resources
95      */

96     public List JavaDoc getLoggedResources() {
97         if (TraceTm.jta.isDebugEnabled()) {
98             TraceTm.jta.debug("logged resources="+ loggedResources);
99         }
100         return loggedResources;
101     }
102
103     public List JavaDoc getLoggedXids() {
104         return loggedXids;
105     }
106
107     public void flushLog(int decide) {
108         if (TraceTm.jta.isDebugEnabled()) {
109             TraceTm.jta.debug("decide="+ decide);
110         }
111         decision = decide;
112
113         // XXX serialize log on disk
114
}
115
116     public void forgetLog() {
117         if (TraceTm.jta.isDebugEnabled()) {
118             TraceTm.jta.debug("forget log");
119         }
120         // XXX remove file on disk
121
}
122 }
123
124 /**
125  * This object is the local coordinator. It may be registered as
126  * sub-coordinator in case of distributed transaction, so it must
127  * be callable remotely and implement Resource
128  */

129 public class SubCoordinator extends PortableRemoteObject JavaDoc implements Resource {
130
131     // ------------------------------------------------------------------
132
// Object state
133
// ------------------------------------------------------------------
134

135     /**
136      * @serial
137      */

138     private TransactionImpl tx = null;
139
140     /**
141      * List of Synchronization objects
142      * @serial
143      */

144     private Vector JavaDoc synchroList = new Vector JavaDoc();
145
146     /**
147      * List of XAResource objects
148      * @serial
149      */

150     private Vector JavaDoc resourceList = new Vector JavaDoc();
151     private Vector JavaDoc javaxxidList = new Vector JavaDoc();
152
153     /**
154      * Keep a reference on TransactionManager
155      * @serial
156      */

157     private TransactionManager tm;
158
159     /**
160      * @serial
161      */

162     private Xid xid = null;
163
164     /**
165      * @serial
166      */

167     private SLog log = null;
168
169     /**
170      * javax.transaction.Status
171      * <dl>
172      * <dt>ACTIVE</dt><dd>transaction started, commit phase not started</dd>
173      * <dt>PREPARING</dt><dd>prepare is being sent to resources</dd>
174      * <dt>PREPARED</dt><dd>prepare is done. Must commit now</dd>
175      * <dt>COMMITTING</dt><dd>commit is being sent to resources</dd>
176      * <dt>COMMITTED</dt><dd>commit was successful</dd>
177      * <dt>ROLLING_BACK</dt><dd>not used</dd>
178      * <dt>MARKED_ROLLBACK</dt><dd>setRollbackOnly has been called</dd>
179      * <dt>ROLLEDBACK</dt>
180      * <dd>transaction has been rolled back (or prepare returned "vote_rollback")</dd>
181      * <dt>UNKNOWN</dt><dd>commit raised heuristics</dd>
182      * <dt>NO_TRANSACTION</dt><dd>cannot get the status value from JTM</dd>
183      * </dl>
184      * @serial
185      */

186     private int status = Status.STATUS_ACTIVE;
187
188     /**
189      * @serial
190      */

191     private boolean beforeCompletionDone = false;
192
193     // ------------------------------------------------------------------
194
// Constructors
195
// ------------------------------------------------------------------
196

197     /**
198      * constructor used by TransactionImpl
199      */

200
201     SubCoordinator(TransactionImpl tx, Xid xid) throws RemoteException JavaDoc {
202
203         if (TraceTm.jta.isDebugEnabled()) {
204             TraceTm.jta.debug("tx="+ tx +", xid="+ xid);
205         }
206         
207         this.tx = tx;
208         this.xid = xid;
209         this.tm = Current.getTransactionManager();
210
211         // increment counter for management
212
Current.getCurrent().incrementBeginCounter();
213         beforeCompletionDone = false;
214     }
215
216     // ------------------------------------------------------------------
217
// Resource interface
218
// ------------------------------------------------------------------
219

220     /**
221      * phase 1 of the 2PC.
222      *
223      * @return int vote commit, rollback, or readonly.
224      */

225
226     public int prepare() throws RemoteException JavaDoc {
227
228         if (TraceTm.jta.isDebugEnabled()) {
229             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
230         }
231         
232         try {
233             tx.doDetach(XAResource.TMSUCCESS);
234         } catch (SystemException e) {
235
236             if (TraceTm.jta.isDebugEnabled()) {
237                 String JavaDoc error =
238                     "Error when detaching XAResource:"
239                     + e
240                     + "--"
241                     + e.getMessage();
242                 TraceTm.jta.debug(error);
243             }
244         }
245
246         switch (status) {
247             case Status.STATUS_MARKED_ROLLBACK :
248                 doBeforeCompletion(false);
249                 doRollback();
250                 return Resource.VOTE_ROLLBACK;
251             case Status.STATUS_COMMITTED :
252                 return Resource.VOTE_COMMIT;
253             default :
254                 doBeforeCompletion(true);
255                 break;
256         }
257
258         // Recheck Status after doBeforeCompletion
259

260         if (status == Status.STATUS_MARKED_ROLLBACK) {
261             TraceTm.jotm.info(
262                 "Rollback during beforeCompletion in SubCoordinator.prepare");
263             doRollback();
264             return Resource.VOTE_ROLLBACK;
265         }
266
267         int ret = doPrepare();
268
269         if (ret == Resource.VOTE_READONLY) {
270             // Transaction completed for this Resource
271
doAfterCompletion();
272         }
273
274         if (TraceTm.jta.isDebugEnabled()) {
275             TraceTm.jta.debug("vote = " + ret);
276         }
277
278         return ret;
279     }
280
281     /**
282      * rollback transaction
283      */

284
285     public void rollback() throws RemoteException JavaDoc {
286
287         if (TraceTm.jta.isDebugEnabled()) {
288             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
289         }
290        
291         try {
292             tx.doDetach(XAResource.TMSUCCESS);
293         } catch (SystemException e) {
294             if (TraceTm.jta.isDebugEnabled()) {
295                 String JavaDoc error =
296                     "Error when detaching XAResource:"
297                     + e
298                     + "--"
299                     + e.getMessage();
300                 TraceTm.jta.debug(error);
301             }
302         }
303
304         switch (status) {
305             case Status.STATUS_ACTIVE :
306             case Status.STATUS_MARKED_ROLLBACK :
307             case Status.STATUS_ROLLING_BACK:
308                 if (TraceTm.jotm.isDebugEnabled()) {
309                     TraceTm.jotm.debug("transaction rolling back");
310                 }
311                 break;
312             case Status.STATUS_PREPARED:
313                 if (TraceTm.jotm.isDebugEnabled()) {
314                     TraceTm.jotm.debug("should not rollback a prepared transaction");
315                 }
316                 break;
317             case Status.STATUS_ROLLEDBACK :
318                 if (TraceTm.jotm.isDebugEnabled()) {
319                     TraceTm.jotm.debug("already rolledback");
320                 }
321                 return;
322             default :
323                 TraceTm.jotm.error(
324                     "rollback: bad status: "
325                         + StatusHelper.getStatusName(status));
326                 return;
327         }
328
329         doBeforeCompletion(false);
330         doRollback();
331     }
332
333     /**
334      * phase 2 of the 2PC.
335      */

336
337     public void commit() throws RemoteException JavaDoc {
338
339         if (TraceTm.jta.isDebugEnabled()) {
340             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
341         }
342
343         switch (status) {
344             case Status.STATUS_PREPARED :
345                 break;
346             default :
347                 TraceTm.jotm.error(
348                     "commit: bad status: "
349                         + StatusHelper.getStatusName(status));
350                 return;
351         }
352
353         doCommit();
354     }
355
356     /**
357      * commit 1 phase. Called either from JTM (distributed transaction) or
358      * from Transaction.commit (local transaction).
359      */

360
361     public void commit_one_phase() throws RemoteException JavaDoc {
362
363         if (TraceTm.jta.isDebugEnabled()) {
364             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
365         }
366
367         switch (status) {
368             case Status.STATUS_ROLLEDBACK :
369                 try {
370                     tx.doDetach(XAResource.TMSUCCESS);
371                 } catch (SystemException e) {
372
373                     if (TraceTm.jta.isDebugEnabled()) {
374                         String JavaDoc error =
375                             "Error when detaching XAResource:"
376                             + e
377                             + "--"
378                             + e.getMessage();
379                         TraceTm.jta.debug(error);
380                     }
381                 }
382                 throw new TransactionRolledbackException();
383             case Status.STATUS_MARKED_ROLLBACK :
384                 doBeforeCompletion(false);
385                 try {
386                     tx.doDetach(XAResource.TMSUCCESS);
387                 } catch (SystemException e) {
388
389                     if (TraceTm.jta.isDebugEnabled()) {
390                         String JavaDoc error =
391                             "Error when detaching XAResource:"
392                             + e
393                             + "--"
394                             + e.getMessage();
395                         TraceTm.jta.debug(error);
396                     }
397                 }
398                 doRollback();
399                 throw new TransactionRolledbackException();
400             case Status.STATUS_COMMITTED :
401                 try {
402                     tx.doDetach(XAResource.TMSUCCESS);
403                 } catch (SystemException e) {
404
405                     if (TraceTm.jta.isDebugEnabled()) {
406                         String JavaDoc error =
407                             "Error when detaching XAResource:"
408                             + e
409                             + "--"
410                             + e.getMessage();
411                         TraceTm.jta.debug(error);
412                     }
413                 }
414                 return;
415             default :
416                 doBeforeCompletion(true);
417                 try {
418                     tx.doDetach(XAResource.TMSUCCESS);
419                 } catch (SystemException e) {
420
421                     if (TraceTm.jta.isDebugEnabled()) {
422                         String JavaDoc error =
423                            "Error when detaching XAResource:"
424                             + e
425                             + "--"
426                             + e.getMessage();
427                         TraceTm.jta.debug(error);
428                     }
429                 }
430                 break;
431         }
432         
433         // status many have changed in doBeforeCompletion
434

435         if (TraceTm.jta.isDebugEnabled()) {
436             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
437         }
438
439         // Recheck Status after doBeforeCompletion
440

441         if (status == Status.STATUS_MARKED_ROLLBACK) {
442             TraceTm.jotm.info(
443                 "Rollback during beforeCompletion in SubCoordinator.commit_one_phase");
444             doRollback();
445             throw new TransactionRolledbackException();
446         }
447
448         // only 1 Resource => 1 phase commit
449

450         if (resourceList.size() == 1) {
451             doOnePhaseCommit();
452             return;
453         }
454
455         // 2 phase commit
456

457         int vote = doPrepare();
458
459         switch (vote) {
460             case Resource.VOTE_COMMIT :
461                 doCommit();
462                 break;
463             case Resource.VOTE_READONLY :
464                 doAfterCompletion();
465                 break;
466             case Resource.VOTE_ROLLBACK :
467                 doRollback();
468                 throw new TransactionRolledbackException();
469         }
470     }
471
472     /**
473      * forget heuristics about this transaction.
474      */

475
476     public void forget() throws RemoteException JavaDoc {
477         if (TraceTm.jta.isDebugEnabled()) {
478             TraceTm.jta.debug("SubCoordinator.forget()");
479         }
480         doForget();
481     }
482
483     // ------------------------------------------------------------------
484
// Other public methods (interface exposed to Transaction object)
485
// ------------------------------------------------------------------
486

487     /**
488      * add a Synchronization to the list
489      *
490      * @param synchro The javax.transaction.Synchronization object for the
491      * transaction associated with the target object
492      *
493      * @exception RollbackException Thrown to indicate that
494      * the transaction has been marked for rollback only.
495      *
496      * @exception IllegalStateException Thrown if the transaction in the
497      * target object is in prepared state or the transaction is inactive.
498      *
499      */

500
501     public void addSynchronization(Synchronization synchro)
502         throws RollbackException, IllegalStateException JavaDoc {
503
504         if (TraceTm.jta.isDebugEnabled()) {
505             TraceTm.jta.debug("synchro="+ synchro);
506             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
507         }
508
509         // check status: should be ACTIVE.
510

511         boolean markedRollback = false;
512
513         switch (status) {
514             case Status.STATUS_MARKED_ROLLBACK :
515             case Status.STATUS_ROLLEDBACK :
516                 markedRollback = true;
517                 break;
518             case Status.STATUS_ACTIVE :
519                 break;
520             default :
521                 String JavaDoc errorMsg =
522                     "addSynchronization: bad status = "
523                         + StatusHelper.getStatusName(status);
524                 TraceTm.jotm.error(errorMsg);
525                 throw new IllegalStateException JavaDoc(errorMsg);
526         }
527
528         // Add synchro to the list of local synchros
529

530         synchroList.addElement(synchro);
531
532         // If transaction marked rollback only, we add synchro but we throw
533
// the correct exception because nobody can presume what will be done in the
534
// Synchronization object, so we must send it beforeCompletion and afterCompletion
535
// even in case of rollback.
536

537         if (markedRollback) {
538             if (TraceTm.jta.isDebugEnabled()) {
539             TraceTm.jta.debug("SubCoordinator.addSynchronization: transaction rollback only");
540             }
541             throw new RollbackException();
542         }
543
544     }
545
546     /**
547      * add a XAResource to the list
548      *
549      * @param xares XAResource to register
550      *
551      * @return true if this datasource was already known
552      *
553      * @exception IllegalStateException Thrown if the transaction in the
554      * target object is in prepared state or the transaction is inactive.
555      */

556
557     public synchronized boolean addResource(XAResource JavaDoc xares)
558         throws IllegalStateException JavaDoc {
559
560         if (TraceTm.jta.isDebugEnabled()) {
561             TraceTm.jta.debug("xares="+ xares);
562             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
563         }
564
565         // check status: should be ACTIVE.
566

567         boolean markedRollback = false;
568
569         switch (status) {
570             case Status.STATUS_MARKED_ROLLBACK :
571                 markedRollback = true;
572                 break;
573             case Status.STATUS_ACTIVE :
574                 break;
575             default :
576                 String JavaDoc errorMsg =
577                     "SubCoordinator.addResource: bad status= "
578                         + StatusHelper.getStatusName(status);
579                 TraceTm.jotm.error(errorMsg);
580                 throw new IllegalStateException JavaDoc(errorMsg);
581         }
582
583         // Check if this DataSource is already known
584
// -> we must register only ONE resource per DataSource.
585

586         boolean found = false;
587
588         for (int i = 0; i < resourceList.size(); i++) {
589             XAResource JavaDoc res = (XAResource JavaDoc) resourceList.elementAt(i);
590
591             try {
592                 if (res.isSameRM(xares)) {
593                     found = true;
594                     break;
595                 }
596             } catch (XAException JavaDoc e) {
597                 String JavaDoc error =
598                 "Cannot send res.isSameRM:"
599                     + e
600                     + " (error code = "
601                     + e.errorCode
602                     + ") --"
603                     + e.getMessage();
604                 TraceTm.jotm.error(
605                     "Exception on resource.isSameRM: "+ error);
606             }
607         }
608
609         // add this XAResource to the list
610

611         if (found == false) {
612             if (TraceTm.jta.isDebugEnabled()) {
613                 TraceTm.jta.debug("new XAResource added to the list");
614             }
615             resourceList.addElement(xares);
616         }
617
618         // If transaction marked rollback only, we enlist resource but we throw
619
// the correct exception. It is important to enlist the Resource because
620
// if we don't, the database would be updated although transaction has been
621
// rolled back.
622

623         if (markedRollback) {
624             if (TraceTm.jta.isDebugEnabled()) {
625             TraceTm.jta.debug("SubCoordinator.addResource: transaction set rollback only");
626             }
627         }
628
629         return found;
630     }
631
632     public synchronized void addJavaxXid(javax.transaction.xa.Xid JavaDoc javaxxid) {
633
634         if (TraceTm.jta.isDebugEnabled()) {
635             TraceTm.jta.debug("addJavaxXid javaxxid="+ javaxxid);
636         }
637
638         // add this javaxxid to the List at the index location of XAResource
639

640         javaxxidList.addElement(javaxxid);
641         
642         if (TraceTm.jta.isDebugEnabled()) {
643             TraceTm.jta.debug("new JavaxXid added to the list");
644         }
645
646     }
647
648     /**
649      * return the status of this transaction
650      */

651
652     public int getStatus() {
653
654         if (TraceTm.jta.isDebugEnabled()) {
655             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
656         }
657
658         return status;
659     }
660
661     public javax.transaction.xa.Xid JavaDoc getJavaxXid(int xaresindex) {
662         javax.transaction.xa.Xid JavaDoc myjavaxxid = (javax.transaction.xa.Xid JavaDoc) javaxxidList.elementAt(xaresindex);
663         return myjavaxxid;
664     }
665     
666     /**
667      * set the transaction "rollback only"
668      */

669
670     public void setRollbackOnly() {
671
672         if (TraceTm.jta.isDebugEnabled()) {
673             TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status));
674         }
675
676         switch (status) {
677             case Status.STATUS_ACTIVE :
678             case Status.STATUS_UNKNOWN :
679             case Status.STATUS_PREPARING :
680                 status = Status.STATUS_MARKED_ROLLBACK;
681                 break;
682             case Status.STATUS_MARKED_ROLLBACK :
683             case Status.STATUS_ROLLING_BACK :
684                 break;
685             case Status.STATUS_PREPARED :
686             case Status.STATUS_COMMITTED :
687             case Status.STATUS_ROLLEDBACK :
688             case Status.STATUS_NO_TRANSACTION :
689             case Status.STATUS_COMMITTING :
690                 TraceTm.jotm.error("Cannot set transaction as rollback only");
691                 TraceTm.jotm.error("Bad status="+ StatusHelper.getStatusName(status));
692                 break;
693         }
694     }
695
696     // ------------------------------------------------------------------
697
// private methods
698
// ------------------------------------------------------------------
699

700     /**
701      * forget Transaction
702      */

703
704     private void doForget() throws RemoteException JavaDoc {
705         if (TraceTm.jta.isDebugEnabled()) {
706             TraceTm.jta.debug("SubCoordinator.doForget()");
707         }
708
709         boolean exception = false;
710
711         for (int i = 0; i < resourceList.size(); i++) {
712             // Tell this Resource to forget the transaction
713
// Remove from the list ?
714
XAResource JavaDoc xar = (XAResource JavaDoc) resourceList.elementAt(i);
715             
716             javax.transaction.xa.Xid JavaDoc myjavaxxid = (javax.transaction.xa.Xid JavaDoc)javaxxidList.elementAt(i);
717             Xid xid = new XidImpl( this.xid, i );
718
719             if (TraceTm.jta.isDebugEnabled()) {
720                 TraceTm.jta.debug("xid= " + xid);
721                 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
722                 TraceTm.jta.debug("forgotten with resource= " + xar);
723             }
724
725             try {
726                 xar.forget(myjavaxxid);
727                 // xar.forget(xid);
728
} catch (XAException JavaDoc e) {
729                 String JavaDoc error =
730                 "Cannot send xar.forget:"
731                     + e
732                     + " (error code = "
733                     + e.errorCode
734                     + ") --"
735                     + e.getMessage();
736                 TraceTm.jotm.error(
737                     "Got XAException from xar.forget: "+ error);
738                 exception = true;
739             }
740         }
741
742         if (exception) {
743             throw new RemoteException JavaDoc("XAException on forget");
744         }
745
746         unexportObject(this);
747     }
748
749     /**
750      * 2PC phase 1 (prepare)
751      * Basically, send prepare on each XAResource and
752      * collect the results.
753      */

754
755     private synchronized int doPrepare() throws RemoteException JavaDoc {
756         if (TraceTm.jta.isDebugEnabled()) {
757             TraceTm.jta.debug("SubCoordinator.doPrepare()");
758         }
759
760         String JavaDoc jotmPrepareRecord = "PREPARE";
761
762         int ret = VOTE_READONLY;
763         int errors = 0;
764
765         // No resource
766

767         if (resourceList.size() == 0) {
768             // increment counter for management
769
Current.getCurrent().incrementCommitCounter();
770             status = Status.STATUS_COMMITTED;
771             return ret;
772         }
773
774         // Creates a log for that transaction, where we will add all the
775
// resources that replied VOTE_COMMIT to prepare.
776
// Do not flush the log on disk before decision to commit.
777

778         log = new SLog();
779
780         // Sends prepare to each resource while no error
781
// In case of prepare on sub-coord. we may have only 1 resource.
782

783         status = Status.STATUS_PREPARING;
784
785         for (int i = 0; i < resourceList.size(); i++) {
786             XAResource JavaDoc res = (XAResource JavaDoc) resourceList.elementAt(i);
787             javax.transaction.xa.Xid JavaDoc myjavaxxid = (javax.transaction.xa.Xid JavaDoc) javaxxidList.elementAt(i);
788
789             Xid xid = new XidImpl( this.xid, i );
790
791             if (errors > 0) {
792
793                 if (TraceTm.jta.isDebugEnabled()) {
794                     TraceTm.jta.debug("xid= " + xid);
795                     TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
796                     TraceTm.jta.debug("rolled back with resource= " + res);
797                 }
798
799                 try {
800                     res.rollback(myjavaxxid);
801                     // res.rollback(xid);
802
} catch (XAException JavaDoc e) {
803                     String JavaDoc error =
804                     "Cannot send res.rollback:"
805                         + e
806                         + " (error code = "
807                         + e.errorCode
808                         + ") --"
809                         + e.getMessage();
810                     TraceTm.jotm.error(
811                         "Got XAException from res.rollback: "+ error);
812                     // Nothing to do ?
813
}
814             } else {
815                 if (TraceTm.jta.isDebugEnabled()) {
816                     TraceTm.jta.debug("xid= " + xid);
817                     TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
818                     TraceTm.jta.debug("prepared with resource= " + res);
819                 }
820
821                 try {
822                     switch (res.prepare(myjavaxxid)) {
823                     // switch (res.prepare(xid)) {
824
case XAResource.XA_OK :
825                             log.addResource(res,xid);
826                             ret = VOTE_COMMIT;
827                             break;
828                         case XAResource.XA_RDONLY :
829                             break;
830                     }
831                 } catch (XAException JavaDoc e) {
832                     String JavaDoc error =
833                     "Cannot send res.prepare:"
834                         + e
835                         + " (error code = "
836                         + e.errorCode
837                         + ") --"
838                         + e.getMessage();
839                     TraceTm.jotm.error(
840                         "Got XAException from res.prepare: "+ error);
841                     ret = VOTE_ROLLBACK;
842                     errors++;
843                 }
844             }
845         }
846
847         // Update the status, depending on vote result
848
// If all resources returned READ_ONLY, we can forget the transaction
849

850         switch (ret) {
851             case VOTE_READONLY :
852                 // increment counter for management
853
Current.getCurrent().incrementCommitCounter();
854                 status = Status.STATUS_COMMITTED;
855                 break;
856             case VOTE_COMMIT :
857                 status = Status.STATUS_PREPARED;
858                 break;
859             case VOTE_ROLLBACK :
860                 status = Status.STATUS_ROLLING_BACK;
861                 break;
862         }
863
864         // return the global vote
865
return ret;
866     }
867
868     /**
869      * 2PC - phase 2 (commit)
870      * See JTM for heuristics management
871      */

872
873     private synchronized int doCommit() throws RemoteException JavaDoc {
874         if (TraceTm.jta.isDebugEnabled()) {
875             TraceTm.jta.debug("SubCoordinator.doCommit()");
876         }
877
878         // We build the Recovery Record in doCommit just in case of a system crash
879
// Store the Recovery Record using HOWL so it can manage for us.
880
//
881
// The Recovery Record consists of two record types:
882
// 1. XA Transaction recovery record
883
// 2. XA Resource recovery record
884
//
885
// The XA Transaction recovery record format:
886
// recovery record type1 (byte[3]) - 'RR1'
887
// recovery record stored date-time (long) - 8 bytes
888
// length of transaction's xid (int) - 4 bytes
889
// transaction's xid (byte []) - txxid.length bytes
890
// length of transactions store date-time (int) - 4 bytes
891
// transactions created date-time (byte []) - Date.length bytes
892
// count of XA resources assigned to the transaction (int) - 4 bytes
893
//
894
// The XA Resource recovery record format:
895
// recovery record type2 (byte[3]) = 'RR2'
896
// length of XA resource (int) - 4 bytes
897
// XA resource (byte []) - xares.length bytes
898
// length of XID assigned to XA resource (int) - 4 bytes
899
// XID assigned to XA resource (byte []) - xid.length bytes
900
// XID status-state (int) = 4 bytes
901
//
902
// The JOTM Done recovery record format:
903
// recovery record type3 (byte[3]) = 'RR3'
904
// JOTM done value (byte[8]) = 'JOTMDONE'
905

906         // First check that a log is initialized
907

908         if (log == null) {
909             TraceTm.jotm.error("doCommit: no log");
910             return -1;
911         }
912         
913         int errors = 0;
914         int commitnb = 0;
915         int heuristicnb = 0;
916         
917         List JavaDoc loggedResources = log.getLoggedResources();
918         List JavaDoc loggedXids = log.getLoggedXids();
919         
920         XACommittingTx xaCommitTx = null;
921         XACommittingTx xaCommitTxRewrite = null;
922
923         byte [] [] recoveryBuffer = new byte [loggedResources.size() + 1] []; // loggedResources + 1 (recoveryRecord1)
924

925         byte [] recoveryRecord1 = null;
926         byte [] recoveryRecord2 = null;
927         ByteBuffer JavaDoc rr1 = null;
928         ByteBuffer JavaDoc rr2 = null;
929
930         String JavaDoc rt1 = "RR1";
931         String JavaDoc rt2 = "RR2";
932         byte [] jotmDone = new byte [11];
933         byte [] [] jotmDoneRecord = new byte [1] [11];
934         
935         if (Current.getDefaultRecovery()) {
936             Xid txxid = tx.getXid();
937             String JavaDoc stxxid = txxid.toString(true);
938             int txxidlength = stxxid.length();
939             String JavaDoc txdate = tx.getTxDate();
940             int txdatelength= txdate.length();
941             long rcdate = System.currentTimeMillis();
942
943             recoveryRecord1 = new byte[3+8+4+txxidlength+4+txdatelength+4];
944
945             rr1 = ByteBuffer.wrap(recoveryRecord1);
946             rr1.put(rt1.getBytes());
947             rr1.putLong(rcdate);
948             rr1.putInt(txxidlength);
949             rr1.put(stxxid.getBytes());
950             rr1.putInt(txdatelength);
951             rr1.put(txdate.getBytes());
952             rr1.putInt(loggedResources.size());
953
954             recoveryBuffer [0] = rr1.array();
955
956             jotmDone = "RR3JOTMDONE".getBytes();
957
958             for (int i = 0; i < loggedResources.size(); i++) {
959                 XAResource JavaDoc res = (XAResource JavaDoc) loggedResources.get(i);
960                 Xid xid = (Xid)loggedXids.get(i);
961                 int rmindex = 99; // Store 99, at recovery we will store the correct index
962

963                 if (TraceTm.recovery.isDebugEnabled()) {
964                     TraceTm.recovery.debug("recovery xid= " + xid);
965                     TraceTm.recovery.debug("recovery resource= " + res);
966                 }
967
968                 int reslength = res.toString().length();
969                 int resnamelength = res.getClass().getName().length();
970                 int xidlength = xid.toString(true).length();
971
972                 recoveryRecord2 = new byte[3+4+4+reslength+4+resnamelength+4+xidlength+4];
973
974                 // ByteBuffer rr2 = ByteBuffer.wrap(recoveryRecord2);
975
rr2 = ByteBuffer.wrap(recoveryRecord2);
976                 rr2.put(rt2.getBytes());
977                 rr2.putInt(rmindex);
978                 rr2.putInt(reslength);
979                 rr2.put(res.toString().getBytes());
980                 rr2.putInt(resnamelength);
981                 rr2.put(res.getClass().getName().getBytes());
982                 rr2.putInt(xidlength);
983                 rr2.put(xid.toString(true).getBytes());
984                 rr2.putInt(status);
985                 
986                 if (TraceTm.recovery.isDebugEnabled()) {
987                     TraceTm.recovery.debug("Prepare Init RR2 to Recovery Buffer");
988                 }
989                 recoveryBuffer [i+1] = rr2.array(); // First record (0) is always rr1
990
}
991
992             try {
993                 xaCommitTx = TransactionRecoveryImpl.getTransactionRecovery().howlCommitLog(recoveryBuffer);
994             } catch (Exception JavaDoc e) {
995                 // If we cannot write the Log, we cannot perform recovery, rollback transaction
996
status = Status.STATUS_ROLLEDBACK;
997
998                 String JavaDoc howlerror =
999                     "Cannot howlCommitLog:"
1000                    + e
1001                    + " --"
1002                    + e.getMessage();
1003                TraceTm.jotm.error("Got LogException from howlCommitLog: "+ howlerror);
1004                xaCommitTx = null;
1005                doAfterCompletion();
1006                log.forgetLog();
1007
1008                throw new TransactionRolledbackException();
1009            }
1010        }
1011
1012        // Status Transaction = committing
1013

1014        status = Status.STATUS_COMMITTING;
1015
1016        // Send commit to each resource prepared
1017

1018        for (int i = 0; i < loggedResources.size(); i++) {
1019            XAResource JavaDoc res = (XAResource JavaDoc) loggedResources.get(i);
1020            
1021            javax.transaction.xa.Xid JavaDoc myjavaxxid = (javax.transaction.xa.Xid JavaDoc) javaxxidList.elementAt(i);
1022            Xid xid = (Xid) loggedXids.get(i);
1023
1024            // Commit every resource that have been logged even if any of
1025
// the commit resources fail. During recovery, the administrator
1026
// will resolve any incomplete transactions.
1027

1028            if (TraceTm.jta.isDebugEnabled()) {
1029                TraceTm.jta.debug("xid= " + xid);
1030                TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
1031                TraceTm.jta.debug("attempting commit with resource= " + res);
1032            }
1033            
1034            if (Current.getDefaultRecovery()) {
1035                int rmindex = 99; // Store 99, at recovery we will store the correct index
1036
int reslength = res.toString().length();
1037                int resnamelength = res.getClass().getName().length();
1038                int xidlength = xid.toString(true).length();
1039            
1040                recoveryRecord2 = new byte[3+4+4+reslength+4+resnamelength+4+xidlength+4];
1041
1042                rr2 = ByteBuffer.wrap(recoveryRecord2);
1043
1044                rr2.put(rt2.getBytes());
1045                rr2.putInt(rmindex);
1046                rr2.putInt(reslength);
1047                rr2.put(res.toString().getBytes());
1048                rr2.putInt(resnamelength);
1049                rr2.put(res.getClass().getName().getBytes());
1050                rr2.putInt(xidlength);
1051                rr2.put(xid.toString(true).getBytes());
1052            }
1053
1054            // commit resource
1055

1056            try {
1057                res.commit(myjavaxxid, false);
1058                // res.commit(xid, false);
1059

1060                if (Current.getDefaultRecovery()) {
1061                    rr2.putInt(Status.STATUS_COMMITTED);
1062                }
1063                
1064                commitnb++; // an XAresource was committed
1065
} catch (XAException JavaDoc e) {
1066                switch (e.errorCode) {
1067                    case XAException.XA_HEURHAZ :
1068                    case XAException.XA_HEURCOM :
1069                    case XAException.XA_HEURRB :
1070                    case XAException.XA_HEURMIX :
1071                        if (TraceTm.jta.isDebugEnabled()) {
1072                            TraceTm.jta.debug("Heuristic condition= " + e.getMessage());
1073                        }
1074
1075                        if (Current.getDefaultRecovery()) {
1076                            rr2.putInt(Status.STATUS_UNKNOWN);
1077                        }
1078                        // break;
1079
case XAException.XAER_RMERR :
1080                    case XAException.XAER_NOTA :
1081                    case XAException.XAER_INVAL :
1082                    case XAException.XAER_PROTO:
1083                    case XAException.XAER_RMFAIL :
1084                        if (TraceTm.jta.isDebugEnabled()) {
1085                            TraceTm.jta.debug("RM error= " + e.getMessage());
1086                        }
1087
1088                        if (Current.getDefaultRecovery()) {
1089                            rr2.putInt(Status.STATUS_COMMITTING);
1090                        }
1091                        // break;
1092
default :
1093                        if (TraceTm.jta.isDebugEnabled()) {
1094                            TraceTm.jta.debug("Default error= " + e.getMessage());
1095                        }
1096
1097                        if (Current.getDefaultRecovery()) {
1098                            rr2.putInt(Status.STATUS_ROLLEDBACK);
1099                        }
1100                }
1101                
1102                String JavaDoc error =
1103                    "Cannot send res.commit:"
1104                    + e
1105                    + " (error code = "
1106                    + e.errorCode
1107                    + ") --"
1108                    + e.getMessage();
1109                TraceTm.jotm.error(
1110                    "Got XAException from res.commit: "+ error);
1111
1112                errors++;
1113                if (commitnb > 0)
1114                    heuristicnb++;
1115            }
1116            
1117            if (Current.getDefaultRecovery()) {
1118                if (TraceTm.recovery.isDebugEnabled()) {
1119                    TraceTm.recovery.debug("Prepare New RR2 to Recovery Buffer");
1120                }
1121                recoveryBuffer [i+1] = rr2.array(); // First record (0) is always rr1
1122
}
1123        }
1124
1125        if (errors == 0) {
1126            // increment counter for management
1127
Current.getCurrent().incrementCommitCounter();
1128            // Everything's fine.
1129
status = Status.STATUS_COMMITTED;
1130
1131
1132            if (Current.getDefaultRecovery()) {
1133                try {
1134                    if (TraceTm.recovery.isDebugEnabled()) {
1135                        TraceTm.recovery.debug("Done howl log, all okay");
1136                    }
1137                    
1138                    jotmDoneRecord [0] = jotmDone;
1139                    TransactionRecoveryImpl.getTransactionRecovery().howlDoneLog(jotmDoneRecord, xaCommitTx);
1140                } catch (Exception JavaDoc f) {
1141                    String JavaDoc howlerror =
1142                        "Cannot howlDoneLog:"
1143                        + f
1144                        + "--"
1145                        + f.getMessage();
1146                    TraceTm.jotm.error("Got LogException from howlDoneLog: "+ howlerror);
1147                }
1148            }
1149            
1150            doAfterCompletion();
1151            log.forgetLog();
1152
1153            return 0;
1154        }
1155
1156        if (heuristicnb == 0) { // commits on all XAResources failed, just rollback
1157
// Transaction has been eventually rolled back
1158
status = Status.STATUS_ROLLEDBACK;
1159            
1160            if (Current.getDefaultRecovery()) {
1161                try {
1162                    jotmDoneRecord [0] = jotmDone;
1163                    TransactionRecoveryImpl.getTransactionRecovery().howlDoneLog(jotmDoneRecord, xaCommitTx);
1164                } catch (Exception JavaDoc f) {
1165                    String JavaDoc howlerror =
1166                        "Cannot howlDoneLog"
1167                        + f
1168                        + "--"
1169                        + f.getMessage();
1170                    TraceTm.jotm.error("Got LogException from howlDoneLog: "+ howlerror);
1171                }
1172            }
1173
1174            doAfterCompletion();
1175            log.forgetLog();
1176
1177            throw new TransactionRolledbackException();
1178        }
1179
1180        // Log heuristics if errors
1181

1182        if (heuristicnb != 0) { // some XAResource commits succeeded, others failed, heuristicmixed
1183

1184            if (Current.getDefaultRecovery()) {
1185                try {
1186                    if (TraceTm.recovery.isDebugEnabled()) {
1187                        TraceTm.recovery.debug("Rewrite HowlCommitLog");
1188                    }
1189                    xaCommitTxRewrite = TransactionRecoveryImpl.getTransactionRecovery().howlCommitLog(recoveryBuffer);
1190                } catch (Exception JavaDoc e) {
1191                    // If we cannot write the Log, we cannot perform recovery, rollback transaction
1192
status = Status.STATUS_UNKNOWN;
1193
1194                    String JavaDoc howlerror =
1195                        "Cannot howlCommitLog:"
1196                        + e
1197                        + " --"
1198                        + e.getMessage();
1199                    TraceTm.jotm.error("Got LogException from howlCommitLog: "+ howlerror);
1200                    xaCommitTx = null;
1201                
1202                    doAfterCompletion();
1203                    log.forgetLog();
1204
1205                    throw new TransactionRolledbackException();
1206                }
1207
1208                // Transaction state is unknown, now job for administrator
1209
status = Status.STATUS_UNKNOWN;
1210
1211                try {
1212                    jotmDoneRecord [0] = jotmDone;
1213                    TransactionRecoveryImpl.getTransactionRecovery().howlDoneLog(jotmDoneRecord, xaCommitTx);
1214                } catch (Exception JavaDoc f) {
1215                    String JavaDoc howlerror =
1216                        "Cannot howlDoneLog"
1217                        + f
1218                        + "--"
1219                        + f.getMessage();
1220                     TraceTm.jotm.error("Got LogException from howlDoneLog: "+ howlerror);
1221                }
1222            }
1223        }
1224        
1225        status = Status.STATUS_UNKNOWN;
1226
1227        doAfterCompletion();
1228        return -1;
1229    }
1230
1231    /**
1232     * 1PC (commit one phase)
1233     */

1234
1235    private synchronized void doOnePhaseCommit() throws RemoteException JavaDoc {
1236        if (TraceTm.jta.isDebugEnabled()) {
1237            TraceTm.jta.debug("SubCoordinator.doOnePhaseCommit()");
1238        }
1239
1240        // Only 1 resource: commit with onePhase=true
1241

1242        status = Status.STATUS_COMMITTING;
1243
1244        XAResource JavaDoc res = (XAResource JavaDoc) resourceList.elementAt(0);
1245        javax.transaction.xa.Xid JavaDoc myjavaxxid = (javax.transaction.xa.Xid JavaDoc) javaxxidList.elementAt(0);
1246        Xid xid = new XidImpl( this.xid, 0 );
1247
1248        if (TraceTm.jta.isDebugEnabled()) {
1249            TraceTm.jta.debug("xid= " + xid);
1250            TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
1251            TraceTm.jta.debug("one phase commit with resource= " + res);
1252        }
1253
1254        try {
1255            res.commit(myjavaxxid, true);
1256            // res.commit(xid, true);
1257

1258            // increment counter for management
1259
Current.getCurrent().incrementCommitCounter();
1260            status = Status.STATUS_COMMITTED;
1261        } catch (XAException JavaDoc e) {
1262            status = Status.STATUS_UNKNOWN;
1263            String JavaDoc error =
1264                "Cannot send res.commit:"
1265                    + e
1266                    + " (error code = "
1267                    + e.errorCode
1268                    + ") --"
1269                    + e.getMessage();
1270            TraceTm.jotm.error(
1271                "Got XAException from res.commit: "+ error);
1272
1273            if (e.errorCode == XAException.XA_RBROLLBACK) {
1274                throw new TransactionRolledbackException("XAException:"+ error);
1275            }
1276            throw new RemoteException JavaDoc("XAException:"+ error);
1277        } finally {
1278            doAfterCompletion();
1279        }
1280    }
1281
1282    /**
1283     * Rollback every resource involved
1284     */

1285
1286    private synchronized void doRollback() throws RemoteException JavaDoc {
1287        if (TraceTm.jta.isDebugEnabled()) {
1288            TraceTm.jta.debug("SubCoordinator.doRollback()");
1289        }
1290
1291        status = Status.STATUS_ROLLEDBACK;
1292        boolean heurroll = false;
1293        String JavaDoc rberror = null;
1294        int errors = 0;
1295
1296        // roll back each resource
1297
for (int i = 0; i < resourceList.size(); i++) {
1298
1299            XAResource JavaDoc res = (XAResource JavaDoc) resourceList.elementAt(i);
1300            javax.transaction.xa.Xid JavaDoc myjavaxxid = (javax.transaction.xa.Xid JavaDoc) javaxxidList.elementAt(i);
1301            Xid xid = new XidImpl( this.xid, i );
1302
1303            if (TraceTm.jta.isDebugEnabled()) {
1304                TraceTm.jta.debug("xid= " + xid);
1305                TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
1306                TraceTm.jta.debug("rolled back with resource= " + res);
1307            }
1308            
1309            // Rollback every resource that have been logged even if any of
1310
// the rollback resources fail. During recovery, the administrator
1311
// will resolve any incomplete transactions.
1312

1313            try {
1314                res.rollback(myjavaxxid);
1315                // res.rollback(xid);
1316
} catch (XAException JavaDoc e) {
1317                switch (e.errorCode) {
1318                    case XAException.XA_HEURHAZ :
1319                    case XAException.XA_HEURCOM :
1320                    case XAException.XA_HEURRB :
1321                    case XAException.XA_HEURMIX :
1322                        if (TraceTm.jta.isDebugEnabled()) {
1323                            TraceTm.jta.debug("Heuristic condition= " + e.getMessage());
1324                        }
1325                        heurroll = true;
1326                    case XAException.XAER_RMERR :
1327                    case XAException.XAER_NOTA :
1328                    case XAException.XAER_INVAL :
1329                    case XAException.XAER_PROTO:
1330                    case XAException.XAER_RMFAIL :
1331                        if (TraceTm.jta.isDebugEnabled()) {
1332                            TraceTm.jta.debug("RM error= " + e.getMessage());
1333                        }
1334                    default :
1335                        if (TraceTm.jta.isDebugEnabled()) {
1336                            TraceTm.jta.debug("Default error= " + e.getMessage());
1337                        }
1338                 }
1339
1340                 rberror =
1341                     "Cannot send res.rollback:"
1342                     + e
1343                     + " (error code = "
1344                     + e.errorCode
1345                     + ") --"
1346                     + e.getMessage();
1347                 TraceTm.jotm.error(
1348                     "Got XAException from res.rollback: "+ rberror);
1349                 
1350                 errors++;
1351            }
1352        }
1353
1354        // raise Heuristic exception if XAResource returned heuristic
1355

1356        if (heurroll) {
1357            throw new HeuristicRollback();
1358        }
1359        
1360        // raise exception if error on a resource
1361

1362        if (errors != 0) {
1363            throw new RemoteException JavaDoc("rollback: Unexpected XAException:"+ rberror);
1364        }
1365
1366        // increment counter for management
1367

1368        Current.getCurrent().incrementRollbackCounter();
1369        
1370        doAfterCompletion();
1371
1372    }
1373
1374    /**
1375     * before completion
1376     *
1377     * @param boolean true if completion ok, false if rollback
1378     */

1379
1380    private void doBeforeCompletion(boolean committing) {
1381        if (TraceTm.jta.isDebugEnabled()) {
1382            TraceTm.jta.debug("doBeforeCompletion committing= "+ committing);
1383        }
1384
1385        if (beforeCompletionDone)
1386            return;
1387
1388        // Unset the timer for this transaction, if any
1389

1390        tx.unsetTimer();
1391
1392        // For each synchro, send beforeCompletion (not if rollback)
1393

1394        if (committing && synchroList.size() > 0) {
1395            // We must be in the correct transaction context
1396
// See JTA spec. page 13 (3.3.2)
1397
// because at beforeCompletion, the bean will write its cache
1398

1399            // Check the trivial case where we already have the correct tx context
1400

1401            Transaction mytx = null;
1402            boolean suspended = false;
1403            boolean resumed = false;
1404
1405            try {
1406                mytx = tm.getTransaction();
1407            } catch (SystemException e) {
1408                if (TraceTm.jta.isDebugEnabled()) {
1409                    String JavaDoc error =
1410                        "Cannot get transaction:"
1411                        + e
1412                        + "--"
1413                        + e.getMessage();
1414                    TraceTm.jta.debug(error);
1415                }
1416            }
1417
1418            // Suspend if another tx context
1419

1420            if (mytx != null && mytx.equals(tx) == false) {
1421                try {
1422                    tm.suspend();
1423                    suspended = true;
1424                } catch (SystemException e) {
1425                    if (TraceTm.jta.isDebugEnabled()) {
1426                        String JavaDoc error =
1427                            "Cannot suspend transaction:"
1428                            + e
1429                            + "--"
1430                            + e.getMessage();
1431                        TraceTm.jta.debug(error);
1432                    }
1433                }
1434            }
1435
1436            // Resume the good tx context
1437

1438            if (mytx == null || suspended) {
1439                try {
1440                    tm.resume(tx);
1441                    resumed = true;
1442                } catch (SystemException e) {
1443                    if (TraceTm.jta.isDebugEnabled()) {
1444                        String JavaDoc error =
1445                            "Cannot resume transaction:"
1446                            + e
1447                            + "--"
1448                            + e.getMessage();
1449                        TraceTm.jta.debug(error);
1450                    }
1451                } catch (InvalidTransactionException e) {
1452                    if (TraceTm.jta.isDebugEnabled()) {
1453                        String JavaDoc error =
1454                            "Cannot resume transaction:"
1455                            + e
1456                            + "--"
1457                            + e.getMessage();
1458                        TraceTm.jta.debug(error);
1459                    }
1460                } catch (IllegalStateException JavaDoc e) {
1461                    if (TraceTm.jta.isDebugEnabled()) {
1462                        String JavaDoc error =
1463                            "Cannot resume transaction:"
1464                            + e
1465                            + "--"
1466                            + e.getMessage();
1467                        TraceTm.jta.debug(error);
1468                    }
1469                }
1470            }
1471
1472            // Call the synchronizations
1473
// beforeCompletion may set the TX rollbackonly if something goes wrong
1474

1475            if (TraceTm.jta.isDebugEnabled()) {
1476                TraceTm.jta.debug("sychronization list size= " + synchroList.size());
1477            }
1478
1479            for (int i = 0; i < synchroList.size(); i++) {
1480                Synchronization sync =
1481                    (Synchronization) synchroList.elementAt(i);
1482
1483                if (TraceTm.jta.isDebugEnabled()) {
1484                    TraceTm.jta.debug("Synchronization sync= " + sync);
1485                }
1486
1487                sync.beforeCompletion();
1488            }
1489
1490            // reset context as it was before
1491

1492            if (resumed) {
1493                try {
1494                    tm.suspend();
1495                } catch (SystemException e) {
1496                    if (TraceTm.jta.isDebugEnabled()) {
1497                        String JavaDoc error =
1498                            "Cannot suspend transaction:"
1499                            + e
1500                            + "--"
1501                            + e.getMessage();
1502                        TraceTm.jta.debug(error);
1503                    }
1504                }
1505            }
1506
1507            if (suspended) {
1508                try {
1509                    tm.resume(mytx);
1510                    resumed = true;
1511                } catch (SystemException e) {
1512                    if (TraceTm.jta.isDebugEnabled()) {
1513                        String JavaDoc error =
1514                            "Cannot resume transaction:"
1515                            + e
1516                            + "--"
1517                            + e.getMessage();
1518                        TraceTm.jta.debug(error);
1519                    }
1520                } catch (InvalidTransactionException e) {
1521                    if (TraceTm.jta.isDebugEnabled()) {
1522                        String JavaDoc error =
1523                            "Cannot resume transaction:"
1524                            + e
1525                            + "--"
1526                            + e.getMessage();
1527                        TraceTm.jta.debug(error);
1528                    }
1529                } catch (IllegalStateException JavaDoc e) {
1530                    if (TraceTm.jta.isDebugEnabled()) {
1531                        String JavaDoc error =
1532                            "Cannot resume transaction:"
1533                            + e
1534                            + "--"
1535                            + e.getMessage();
1536                        TraceTm.jta.debug(error);
1537                    }
1538                }
1539            }
1540        }
1541
1542        beforeCompletionDone = true;
1543    }
1544    
1545    /**
1546     * after completion
1547     */

1548
1549    private void doAfterCompletion() {
1550        if (TraceTm.jta.isDebugEnabled()) {
1551            TraceTm.jta.debug("doAfterCompletion()");
1552        }
1553
1554        // For each synchro, send afterCompletion
1555
/// CompletedTransactionListener has been replaced by Synchronization
1556

1557        if (TraceTm.jta.isDebugEnabled()) {
1558            TraceTm.jta.debug("sychronization list size= "+ synchroList.size());
1559        }
1560
1561        for (int i = 0; i < synchroList.size(); i++) {
1562            Synchronization sync = (Synchronization) synchroList.elementAt(i);
1563
1564            if (TraceTm.jta.isDebugEnabled()) {
1565                TraceTm.jta.debug("Synchronization sync= " + sync);
1566                TraceTm.jta.debug("sync.afterCompletion status= " + StatusHelper.getStatusName(status));
1567            }
1568
1569            sync.afterCompletion(status);
1570        }
1571
1572        // Forget this transaction.
1573
// LATER:
1574
// - Should not forget it in case of heuristics (for recovery)
1575
// - May be this could be deferred in case of retry from a client: use a timer.
1576

1577        Current.getCurrent().forgetTx(tx.getXid());
1578
1579        if (TraceTm.jta.isDebugEnabled()) {
1580            TraceTm.jta.debug("SubCoordinator unexported [subcoord=" + this + "]");
1581        }
1582
1583        try {
1584            unexportObject(this);
1585        } catch (Exception JavaDoc e) {}
1586    }
1587
1588    // ------------------------------------------------------------------
1589
// new method for TxImpl
1590
// ------------------------------------------------------------------
1591

1592    public int getXaresIndex( XAResource JavaDoc xares ) {
1593
1594        if (TraceTm.jta.isDebugEnabled()) {
1595            TraceTm.jta.debug("getXaresIndex xares= "+ xares);
1596            TraceTm.jta.debug("resourceList.size= " + resourceList.size());
1597        }
1598
1599        int xaresIndex = -1;
1600
1601        // first, search for an XAResource with the same object reference
1602
if (TraceTm.jta.isDebugEnabled()) {
1603            TraceTm.jta.debug("search xares with same obj ref");
1604        }
1605        
1606        for (int i = 0; i < resourceList.size(); i++ ) {
1607            XAResource JavaDoc res = (XAResource JavaDoc)resourceList.elementAt(i);
1608            
1609            if (TraceTm.jta.isDebugEnabled()) {
1610                TraceTm.jta.debug("res= "+ res);
1611            }
1612            
1613            if (res.equals(xares)) {
1614                xaresIndex = i;
1615                break;
1616            }
1617        }
1618
1619        // if not found, search for a xares with the same RM
1620
if (xaresIndex == -1) {
1621            if (TraceTm.jta.isDebugEnabled()) {
1622                TraceTm.jta.debug("not found -> search for xares with same RM");
1623            }
1624
1625            for (int i = 0; i < resourceList.size(); i++) {
1626                XAResource JavaDoc res = (XAResource JavaDoc) resourceList.elementAt(i);
1627
1628                if (TraceTm.jta.isDebugEnabled()) {
1629                    TraceTm.jta.debug("res= "+ res);
1630                }
1631                    
1632                try {
1633                    if (res.isSameRM(xares) ) {
1634                        xaresIndex = i;
1635                        break;
1636                    }
1637                } catch( XAException JavaDoc e ) {
1638                    if (TraceTm.jta.isDebugEnabled()) {
1639                       String JavaDoc error =
1640                         "res.isSameRm exception:"
1641                          + e
1642                          + "--"
1643                          + e.getMessage();
1644                     TraceTm.jta.debug(error);
1645                    }
1646                }
1647            }
1648        }
1649
1650        if (TraceTm.jta.isDebugEnabled()) {
1651            TraceTm.jta.debug("xaresIndex= " + xaresIndex);
1652        }
1653
1654        return xaresIndex;
1655    }
1656
1657}
1658
Popular Tags