KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#) TransactionImpl.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/01/15 Dean Jennings - List instead of Vector for enlistedXARes delistedXARes
46  *
47  * 02/06/18 Marek Prochazka - in timeoutExpired() removed code
48  * preventing deadlock by rolling back transaction
49  * --------------------------------------------------------------------------
50  * $Id: TransactionImpl.java,v 1.45 2005/05/10 22:52:35 tonyortiz Exp $
51  * --------------------------------------------------------------------------
52  */

53 package org.objectweb.jotm;
54
55 import java.rmi.RemoteException JavaDoc;
56 import java.util.ArrayList JavaDoc;
57 import java.util.Collections JavaDoc;
58 import java.util.List JavaDoc;
59 import javax.transaction.*;
60 import javax.transaction.xa.XAException JavaDoc;
61 import javax.transaction.xa.XAResource JavaDoc;
62
63 /**
64  * TransactionImpl is the implementation of the Transaction interface,
65  * defined in JTA specifications. This object is intended to be used
66  * by the EJBServer for transaction management. It is used indirectly
67  * by the UserTransaction implementation too, i.e. the Current object.
68  * The goal is to use the JTA interface to hide the JTM interface to
69  * the caller (EJBServer, Bean or Client).
70  */

71
72 public class TransactionImpl implements Transaction, TimerEventListener {
73
74     // ------------------------------------------------------------------
75
// Private data
76
// ------------------------------------------------------------------
77
private SubCoordinator subcoord = null;
78     private TransactionContext myCtx = null;
79     private Xid myXid = null;
80     private boolean genXidhashcode = false;
81     private boolean genXidtostring = false;
82     private int myXidhashcode = 0;
83     private String JavaDoc myXidtostring = null;
84     private String JavaDoc txDate = null;
85     private boolean interpose = false;
86     private int ucount = 0; // count of users (0 => can be freed)
87
private TimerEvent timer = null; // keep this to unvalidate timer
88
private RecoveryCoordinator recoveryCoord = null;
89     /// store enlisted resources
90
private List JavaDoc enlistedXARes = Collections.synchronizedList(new ArrayList JavaDoc());
91     /// store suspended resources
92
private List JavaDoc delistedXARes = null;
93     // propagate context
94
private boolean propagateCtx = true;
95     private List JavaDoc enlistedJavaxXid = Collections.synchronizedList(new ArrayList JavaDoc());
96     // ------------------------------------------------------------------
97
// Constructors
98
// ------------------------------------------------------------------
99

100     /**
101      * New transaction (begin).
102      *
103      * @param timeout The value of the timeout in seconds.
104      *
105      */

106
107     public TransactionImpl(Xid xid, int timeout) throws SystemException {
108         if (TraceTm.jta.isDebugEnabled()) {
109             TraceTm.jta.debug("xid= " + xid);
110             TraceTm.jta.debug("timeout= " + timeout);
111         }
112
113         // Build a propagation context local (no ref to JTM yet)
114
myXid = xid;
115         // myXidhashcode = myXid.hashCode();
116
// myXidtostring = myXid.toString();
117
myCtx = new InternalTransactionContext(timeout, null, (javax.transaction.xa.Xid JavaDoc) xid);
118     }
119
120     /**
121      * New Transaction for this thread (setPropagationContext)
122      *
123      * @param pctx propagation context
124      *
125      */

126
127     public TransactionImpl(TransactionContext pctx) {
128
129         if (pctx == null) {
130             TraceTm.jotm.error("TransactionImpl: null PropagationContext");
131         }
132         myCtx = pctx;
133         myXid = pctx.getXid();
134         // myXidhashcode = myXid.hashCode();
135
// myXidtostring = myXid.toString();
136
// interposition will be done later, only if necessary.
137
interpose = true;
138     }
139
140     // ------------------------------------------------------------------
141
// Transaction implementation
142
// ------------------------------------------------------------------
143

144     /**
145      * Complete the transaction represented by this Transaction object
146      * The calling thread is not required to have the same transaction
147      * associated with the thread. (JTA 3.3.3)
148      *
149      * @exception RollbackException Thrown to indicate that
150      * the transaction has been rolled back rather than committed.
151      *
152      * @exception HeuristicMixedException Thrown to indicate that a heuristic
153      * decision was made and that some relevant updates have been committed
154      * while others have been rolled back.
155      *
156      * @exception HeuristicRollbackException Thrown to indicate that a
157      * heuristic decision was made and that some relevant updates have been
158      * rolled back.
159      *
160      * @exception SecurityException Thrown to indicate that the thread is
161      * not allowed to commit the transaction.
162      *
163      * @exception IllegalStateException Thrown if the current thread is
164      * not associated with a transaction.
165      *
166      * @exception SystemException Thrown if the transaction manager
167      * encounters an unexpected error condition
168      */

169
170     public void commit()
171         throws
172             RollbackException,
173             HeuristicMixedException,
174             HeuristicRollbackException,
175             SecurityException JavaDoc,
176             SystemException {
177         
178         if (TraceTm.jta.isDebugEnabled()) {
179             TraceTm.jta.debug("TransactionImpl.commit (tx= " + this +")");
180         }
181
182         // *** Distributed transaction.
183
Terminator JavaDoc term = myCtx.getTerminator();
184
185         if (term != null) {
186             // Commits the Transaction, with heuristic report
187
try {
188                 propagateCtx = false;
189                 term.commit(true);
190                 propagateCtx = true;
191             } catch (TransactionRolledbackException e) {
192                 Current.getCurrent().forgetTx(getXid());
193                 if (TraceTm.jta.isDebugEnabled()) {
194                     TraceTm.jta.debug("Commit distributed transaction -> rolled back!");
195                 }
196                 throw new RollbackException();
197             } catch (RemoteException JavaDoc e) {
198
199                 if (TraceTm.jta.isWarnEnabled()) {
200                     TraceTm.jta.warn("got a RemoteException", e);
201                 }
202
203                 if (e.detail instanceof TransactionRolledbackException) {
204                     Current.getCurrent().forgetTx(getXid());
205                     if (TraceTm.jta.isDebugEnabled()) {
206                         TraceTm.jta.debug("Commit distributed transaction -> rolled back!");
207                     }
208                     throw new RollbackException();
209                 }
210
211                 if (e.detail instanceof HeuristicMixed) {
212                     TraceTm.jotm.info(
213                         "Commit distributed transaction -> Heuristic mixed!");
214                     throw new HeuristicMixedException();
215                 } else {
216                     throw new SystemException(
217                         "Unexpected RemoteException on commit:"
218                             + e.detail.getMessage());
219                 }
220             } catch (Exception JavaDoc e) {
221                 TraceTm.jotm.error("Unexpected Exception on commit:", e);
222                 throw new SystemException("Unexpected Exception on commit");
223             }
224
225             if (subcoord == null) {
226                 // if no coordinator, timer will not be unset by JTM.
227
unsetTimer();
228             }
229
230             Current.getCurrent().forgetTx(getXid());
231             return;
232         }
233
234         // *** Local transaction
235
// commit_one_phase may raise remote exceptions. We must rethrow local exceptions.
236

237         if (subcoord != null) {
238             try {
239                 subcoord.commit_one_phase();
240             } catch (TransactionRolledbackException e) {
241                 if (TraceTm.jta.isDebugEnabled()) {
242                     TraceTm.jta.debug("Commit local transaction -> rolled back!");
243                 }
244                 Current.getCurrent().forgetTx(getXid());
245                 throw new RollbackException();
246             } catch (RemoteException JavaDoc e) {
247                 TraceTm.jotm.error(
248                     "Unexpected Exception on commit_one_phase:",
249                     e);
250                 Current.getCurrent().forgetTx(getXid());
251                 throw new SystemException("Unexpected Exception on commit_one_phase");
252             }
253         } else {
254             // if no coordinator, just unset the timer and release this object.
255
unsetTimer();
256             Current.getCurrent().forgetTx(getXid());
257         }
258     }
259
260     /**
261      * Delist the resource specified from the current transaction
262      * associated with the calling thread.
263      *
264      * @param xares The XAResource object representing the resource to delist
265      *
266      * @param flag One of the values of TMSUCCESS, TMSUSPEND, or TMFAIL.
267      *
268      * @exception IllegalStateException Thrown if the transaction in the
269      * target object is inactive.
270      *
271      * @exception SystemException Thrown if the transaction manager
272      * encounters an unexpected error condition
273      *
274      * @return true if the dissociation of the Resource is successful;
275      * false otherwise.
276      */

277
278     public boolean delistResource(XAResource JavaDoc xares, int flag)
279         throws IllegalStateException JavaDoc, SystemException {
280
281         if (TraceTm.jta.isDebugEnabled()) {
282             TraceTm.jta.debug("TransactionImpl.delistResource");
283             TraceTm.jta.debug("xares= " + xares + ", flag= " + flag);
284         }
285
286         if (enlistedXARes == null) {
287             if (TraceTm.jta.isDebugEnabled()) {
288                 TraceTm.jta.error("No XA resources enlisted by JOTM");
289             }
290             return false;
291         }
292
293         // Verify that the XAResource to be delisted was enlisted earlier.
294

295         if (!enlistedXARes.contains(xares)) {
296             if (TraceTm.jta.isDebugEnabled()) {
297                 TraceTm.jta.error("XAResouce " + xares + " not enlisted by JOTM");
298             }
299             return false;
300         }
301
302         Xid resXid = new XidImpl( getXid(),subcoord.getXaresIndex(xares) );
303
304         javax.transaction.xa.Xid JavaDoc javaxxid = subcoord.getJavaxXid(subcoord.getXaresIndex(xares));
305         
306         if (!enlistedJavaxXid.contains(javaxxid)) {
307             if (TraceTm.jta.isDebugEnabled()) {
308                 TraceTm.jta.error("XAResouce " + xares + " not enlisted by JOTM");
309             }
310             return false;
311         }
312         
313         int javaxxidindex = enlistedJavaxXid.indexOf(javaxxid);
314         javax.transaction.xa.Xid JavaDoc myjavaxxid = (javax.transaction.xa.Xid JavaDoc) enlistedJavaxXid.get(javaxxidindex);
315         
316         if (TraceTm.jta.isDebugEnabled()) {
317             TraceTm.jta.debug("resXid= " + resXid);
318             TraceTm.jta.debug("delisted with resource= " + xares);
319             TraceTm.jta.debug("end myjavaxxid= " + myjavaxxid);
320         }
321
322         // Send the XA end to the XAResource
323
try {
324             xares.end (myjavaxxid, flag);
325             // xares.end( (javax.transaction.xa.Xid) resXid, flag );
326
} catch (XAException JavaDoc e) {
327             String JavaDoc error =
328                 "Cannot send XA end:"
329                     + e
330                     + " (error code = "
331                     + e.errorCode
332                     + ") --"
333                     + e.getMessage();
334             TraceTm.jotm.error(error);
335             if (TraceTm.jta.isDebugEnabled()) {
336                 TraceTm.jotm.debug("xares.end= " + xares);
337             }
338             throw new SystemException(error);
339         }
340
341         if (TraceTm.jta.isDebugEnabled()) {
342             TraceTm.jta.debug("enlistedXAres.remove xares= " + xares);
343         }
344
345         /// remove from enlisted list
346
enlistedXARes.remove(xares);
347         enlistedJavaxXid.remove(javaxxid);
348         return true;
349     }
350
351     /**
352      * Enlist the resource specified with the current transaction
353      * context of the calling thread
354      *
355      * @param xares The XAResource object representing the resource to enlist
356      *
357      * @return <i>true</i> if the resource was enlisted successfully; otherwise
358      * false.
359      *
360      * @exception RollbackException Thrown to indicate that
361      * the transaction has been marked for rollback only.
362      *
363      * @exception IllegalStateException Thrown if the transaction in the
364      * target object is in prepared state or the transaction is inactive.
365      *
366      * @exception SystemException Thrown if the transaction manager
367      * encounters an unexpected error condition
368      *
369      */

370
371     public boolean enlistResource(XAResource JavaDoc xares)
372         throws RollbackException, IllegalStateException JavaDoc, SystemException {
373
374         if (TraceTm.jta.isDebugEnabled()) {
375             TraceTm.jta.debug("TransactionImpl.enlistResource");
376             TraceTm.jta.debug("xares= " + xares);
377         }
378
379         // Check trivial cases
380
if (xares == null) {
381             TraceTm.jotm.error("enlistResource: null argument");
382             throw new SystemException("enlistResource: null argument");
383         }
384
385         if (myCtx == null) {
386             throw new SystemException("enlistResource: no Transactional Context");
387         }
388
389         // make a subCoordinator object if not existing yet
390
if (subcoord == null) {
391             makeSubCoord();
392             if (subcoord == null) {
393                 TraceTm.jotm.error(
394                     "enlistResource: could not create subcoordinator");
395                 throw new SystemException("enlistResource: could not create subcoordinator");
396             }
397         }
398
399         boolean found = false;
400
401         try{
402             found = subcoord.addResource(xares);
403         } catch (IllegalStateException JavaDoc e) {
404             throw new IllegalStateException JavaDoc("enlistResource: could not addResource " + xares);
405         }
406           
407         boolean rollbackOnly = false;
408
409         // Send the XA start to the XAResource
410
// A new Xid branch should be generated in case of new RM (if !found)
411
// See JTA Specifications, page 12/13.
412
int flag = found ? XAResource.TMJOIN : XAResource.TMNOFLAGS;
413
414         if ((delistedXARes != null) && delistedXARes.contains(xares)) {
415             flag = XAResource.TMRESUME;
416         }
417
418         Xid resXid = new XidImpl( getXid(),subcoord.getXaresIndex(xares) );
419         javax.transaction.xa.Xid JavaDoc javaxxid = new JavaXidImpl(resXid);
420         
421         if (TraceTm.jta.isDebugEnabled()) {
422             TraceTm.jta.debug("resXid= " + resXid);
423             TraceTm.jta.debug("enlisted with resource= " + xares);
424             TraceTm.jta.debug("start javaxxid= " + javaxxid);
425         }
426         
427         if (!found) {
428             subcoord.addJavaxXid(javaxxid);
429         }
430
431         try {
432             xares.start (javaxxid, flag);
433             // xares.start( (javax.transaction.xa.Xid) resXid, flag );
434
} catch (XAException JavaDoc e) {
435             String JavaDoc error =
436                 "Cannot send XA("
437                     +xares
438                     + ") start:"
439                     + e
440                     + " (error code = "
441                     + e.errorCode
442                     + ") --"
443                     + e.getMessage();
444             TraceTm.jotm.error(error);
445             throw new SystemException(error);
446         }
447
448         if (rollbackOnly) {
449             throw new RollbackException();
450         }
451
452         if (!enlistedXARes.contains(xares)) {
453            /// add to enlisted list
454
enlistedXARes.add(xares);
455            enlistedJavaxXid.add(javaxxid);
456         }
457
458         int status = this.getStatus();
459
460         switch (status) {
461             case Status.STATUS_ACTIVE :
462             case Status.STATUS_PREPARING :
463                 break;
464             case Status.STATUS_PREPARED :
465                 throw new IllegalStateException JavaDoc("Transaction already prepared.");
466             case Status.STATUS_COMMITTING :
467                 // throw new IllegalStateException("Transaction already started committing.");
468
break;
469             case Status.STATUS_COMMITTED :
470                 throw new IllegalStateException JavaDoc("Transaction already committed.");
471             case Status.STATUS_MARKED_ROLLBACK :
472                 throw new RollbackException("Transaction already marked for rollback");
473             case Status.STATUS_ROLLING_BACK :
474                 throw new RollbackException("Transaction already started rolling back.");
475             case Status.STATUS_ROLLEDBACK :
476                 throw new RollbackException("Transaction already rolled back.");
477             case Status.STATUS_NO_TRANSACTION :
478                 throw new IllegalStateException JavaDoc("No current transaction.");
479             case Status.STATUS_UNKNOWN :
480                 throw new IllegalStateException JavaDoc("Unknown transaction status");
481             default :
482                 throw new IllegalStateException JavaDoc("Illegal transaction status: " + status);
483         }
484
485         return true;
486     }
487
488     /// delist all enlisted resources and move to suspended
489

490     public void doDetach(int flag) throws SystemException {
491         if (TraceTm.jta.isDebugEnabled()) {
492             TraceTm.jta.debug("TransactionImpl.doDetach flag= " + XAResourceHelper.getFlagName(flag));
493             TraceTm.jta.debug("number of enlisted= " + enlistedXARes.size());
494         }
495
496         // always copy enlisted to suspended resource list
497
// since jonas may resume the transaction in beforecompletion
498

499         delistedXARes = new ArrayList JavaDoc(enlistedXARes);
500
501         for (int i = 0; i < delistedXARes.size(); i++) {
502             delistResource((XAResource JavaDoc) delistedXARes.get(i), flag);
503         }
504     }
505
506     /// enlist/clear all suspended resource
507

508     public void doAttach(int flag) throws SystemException, RollbackException {
509         if (TraceTm.jta.isDebugEnabled()) {
510             TraceTm.jta.debug("TransactionImpl.doAttach flag= " + XAResourceHelper.getFlagName(flag));
511             TraceTm.jta.debug("number of enlisted= " + enlistedXARes.size());
512         }
513
514         // we attach suspended transactions
515

516         if (flag == XAResource.TMRESUME) {
517             // we may be calling resume from beforecompletion on transaction that are not suspended!
518

519             for (int i = 0;
520                 (delistedXARes != null) && (i < delistedXARes.size());
521                 i++) {
522
523                 enlistResource((XAResource JavaDoc) delistedXARes.get(i));
524             }
525         }
526
527         delistedXARes = null;
528     }
529
530     /// get a copy of the list of currently enlisted resource
531

532     public List JavaDoc getEnlistedXAResource() {
533         if (TraceTm.jta.isDebugEnabled()) {
534             TraceTm.jta.debug("getEnlistedXAResource size= " + enlistedXARes.size());
535         }
536         return new ArrayList JavaDoc(enlistedXARes);
537     }
538
539     /**
540      * Obtain the status of the transaction associated with the current thread.
541      *
542      * @return The transaction status. If no transaction is associated with
543      * the current thread, this method returns the Status.NoTransaction
544      * value.
545      *
546      * @exception SystemException Thrown if the transaction manager
547      * encounters an unexpected error condition
548      *
549      */

550
551     public int getStatus() throws SystemException {
552         if (TraceTm.jta.isDebugEnabled()) {
553             TraceTm.jta.debug("TransactionImpl.getStatus()");
554         }
555
556         // *** Distributed transaction
557
Coordinator coord = myCtx.getCoordinator();
558
559         if (coord != null) {
560             // Ask the transaction status to JTM
561
int ret;
562             try {
563                 ret = coord.get_status();
564             } catch (Exception JavaDoc e) {
565                 TraceTm.jotm.error("cannot reach JTM:", e);
566                 return Status.STATUS_NO_TRANSACTION;
567             }
568             return ret;
569         }
570
571         // *** Local transaction
572
// The status is kept in the subcoordinator
573

574         if (subcoord == null) {
575             // The transaction has just been started
576
// No resource or synchro are registered yet.
577
return Status.STATUS_ACTIVE;
578         }
579
580         return subcoord.getStatus();
581     }
582
583     /**
584      * Register a synchronization object for the transaction currently
585      * associated with the calling thread. The transction manager invokes
586      * the beforeCompletion method prior to starting the transaction
587      * commit process. After the transaction is completed, the transaction
588      * manager invokes the afterCompletion method.
589      *
590      * @param sync The javax.transaction.Synchronization object for the
591      * transaction associated with the target object
592      *
593      * @exception RollbackException Thrown to indicate that
594      * the transaction has been marked for rollback only.
595      *
596      * @exception IllegalStateException Thrown if the transaction in the
597      * target object is in prepared state or the transaction is inactive.
598      *
599      * @exception SystemException Thrown if the transaction manager
600      * encounters an unexpected error condition
601      */

602
603     public void registerSynchronization(Synchronization sync)
604         throws RollbackException, IllegalStateException JavaDoc, SystemException {
605         if (TraceTm.jta.isDebugEnabled()) {
606             TraceTm.jta.debug("TransactionImpl.registerSynchronization(Synchronization sync)");
607         }
608
609         // It's time to make the subcoordinator, if not existing yet.
610
if (subcoord == null) {
611             makeSubCoord();
612         }
613
614         // Add Synchronization to the list.
615
// may raise exceptions
616
subcoord.addSynchronization(sync);
617     }
618
619     /**
620      * Rollback the transaction represented by this Transaction object.
621      *
622      * @exception IllegalStateException Thrown if the transaction in the
623      * target object is in prepared state or the transaction is inactive.
624      *
625      * @exception SystemException Thrown if the transaction manager
626      * encounters an unexpected error condition
627      *
628      */

629
630     public void rollback() throws IllegalStateException JavaDoc, SystemException {
631         if (TraceTm.jta.isDebugEnabled()) {
632             TraceTm.jta.debug("TransactionImpl.rollback(tx= " + this +")");
633         }
634
635         // *** Distributed transaction.
636
Terminator JavaDoc term = myCtx.getTerminator();
637
638         if (term != null) {
639             // Rollback the Transaction
640
try {
641                 propagateCtx = false;
642                 term.rollback();
643                 propagateCtx = true;
644             } catch (java.rmi.ServerException JavaDoc e) {
645                 // HeuristicCommit ????
646
throw new IllegalStateException JavaDoc(
647                     "Exception on rollback:" + e.detail);
648             } catch (Exception JavaDoc e) {
649                 Current.getCurrent().forgetTx(getXid());
650                 throw new SystemException("Unexpected Exception on rollback");
651             }
652
653             if (subcoord == null) {
654                 // if no coordinator, timer will not be unset by JTM.
655
unsetTimer();
656             }
657             
658             // release this object.
659
Current.getCurrent().forgetTx(getXid());
660             return;
661         }
662
663         // *** Local transaction.
664
// if no coordinator, nothing to do.
665

666         if (subcoord != null) {
667             try {
668                 subcoord.rollback();
669             } catch (RemoteException JavaDoc e) {
670                 Current.getCurrent().forgetTx(getXid());
671                 throw new IllegalStateException JavaDoc("Exception on rollback:" + e);
672             }
673
674         } else {
675             // if no coordinator, just unset the timer.
676
unsetTimer();
677         }
678         
679         // release this object.
680
Current.getCurrent().forgetTx(getXid());
681     }
682
683     /**
684      * Prepare the transaction represented by this Transaction object.
685      *
686      * @exception IllegalStateException Thrown if the transaction in the
687      * target object is in prepared state or the transaction is inactive.
688      *
689      * @exception SystemException Thrown if the transaction manager
690      * encounters an unexpected error condition
691      *
692      */

693
694     public int prepare() throws IllegalStateException JavaDoc, SystemException {
695         if (TraceTm.jta.isDebugEnabled()) {
696             TraceTm.jta.debug("TransactionImpl.prepare(tx= " + this +")");
697         }
698
699         int ret = 0;
700         if (subcoord != null) {
701             try {
702                 ret = subcoord.prepare();
703             } catch (RemoteException JavaDoc e) {
704                 TraceTm.jotm.error(
705                     "Unexpected Exception on prepare:",
706                     e);
707                 throw new SystemException("Unexpected Exception on prepare");
708             }
709         }
710         
711         return ret;
712     }
713
714     /**
715      * Modify the transaction associated with the current thread such that
716      * the only possible outcome of the transaction is to roll back the
717      * transaction.
718      *
719      * @exception IllegalStateException Thrown if the current thread is
720      * not associated with any transaction.
721      *
722      * @exception SystemException Thrown if the transaction manager
723      * encounters an unexpected error condition
724      *
725      */

726
727     public void setRollbackOnly() throws IllegalStateException JavaDoc, SystemException {
728         if (TraceTm.jta.isDebugEnabled()) {
729             TraceTm.jta.debug("TransactionImpl.setRollbackOnly(tx= " + this +")");
730         }
731
732         // *** Distributed transaction
733
Coordinator coord = myCtx.getCoordinator();
734
735         if (coord != null) {
736             try {
737                 coord.rollback_only();
738             } catch (RemoteException JavaDoc e) {
739                 TraceTm.jotm.error("Cannot perform coordinator rollback only", e);
740             }
741         }
742
743         // perform the if within this else, resolves bugs 300077, 300078
744
// subbcoord.setRollbackOnly sets the 'status' variable to
745
// "rollbackonly", checked in SubCoordinator.commit_one_phase
746
// } else {
747
// *** Local transaction
748
// The status is kept in the subcoordinator
749

750             if (subcoord == null) {
751                 // make a subCoordinator object if not existing yet
752
makeSubCoord();
753             }
754
755             subcoord.setRollbackOnly();
756         // }
757
}
758
759     // ------------------------------------------------------------------
760
// TimerEventListener implementation
761
// ------------------------------------------------------------------
762

763     /**
764      * timeout for that transaction has expired
765      */

766
767     public void timeoutExpired(Object JavaDoc arg) {
768         if (TraceTm.jta.isDebugEnabled()) {
769             TraceTm.jta.debug("TransactionImpl.timeoutExpired");
770         }
771
772         // increment counter for management
773
Current.getCurrent().incrementExpiredCounter();
774
775         // make the subcoordinator object, if not existing yet.
776

777         if (subcoord == null) {
778             // if this is a proxy, just forget this object. The JTM will
779
// rollback transaction with its own timer.
780
Terminator JavaDoc term = myCtx.getTerminator();
781
782             if (term != null) {
783                 TraceTm.jotm.info("forget tx (tx=" + this +")");
784                 Current.getCurrent().forgetTx(getXid());
785                 return;
786             }
787
788             makeSubCoord();
789         }
790
791         // Try to set it "rollback only"
792
// avoids a rollback while SQL requests are in progress
793
TraceTm.jotm.info("set rollback only (tx=" + this +")");
794
795         try {
796             subcoord.setRollbackOnly();
797         } catch (Exception JavaDoc e) {
798             TraceTm.jotm.error("cannot rollbackonly:" + e);
799             return;
800         }
801     }
802
803     // ------------------------------------------------------------------
804
// This object is used as an HashTable index
805
// ------------------------------------------------------------------
806

807     /**
808      * return true if objects are identical
809      */

810
811     public boolean equals(Object JavaDoc obj2) {
812         TransactionImpl tx2 = (TransactionImpl) obj2;
813
814         // trivial cases
815
if (tx2 == this) {
816             return true;
817         }
818         if (tx2 == null) {
819             return false;
820         }
821
822         // compare otids
823
return getXid().equals(tx2.getXid());
824     }
825
826     /**
827      * return a hashcode value for this object
828      */

829
830     public int hashCode() {
831         if (!genXidhashcode) {
832             genXidhashcode = true;
833             myXidhashcode = getXid().hashCode();
834         }
835         
836         return myXidhashcode;
837         // return getXid().hashCode();
838
}
839
840     // ------------------------------------------------------------------
841
// Other methods
842
// ------------------------------------------------------------------
843

844     /**
845      * string form
846      */

847
848     public String JavaDoc toString() {
849         if (!genXidtostring) {
850             genXidtostring = true;
851             myXidtostring = getXid().toString();
852         }
853         
854         return myXidtostring;
855         // return getXid().toString();
856
}
857
858     /**
859      * Return associated PropagationContext
860      * Used for implicit Context propagation.
861      *
862      * @return PropagationContext associated with the transaction.
863      */

864
865     public synchronized TransactionContext getPropagationContext(boolean hold) {
866
867         if (propagateCtx) {
868             if (hold) {
869                 ucount++;
870             }
871             return myCtx;
872         } else {
873             return null;
874         }
875     }
876
877     /**
878      * set a timer for the transaction
879      */

880
881     public void setTimer(TimerEvent timer) {
882         if (TraceTm.jta.isDebugEnabled()) {
883             TraceTm.jta.debug("set timer for tx (timer=" + timer + ", tx=" + this +")");
884         }
885         this.timer = timer;
886     }
887
888     /**
889      * unset the timer
890      */

891
892     public void unsetTimer() {
893         if (TraceTm.jta.isDebugEnabled()) {
894             TraceTm.jta.debug("unset timer for tx (timer=" + timer + ", tx=" + this +")");
895         }
896         if (timer != null) {
897             timer.unset();
898             timer = null;
899         }
900     }
901
902     /**
903      * set the date time stamp for the transaction
904      */

905
906     public void setTxDate(String JavaDoc date) {
907         if (TraceTm.jta.isDebugEnabled()) {
908             TraceTm.jta.debug("set date for tx (data=" + date + ", tx=" + this +")");
909         }
910         txDate = date;
911     }
912
913     /**
914      * get the date time stamp for the transaction
915      */

916
917     public String JavaDoc getTxDate() {
918         if (TraceTm.jta.isDebugEnabled()) {
919             TraceTm.jta.debug("get date for tx (date=" + txDate + ", tx=" + this +")");
920         }
921         return txDate;
922     }
923
924     /**
925      * update the propagation context
926      * We should be inside the reply of a request involved in a tx here!
927      */

928
929     public synchronized void updatePropagationContext(TransactionContext pctx) {
930         if (TraceTm.jta.isDebugEnabled()) {
931             TraceTm.jta.debug("TransactionImpl.updatePropagationContext");
932         }
933
934         Coordinator remoteCoord = pctx.getCoordinator();
935
936         if (remoteCoord == null && myCtx.getCoordinator() != null) {
937             TraceTm.jotm.error("setPropagationContext: Bad Coordinator");
938             TraceTm.jotm.error("remoteCoord = " + remoteCoord);
939             TraceTm.jotm.error("myCtx.getCoordinator()= " + myCtx.getCoordinator());
940             return;
941         }
942
943         // release count of users
944
ucount--;
945
946         // Interpose subCoordinator if newly distributed Tx
947
if (remoteCoord != null && myCtx.getCoordinator() == null) {
948             myCtx.setCoordinator(pctx.getCoordinator());
949
950             if (subcoord != null) {
951                 // register the subCoordinator as a Resource.
952
try {
953                     recoveryCoord = remoteCoord.register_resource(subcoord);
954                 } catch (RemoteException JavaDoc e) {
955                     TraceTm.jotm.error("Cannot make interposition:", e);
956                     return;
957                 }
958             }
959         }
960
961         if ( pctx.getTerminator() != null ) {
962             myCtx.setTerminator(pctx.getTerminator());
963         }
964     }
965
966     /**
967      * Get the Xid of the transaction
968      */

969
970     public Xid getXid() {
971         return myXid;
972     }
973
974     /**
975      * make a SubCoordinator for this Transaction object
976      */

977
978     private void makeSubCoord() {
979         if (TraceTm.jta.isDebugEnabled()) {
980             TraceTm.jta.debug("make subcoordinator");
981         }
982
983         // Build the SubCoordinator object
984
try {
985             subcoord = new SubCoordinator(this, getXid());
986         } catch (RemoteException JavaDoc e) {
987             // should never go here.
988
TraceTm.jotm.error("new SubCoordinator raised exception: ", e);
989             return;
990         }
991
992         // If interposition must be done: do it now!
993
// Each time we have a remoteCoord + a subCoord, we must interpose.
994
Coordinator remoteCoord = myCtx.getCoordinator();
995
996         // First of all, create the Control object on JTM
997
// if it was not created before, if interpose flag is set.
998

999         if (interpose && remoteCoord == null) {
1000            try {
1001                // XXX Note that the JTM will build another Xid
1002
// This must be clarified
1003
if (TraceTm.jta.isDebugEnabled()) {
1004                    TraceTm.jta.debug("Creating a remote Control on JTM for a distributed transaction");
1005                }
1006
1007                remoteCoord =
1008                    (Coordinator) javax.rmi.PortableRemoteObject.narrow(
1009                        Current.getJTM().create(myCtx.getTimeout()),
1010                        Coordinator.class);
1011
1012            } catch (RemoteException JavaDoc e) {
1013                TraceTm.jotm.error("Cannot create distributed transaction:", e);
1014                return;
1015            }
1016
1017            myCtx.setCoordinator(remoteCoord);
1018
1019            // fix for transaction context propagation with
1020
// the Jeremie protocol
1021

1022            if (myCtx.getTerminator() == null) {
1023                myCtx.setTerminator((Terminator JavaDoc) remoteCoord);
1024            }
1025        }
1026
1027        // Achieve interposition if not already done:
1028
// - register the subCoordinator as a Resource.
1029
if (remoteCoord != null && recoveryCoord == null) {
1030            try {
1031                recoveryCoord = remoteCoord.register_resource(subcoord);
1032            } catch (RemoteException JavaDoc e) {
1033                TraceTm.jotm.error("Cannot make interposition:", e);
1034                return;
1035            }
1036        }
1037    }
1038
1039    /**
1040     * return true if object is no more used (= removable)
1041     */

1042
1043    public boolean isRemovable() {
1044        return (ucount == 0 && subcoord == null);
1045    }
1046
1047}
1048
Popular Tags