KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#) Current.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  * The original code and portions created by Bull SA are
13  * Copyright (c) 1999 BULL SA
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions are met:
18  *
19  * -Redistributions of source code must retain the above copyright notice, this
20  * list of conditions and the following disclaimer.
21  *
22  * -Redistributions in binary form must reproduce the above copyright notice,
23  * this list of conditions and the following disclaimer in the documentation
24  * and/or other materials provided with the distribution.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  * --------------------------------------------------------------------------
38  *
39  * Contributor(s):
40  * 01/11/06 Christophe Ney cney@batisseurs.com
41  * Added ResourceManagerListener mechanism to remove ThreadData
42  * dependency.
43  * 01/12/03 Dean Jennings - synchronizedMap for txXids
44  *
45  * --------------------------------------------------------------------------
46  * $Id: Current.java,v 1.54 2005/05/12 14:06:26 tonyortiz Exp $
47  * --------------------------------------------------------------------------
48  */

49 package org.objectweb.jotm;
50
51 import java.io.Serializable JavaDoc;
52 import java.util.Collections JavaDoc;
53 import java.util.Date JavaDoc;
54 import java.util.EmptyStackException JavaDoc;
55 import java.util.HashMap JavaDoc;
56 import java.util.Iterator JavaDoc;
57 import java.util.List JavaDoc;
58 import java.util.Map JavaDoc;
59 import java.util.Set JavaDoc;
60 import java.util.Stack JavaDoc;
61 import java.util.Vector JavaDoc;
62
63 import javax.naming.NamingException JavaDoc;
64 import javax.naming.Reference JavaDoc;
65 import javax.naming.Referenceable JavaDoc;
66 import javax.naming.StringRefAddr JavaDoc;
67 import javax.resource.spi.XATerminator JavaDoc;
68 import javax.transaction.HeuristicMixedException JavaDoc;
69 import javax.transaction.HeuristicRollbackException JavaDoc;
70 import javax.transaction.InvalidTransactionException JavaDoc;
71 import javax.transaction.NotSupportedException JavaDoc;
72 import javax.transaction.RollbackException JavaDoc;
73 import javax.transaction.Status JavaDoc;
74 import javax.transaction.SystemException JavaDoc;
75 import javax.transaction.Transaction JavaDoc;
76 import javax.transaction.UserTransaction JavaDoc;
77 import javax.transaction.xa.XAException JavaDoc;
78 import javax.transaction.xa.XAResource JavaDoc;
79
80 import org.objectweb.transaction.jta.ResourceManagerEvent;
81 import org.objectweb.transaction.jta.TransactionManager;
82 import org.objectweb.howl.log.xa.XACommittingTx;
83
84 /**
85  * <code>Current</code> is the common implementation for both
86  * <code>UserTransaction</code> and <code>TransactionManager</code>.
87  * <ul>
88  * <li><code>UserTransaction</code> is used by clients that want to demarcate
89  * transactions themselves. It is referenceable through JNDI.</li>
90  * <li><code>TransactionManager</code> is used by an application server.</li>
91  * </ul>
92  *
93  * <p>This object is unique in a VM, i. e. each application server has
94  * <em>ONE</em> <code>Current</code> object and each client program should
95  * normally issue only <em>ONE</em> lookup on JNDI.</p>
96  *
97  * <p><code>Current</code> also implements <code>Referenceable</code> and
98  * <code>Serializable</code> because of JNDI.</p>
99  */

100
101 public class Current implements UserTransaction JavaDoc, TransactionManager, Referenceable JavaDoc, Serializable JavaDoc {
102
103     // transaction associated to the thread
104
// Thread specific data
105
private transient static ThreadLocal JavaDoc threadTx = new ThreadLocal JavaDoc();
106
107     // ------------------------------------------------------------------
108
// Private data
109
// ------------------------------------------------------------------
110

111     // Static hashtable: Xid ---> transaction
112
private transient static Map JavaDoc txXids = Collections.synchronizedMap(new HashMap JavaDoc());
113
114     // Must be init at null, for clients that do not get UserTransaction
115
private transient static Current unique = null;
116     
117     // private info
118
private transient static TimerManager timermgr = null; // local
119
private transient static TransactionFactory tm = null; // local or remote
120
private transient static TransactionRecovery tr = null; // transaction recovery object
121

122     private static final String JavaDoc JOTM_VERSION = "JOTM 2.0.10";
123     private static final int DEFAULT_TIMEOUT = 60;
124     private int defaultTimeout = DEFAULT_TIMEOUT;
125     private int transactionTimeout = DEFAULT_TIMEOUT;
126     private static final boolean DEFAULT_RECOVERY = false;
127     private static boolean transactionRecovery = DEFAULT_RECOVERY;
128     
129     // management counter
130
private transient int nb_bg_tx = 0;
131     private transient int nb_rb_tx = 0;
132     private transient int nb_cm_tx = 0;
133     private transient int nb_to = 0;
134
135     // ------------------------------------------------------------------
136
// Constructors
137
// ------------------------------------------------------------------
138

139     /**
140      * Default constructor.
141      * A client does not need the TMFactory.
142      */

143
144     public Current(){
145         TraceTm.jta.info(JOTM_VERSION);
146         
147         if (TraceTm.jta.isDebugEnabled()) {
148             TraceTm.jta.debug("no args constructor");
149         }
150
151         unique = this;
152         timermgr = TimerManager.getInstance();
153         
154         try {
155             tr = new TransactionRecoveryImpl ();
156         } catch (Exception JavaDoc e) {
157             setDefaultRecovery(false);
158             TraceTm.recovery.error("Cannot open Howl Log");
159             TraceTm.recovery.error("JOTM Recovery is being disabled");
160         }
161     }
162
163     /**
164      * Constructor for an application server.
165      *
166      * The TM factory is passed as an argument. Note that the TM factory can be
167      * either local or remote.
168      *
169      * @param tmfact TM Factory to use
170      */

171
172     public Current(TransactionFactory tmfact){
173         TraceTm.jta.info(JOTM_VERSION);
174         
175         if (TraceTm.jta.isDebugEnabled()) {
176             TraceTm.jta.debug("TransactionFactory="+ tmfact);
177         }
178
179         unique = this;
180         tm = tmfact;
181         
182         timermgr = TimerManager.getInstance();
183         
184         try {
185             tr = new TransactionRecoveryImpl ();
186         } catch (Exception JavaDoc e) {
187             setDefaultRecovery(false);
188             TraceTm.recovery.error("Cannot open Howl Log");
189             TraceTm.recovery.error("JOTM Recovery is being disabled");
190         }
191     }
192
193     /**
194      * Gets the <code>TransactionManager</code> instance.
195      *
196      * @return TransactionManager
197      */

198
199     public static TransactionManager getTransactionManager() {
200         return (TransactionManager) unique;
201     }
202
203     // ------------------------------------------------------------------
204
// UserTransaction implementation
205
// ------------------------------------------------------------------
206

207     /**
208      * Creates a new transaction and associate it with the current thread.
209      *
210      * @exception NotSupportedException Thrown if the thread is already
211      * associated with a transaction. (nested transaction are not
212      * supported)
213      *
214      * @exception SystemException Thrown if the transaction manager
215      * encounters an unexpected error condition
216      */

217
218     public void begin() throws NotSupportedException JavaDoc, SystemException JavaDoc {
219
220         if (TraceTm.jta.isDebugEnabled()) {
221             TraceTm.jta.debug("begin transaction");
222         }
223
224         // checks that no transaction is already associated with this thread.
225
TransactionImpl tx = (TransactionImpl) threadTx.get();
226
227         if (TraceTm.jta.isDebugEnabled()) {
228             TraceTm.jta.debug("threadTx.get= " + threadTx.toString());
229         }
230
231         if (tx != null) {
232             if (txXids.containsValue(tx)) {
233                 throw new NotSupportedException JavaDoc("Nested transactions not supported");
234             } else {
235                 if (TraceTm.jta.isDebugEnabled()) {
236                     TraceTm.jta.debug("Resetting current tx = " + tx + " since it is already completed.");
237                 }
238             }
239         }
240
241         // builds a new Xid
242
// - should pass servername + ip addr. (LATER)
243
XidImpl otid = new XidImpl();
244
245         // creates a new TransactionImpl object
246
// - May raise SystemException
247
tx = new TransactionImpl(otid, transactionTimeout);
248
249         if (TraceTm.jta.isDebugEnabled()) {
250             TraceTm.jta.debug("tx=" + tx);
251         }
252
253         /// clear suspended transaction.
254
try {
255             tx.doAttach(XAResource.TMJOIN);
256         } catch (RollbackException JavaDoc e) {
257             // never.
258
TraceTm.jotm.error("doAttach: RollbackException");
259             throw new SystemException JavaDoc("RollbackException in occured in begin() " + e.getMessage());
260         }
261
262         // associates transaction with current thread
263
threadTx.set(tx);
264
265         if (TraceTm.jta.isDebugEnabled()) {
266             TraceTm.jta.debug("threadTx.set= " + threadTx.toString());
267         }
268
269         // associates this Tx with the Xid
270
putTxXid(otid, tx);
271
272         // sets a timer for the transaction
273
if (timermgr != null) {
274             tx.setTimer(timermgr.addTimer(tx, transactionTimeout, null, false));
275         }
276
277         // sets the time stamp for the transaction
278
Date JavaDoc myDate = new Date JavaDoc();
279         tx.setTxDate(myDate.toString());
280
281         // enlist all connections using the event callback this should be done in UserTransaction
282
// was done in doAttach
283
Stack JavaDoc curStack = (Stack JavaDoc) eventListStack.get();
284
285         if (curStack != null) { // if there is opened connections
286

287             try {
288                 List JavaDoc list = (List JavaDoc) curStack.peek();
289
290                 if (list != null) {
291
292                     for (Iterator JavaDoc it = list.iterator(); it.hasNext();) {
293                         ((ResourceManagerEvent) it.next()).enlistConnection(tx);
294                     }
295                 } else {
296
297                     if (TraceTm.jta.isDebugEnabled()) {
298                         TraceTm.jta.debug("Current.begin called with null list");
299                     }
300                 }
301             } catch (EmptyStackException JavaDoc e) {
302                 if (TraceTm.jta.isDebugEnabled()) {
303                     TraceTm.jta.debug("Current.begin called with empty stack");
304                 }
305             }
306         }
307     }
308
309     // ------------------------------------------------------------------
310
// Inflow Transaction implementation
311
// ------------------------------------------------------------------
312

313     /**
314      * Creates a new inflow transaction and associates it with the current thread.
315      *
316      * @param passxid <code>Xid</code> of the inflow transaction.
317      *
318      * @exception NotSupportedException Thrown if the thread is already
319      * associated with a transaction. (nested transaction are not
320      * supported)
321      *
322      * @exception SystemException Thrown if the transaction manager
323      * encounters an unexpected error condition
324      */

325
326     public void begin(javax.transaction.xa.Xid JavaDoc passxid) throws NotSupportedException JavaDoc, SystemException JavaDoc {
327         begin(passxid, (long) transactionTimeout);
328     }
329
330     /**
331      * Creates a new inflow transaction and associates it with the current thread.
332      *
333      * @param passxid <code>Xid</code> of the inflow transaction.
334      *
335      * @param timeout value of the timeout (in seconds). If the value is less than
336      * or equal to zero, the value will be set to the default value.
337      *
338      * @exception NotSupportedException Thrown if the thread is already
339      * associated with a transaction. (nested transaction are not
340      * supported)
341      *
342      * @exception SystemException Thrown if the transaction manager
343      * encounters an unexpected error condition
344      */

345
346     public void begin(javax.transaction.xa.Xid JavaDoc passxid, long timeout) throws NotSupportedException JavaDoc, SystemException JavaDoc {
347
348         if (TraceTm.jta.isDebugEnabled()) {
349             TraceTm.jta.debug("begin inflow transaction, timeout = " + timeout);
350         }
351
352         if (timeout <= 0) {
353             timeout = defaultTimeout;
354         }
355         
356         // checks that no transaction is already associated with this thread.
357
TransactionImpl tx = (TransactionImpl) threadTx.get();
358
359         if (TraceTm.jta.isDebugEnabled()) {
360             TraceTm.jta.debug("threadTx.get= " + threadTx.toString());
361         }
362
363         if (tx != null) {
364             if (txXids.containsValue(tx)) {
365                 throw new NotSupportedException JavaDoc("Nested transactions not supported");
366             } else {
367                 if (TraceTm.jta.isDebugEnabled()) {
368                     TraceTm.jta.debug("Resetting current tx = " + tx + " since it is already completed.");
369                 }
370             }
371         }
372
373         // stores the passed xid components
374
XidImpl pxid = new XidImpl(passxid);
375
376         // creates a new TransactionImpl object
377
// - May raise SystemException
378
tx = new TransactionImpl(pxid, (int) timeout);
379
380         if (TraceTm.jta.isDebugEnabled()) {
381             TraceTm.jta.debug("tx=" + tx);
382         }
383
384         // associates transaction with current thread
385
threadTx.set(tx);
386
387         if (TraceTm.jta.isDebugEnabled()) {
388             TraceTm.jta.debug("threadTx.set= " + threadTx.toString());
389         }
390
391         // associates this Tx with the Xid
392
putTxXid(pxid, tx);
393
394         // sets a timer for the transaction
395
if (timermgr != null) {
396             tx.setTimer(timermgr.addTimer(tx, (int) timeout, null, false));
397         }
398
399         // sets the time stamp for the transaction
400
Date JavaDoc myDate = new Date JavaDoc();
401         tx.setTxDate(myDate.toString());
402     }
403
404     /**
405      * Gets the inflow transaction object that represents the transaction context of
406      * the calling thread.
407      *
408      * @return the XATerminator object representing the inflow transaction
409      * associated with the calling thread. If the calling thread is
410      * not associated with an inflow transaction, a null object reference
411      * is returned.
412      *
413      * @exception XAException Thrown if the transaction manager
414      * encounters an unexpected error condition
415      */

416
417     public XATerminator JavaDoc getXATerminator() throws XAException JavaDoc {
418
419         XATerminator JavaDoc xaterm = null;
420
421         try {
422             xaterm = new XATerminatorImpl();
423         } catch (XAException JavaDoc e) {
424             if (TraceTm.jta.isDebugEnabled()) {
425                 TraceTm.jta.debug("Cannot create XATerminatorImpl"+ e);
426             }
427         }
428
429         return xaterm;
430     }
431
432     // ------------------------------------------------------------------
433
// End of Inflow Transaction implementation
434
// ------------------------------------------------------------------
435

436
437     /**
438       * Commits the transaction associated with the current thread. When this
439       * method completes, the thread becomes associated with no transaction.
440       *
441       * @exception RollbackException Thrown to indicate that the transaction
442       * has been rolled back rather than committed.
443       *
444       * @exception HeuristicMixedException Thrown to indicate that a heuristic
445       * decision was made and that some relevant updates have been committed
446       * while others have been rolled back.
447       *
448       * @exception HeuristicRollbackException Thrown to indicate that a
449       * heuristic decision was made and that some relevant updates have been
450       * rolled back.
451       *
452       * @exception SecurityException Thrown to indicate that the thread is not
453       * allowed to commit the transaction.
454       *
455       * @exception IllegalStateException Thrown if the current thread is not
456       * associated with a transaction.
457       *
458       * @exception SystemException Thrown if the transaction manager encounters
459       * an unexpected error condition
460       */

461
462     public void commit()
463         throws
464             RollbackException JavaDoc,
465             HeuristicMixedException JavaDoc,
466             HeuristicRollbackException JavaDoc,
467             SecurityException JavaDoc,
468             IllegalStateException JavaDoc,
469             SystemException JavaDoc {
470
471         if (TraceTm.jta.isDebugEnabled()) {
472             TraceTm.jta.debug("commit transaction ");
473         }
474
475         // Get Transaction
476
TransactionImpl tx = (TransactionImpl) getTransaction();
477
478         if (tx == null) {
479             throw new IllegalStateException JavaDoc("Cannot get Transaction for commit");
480         }
481
482         if (TraceTm.jta.isDebugEnabled()) {
483             TraceTm.jta.debug("tx=" + tx);
484         }
485         
486         // Commit Transaction. Exceptions may be raised!
487
try {
488             tx.commit();
489         } finally {
490             // Dissociates the transaction from current thread
491
// Has not been done in doDetach because we need to
492
// be in the transactional context for beforeCompletion
493
threadTx.set(null);
494             
495             // Reset the timeout to the default timeout
496
transactionTimeout = defaultTimeout;
497             
498             if (TraceTm.jta.isDebugEnabled()) {
499                 TraceTm.jta.debug("threadTx.set= null");
500                 TraceTm.jta.debug("reset timeout= " + defaultTimeout);
501             }
502         }
503     }
504
505     /**
506      * Rolls back the transaction associated with the current thread. When this
507      * method completes, the thread becomes associated with no transaction.
508      *
509      * @exception SecurityException Thrown to indicate that the thread is not
510      * allowed to roll back the transaction.
511      *
512      * @exception IllegalStateException Thrown if the current thread is not
513      * associated with a transaction.
514      *
515      * @exception SystemException Thrown if the transaction manager
516      * encounters an unexpected error condition
517      */

518     public void rollback() throws IllegalStateException JavaDoc, SecurityException JavaDoc, SystemException JavaDoc {
519
520         if (TraceTm.jta.isDebugEnabled()) {
521             TraceTm.jta.debug("Current.rollback()");
522         }
523
524         // Get Transaction
525
TransactionImpl tx = (TransactionImpl) getTransaction();
526
527         if (tx == null) {
528             throw new IllegalStateException JavaDoc("Cannot get Transaction for rollback");
529         }
530         
531         threadTx.set(null);
532
533         if (TraceTm.jta.isDebugEnabled()) {
534             TraceTm.jta.debug("threadTx.set= null");
535         }
536
537         // Roll back the transaction. Exceptions may be raised!
538
tx.rollback();
539         
540         if (TraceTm.jta.isDebugEnabled()) {
541             TraceTm.jta.debug("reset timeout= " + defaultTimeout);
542         }
543         
544         transactionTimeout = defaultTimeout;
545         
546     }
547
548     /**
549      * Modify the transaction associated with the current thread such that the
550      * only possible outcome of the transaction is to roll back the transaction.
551      *
552      * @exception IllegalStateException Thrown if the current thread is not
553      * associated with a transaction.
554      *
555      * @exception SystemException Thrown if the transaction manager
556      * encounters an unexpected error condition
557      */

558
559     public void setRollbackOnly() throws IllegalStateException JavaDoc, SystemException JavaDoc {
560
561         if (TraceTm.jta.isDebugEnabled()) {
562             TraceTm.jta.debug("Current.setRollbackOnly()");
563         }
564         // Get Transaction
565
TransactionImpl tx = (TransactionImpl) getTransaction();
566
567         if (tx == null) {
568             throw new IllegalStateException JavaDoc("Cannot get Transaction for setRollbackOnly");
569         }
570
571         // Set transaction rollback only. Exceptions may be raised!
572
tx.setRollbackOnly();
573     }
574
575     /**
576       * Returns the status of the transaction associated with the current
577       * thread.
578       *
579       * @return transaction status. If no transaction is associated with the
580       * current thread, this method returns the Status.NoTransaction value.
581       *
582       * @exception SystemException Thrown if the transaction manager
583       * encounters an unexpected error condition
584       */

585
586     public int getStatus() throws SystemException JavaDoc {
587
588         if (TraceTm.jta.isDebugEnabled()) {
589             TraceTm.jta.debug("Current.getStatus()");
590         }
591
592         // Get Transaction
593
TransactionImpl tx = (TransactionImpl) getTransaction();
594
595         if (tx == null) {
596             return Status.STATUS_NO_TRANSACTION;
597         }
598
599         // Get TX status. Exceptions may be raised!
600
return tx.getStatus();
601     }
602
603     /**
604       * Modifies the value of the timeout value that is associated with the
605       * transactions started by the current thread with the begin method.
606       *
607       * If an application has not called this method, the transaction
608       * service uses some default value for the transaction timeout.
609       *
610       * @param timeout value of the timeout (in seconds). If the value is zero,
611       * the transaction service restores the default value.
612       *
613       * @exception SystemException Thrown if the transaction manager
614       * encounters an unexpected error condition
615       */

616
617     public void setTransactionTimeout(int timeout) throws SystemException JavaDoc {
618         
619         if (TraceTm.jta.isDebugEnabled()) {
620             TraceTm.jta.debug("timeout= "+ timeout);
621         }
622         
623         // checks that no transaction is already associated with this thread.
624
// If one is, then we have a running transaction (ut.begin) and we must
625
// wait until transaction completes (ut.commit or ut.rollback)
626

627         TransactionImpl tx = (TransactionImpl) threadTx.get();
628
629         if (tx != null) {
630             if (txXids.containsValue(tx)) {
631                 if (TraceTm.jta.isDebugEnabled()) {
632                     TraceTm.jta.debug("Cannot reset transaction timeout, tx in execution");
633                 }
634                 // Cannot reset transaction timeout, tx (ut.begin)in execution, ignore.
635
return;
636             }
637         }
638         
639         if (timeout > 0) {
640             transactionTimeout = timeout;
641         } else {
642             transactionTimeout = defaultTimeout;
643         }
644         
645         if (TraceTm.jta.isDebugEnabled()) {
646             TraceTm.jta.debug("Resetting transaction timeout= " + transactionTimeout);
647         }
648     }
649     
650     /**
651      * Modifies the value of the recovery value that is associated with the
652      * transactions started by the current thread with the begin method.
653      *
654      * If an application has not called this method, the transaction
655      * service uses the default value of 'false' for recovery.
656      *
657      * @param recovery value of the recovery (true or faluse). If the value is
658      * false, recovery of transactions is disabled.
659      *
660      * @exception SystemException Thrown if the transaction manager
661      * encounters an unexpected error condition
662      */

663
664    public void setTransactionRecovery(boolean recovery) throws SystemException JavaDoc {
665
666        if (TraceTm.recovery.isDebugEnabled()) {
667            TraceTm.recovery.debug("recovery="+ recovery);
668        }
669
670        if (recovery) {
671            transactionRecovery = recovery;
672        } else {
673            transactionRecovery = DEFAULT_RECOVERY;
674        }
675    }
676
677     // ------------------------------------------------------------------
678
// TransactionManager implementation
679
// (only the methods that are not already in UserTransaction)
680
// ------------------------------------------------------------------
681

682     /**
683      * Gets the transaction object that represents the transaction context of
684      * the calling thread.
685      *
686      * @return the Transaction object representing the transaction
687      * associated with the calling thread. If the calling thread is
688      * not associated with a transaction, a null object reference
689      * is returned.
690      *
691      * @exception SystemException Thrown if the transaction manager
692      * encounters an unexpected error condition
693      */

694
695     public Transaction JavaDoc getTransaction() throws SystemException JavaDoc {
696         Transaction JavaDoc ret = (Transaction JavaDoc) threadTx.get();
697
698         if (TraceTm.jta.isDebugEnabled()) {
699             TraceTm.jta.debug("threadTx.get= " + threadTx.toString());
700             TraceTm.jta.debug("Transaction ret= " + ret);
701         }
702
703         return ret;
704     }
705
706     /**
707      * Resumes the transaction context association of the calling thread with
708      * the transaction represented by the supplied Transaction object. When this
709      * method returns, the calling thread is associated with the transaction
710      * context specified.
711      * <p><em>Warning</em>: No XA start is done here. We suppose it is already
712      * done after a <code>getConnection()</code>.
713      * </p>
714      * The supposed programming model is: <ol>
715      * <li><code>getConnection()</code></li>
716      * <li>SQL code</li>
717      * <li><code>connection.close()</code</li>
718      * </ol>
719      *
720      * @param tobj The <code>Transaction</code> object that represents the
721      * transaction to be resumed.
722      *
723      * @exception InvalidTransactionException Thrown if the parameter
724      * transaction object contains an invalid transaction
725      *
726      * @exception IllegalStateException Thrown if the thread is already
727      * associated with another transaction.
728      *
729      * @exception SystemException Thrown if the transaction manager
730      * encounters an unexpected error condition
731      */

732
733     public void resume(Transaction JavaDoc tobj) throws InvalidTransactionException JavaDoc, IllegalStateException JavaDoc, SystemException JavaDoc {
734
735         if (TraceTm.jta.isDebugEnabled()) {
736             TraceTm.jta.debug("resume transaction");
737         }
738
739         // invalid Transaction
740
if (tobj == null) {
741             TraceTm.jotm.error("resume: null arg.");
742             throw new InvalidTransactionException JavaDoc("resume(null) is not valid");
743         }
744
745         if (TraceTm.jta.isDebugEnabled()) {
746             TraceTm.jta.debug("tx="+ tobj);
747         }
748
749         // Checks that the thread is not already associated to ANOTHER transaction
750
Transaction JavaDoc mytx = (Transaction JavaDoc) threadTx.get();
751
752         if (TraceTm.jta.isDebugEnabled()) {
753             TraceTm.jta.debug("threadTx.get= " + threadTx.toString());
754         }
755
756         if (mytx != null) {
757             if (mytx.equals(tobj)) {
758                 if (TraceTm.jta.isDebugEnabled()) {
759                     TraceTm.jta.debug("nothing to do");
760                 }
761                 return;
762             }
763             TraceTm.jotm.error("resume: already associated with another transaction.");
764             throw new IllegalStateException JavaDoc("the thread is already associated with another transaction.");
765         }
766
767         // test for type before cast
768
if (!(tobj instanceof TransactionImpl)) {
769             TraceTm.jotm.error("resume: non TransactionImpl arg.");
770             throw new InvalidTransactionException JavaDoc("resume(" + tobj.getClass().getName() + ") is not valid");
771         }
772
773         // Associates this Tx with the current thread
774
threadTx.set(tobj);
775
776         if (TraceTm.jta.isDebugEnabled()) {
777             TraceTm.jta.debug("threadTx.set= " + threadTx.toString());
778         }
779
780         // attach suspended resources
781
try {
782             ((TransactionImpl) tobj).doAttach(XAResource.TMRESUME);
783         } catch (RollbackException JavaDoc e) {
784             // never.
785
TraceTm.jotm.error("RollbackException occured in resume()");
786             throw new SystemException JavaDoc("RollbackException in occured in resume() " + e.getMessage());
787         }
788     }
789
790     /**
791       * Suspends the transaction currently associated with the calling thread
792       * and return a <code>Transaction</code> object that represents the
793       * transaction context being suspended.
794       * If the calling thread is not
795       * associated with a transaction, the method returns
796       * <code>null</code>. When this method returns, the calling thread is
797       * associated with no transaction.
798       <p><em>Warning</em>: No XA start is done here. We suppose it is already
799       done after a <code>getConnection()</code>.
800      * </p>
801      * The supposed programming model is: <ol>
802      * <li><code>getConnection()</code></li>
803      * <li>SQL code</li>
804      * <li><code>connection.close()</code</li>
805      * </ol>
806      *
807      * @return Transaction object representing the suspended transaction.
808      *
809      * @exception SystemException Thrown if the transaction manager
810      * encounters an unexpected error condition
811      *
812      * @exception SystemException Thrown if the transaction manager
813      * encounters an unexpected error condition
814      */

815
816     public Transaction JavaDoc suspend() throws SystemException JavaDoc {
817
818         if (TraceTm.jta.isDebugEnabled()) {
819             TraceTm.jta.debug("suspend transaction");
820         }
821
822         /// TMSUSPEND should be defined in Transaction.
823
TransactionImpl tx = (TransactionImpl) threadTx.get();
824
825         if (TraceTm.jta.isDebugEnabled()) {
826             TraceTm.jta.debug("threadTx.get= " + threadTx.toString());
827         }
828
829         if (tx != null) {
830
831             if (TraceTm.jta.isDebugEnabled()) {
832                 TraceTm.jta.debug("tx="+ tx);
833             }
834             
835             tx.doDetach(XAResource.TMSUSPEND);
836             threadTx.set(null);
837
838             if (TraceTm.jta.isDebugEnabled()) {
839                 TraceTm.jta.debug("threadTx.set= null");
840             }
841         }
842
843         return tx;
844     }
845
846     // ------------------------------------------------------------------
847
// ResourceManagerEventListener implementation
848
// Should be in UserTransaction only.
849
// ------------------------------------------------------------------
850

851     /**
852       * @see org.objectweb.transaction.jta.ResourceManagerEventListener#connectionOpened(org.objectweb.transaction.jta.ResourceManagerEvent)
853       */

854
855     public void connectionOpened(ResourceManagerEvent event) {
856
857         if (TraceTm.jta.isDebugEnabled()) {
858             TraceTm.jta.debug("Current.connectionOpened " + this);
859         }
860
861         List JavaDoc list = null;
862         Stack JavaDoc curStack = (Stack JavaDoc) eventListStack.get();
863         // get thread local stack
864

865         if (curStack == null) {
866             // no stack yet : create one
867
eventListStack.set(curStack = new Stack JavaDoc());
868         } else { // pop list from current stack
869
try {
870                 list = (List JavaDoc) curStack.pop();
871             } catch (EmptyStackException JavaDoc e) {
872                 // ignore: might happen if thread used by session bean
873
}
874         }
875
876         // no list yet: create one
877
if (list == null)
878             list = new Vector JavaDoc(1);
879
880         // add event to list
881
list.add(event);
882
883         if (TraceTm.jta.isDebugEnabled()) {
884             TraceTm.jta.debug("list.add(event) = " + event);
885         }
886
887         // push list into stack
888
curStack.push(list);
889     }
890
891     /**
892      * @see org.objectweb.transaction.jta.ResourceManagerEventListener#connectionClosed(org.objectweb.transaction.jta.ResourceManagerEvent)
893      */

894
895     public void connectionClosed(ResourceManagerEvent event) {
896
897         if (TraceTm.jta.isDebugEnabled()) {
898             TraceTm.jta.debug("Current.connectionClosed, remove");
899         }
900
901         // remove event from list
902
removeFromCurrentStack(event);
903     }
904
905     /**
906      * @see org.objectweb.transaction.jta.ResourceManagerEventListener#connectionErrorOccured(org.objectweb.transaction.jta.ResourceManagerEvent)
907      */

908
909     public void connectionErrorOccured(ResourceManagerEvent event) {
910
911         if (TraceTm.jta.isDebugEnabled()) {
912             TraceTm.jta.debug("Current.connectionErrorOccured");
913         }
914
915         removeFromCurrentStack(event); // remove event from list
916
}
917
918     private void removeFromCurrentStack(ResourceManagerEvent event) {
919
920         if (TraceTm.jta.isDebugEnabled()) {
921             TraceTm.jta.debug("Current.removeFromCurrentStack " + event);
922             TraceTm.jta.debug("Current = " + this);
923         }
924
925         Stack JavaDoc curStack = (Stack JavaDoc) eventListStack.get();
926         // get thread local stack
927

928         if (curStack == null) {
929             // if no transaction currently executing (no begin), no curStack
930
// has been put on the eventListStack so just return
931
return;
932         }
933
934         try {
935
936             List JavaDoc list = (List JavaDoc) curStack.peek();
937
938             if (list != null) {
939                 // get list from stack top
940

941                 list.remove(event);
942             }
943         } catch (EmptyStackException JavaDoc e) {
944             // no list of RM Events are known, just return
945
}
946     }
947
948     //
949
// objectweb transaction manager implementation
950
//
951

952     // thread local variable that stores all RM Events
953

954     private transient ThreadLocal JavaDoc eventListStack = new ThreadLocal JavaDoc();
955
956     /**
957      * @see org.objectweb.transaction.jta.TransactionManager#pushThreadLocalRMEventList(java.util.List)
958      */

959
960     public void pushThreadLocalRMEventList(List JavaDoc eventList) {
961
962         if (TraceTm.jta.isDebugEnabled()) {
963             TraceTm.jta.debug("Current.pushThreadLocalRMEventList");
964         }
965
966         Stack JavaDoc curStack = (Stack JavaDoc) eventListStack.get();
967
968         if (curStack == null) {
969             eventListStack.set(curStack = new Stack JavaDoc());
970         }
971
972         curStack.push(eventList);
973     }
974
975     /**
976      * @see org.objectweb.transaction.jta.TransactionManager#popThreadLocalRMEventList()
977      */

978
979     public List JavaDoc popThreadLocalRMEventList() {
980
981         if (TraceTm.jta.isDebugEnabled()) {
982             TraceTm.jta.debug("Current.popThreadLocalRMEventList");
983         }
984
985         Stack JavaDoc curStack = (Stack JavaDoc) eventListStack.get();
986         return (List JavaDoc) curStack.pop();
987     }
988
989     // ------------------------------------------------------------------
990
// Referenceable implementation
991
// ------------------------------------------------------------------
992

993     /**
994      * Retrieves the <code>Reference</code> of this object.
995      *
996      * @return The non-null <code>Reference</code> of this object.
997      *
998      * @exception NamingException If a naming exception was encountered while retrieving the reference.
999      */

1000
1001    public Reference JavaDoc getReference() throws NamingException JavaDoc {
1002
1003        if (TraceTm.jta.isDebugEnabled()) {
1004            TraceTm.jta.debug("Current.getReference()");
1005        }
1006
1007        // create the reference
1008
Reference JavaDoc ref = new Reference JavaDoc(this.getClass().getName(), "org.objectweb.jotm.UserTransactionFactory", null);
1009        Integer JavaDoc i = new Integer JavaDoc(transactionTimeout);
1010        ref.add(new StringRefAddr JavaDoc("jotm.timeout", i.toString()));
1011        return ref;
1012    }
1013
1014    // ------------------------------------------------------------------
1015
// Other public methods
1016
// ------------------------------------------------------------------
1017

1018    /**
1019     * Returns the unique instance of the class or <code>null</code> if not
1020     * initialized in case of plain client.
1021     *
1022     * @return The <code>Current</code> object created
1023     */

1024
1025    public static Current getCurrent() {
1026
1027        return unique;
1028    }
1029
1030    /**
1031     * Returns the TMFactory (in JTM)
1032     *
1033     * @return TransactionFactory
1034     */

1035
1036    public static TransactionFactory getJTM() {
1037
1038        if (tm == null) {
1039            TraceTm.jotm.error("Current: TMFactory is null!");
1040        }
1041
1042        return tm;
1043    }
1044    
1045    /**
1046     * Returns the Transaction Recovery object
1047     *
1048     * @return TransactionRecovery
1049     */

1050
1051    public static TransactionRecovery getTransactionRecovery() {
1052
1053        if (tr == null) {
1054            TraceTm.jotm.error("Current: Transaction Recovery is null!");
1055        }
1056
1057        return tr;
1058    }
1059    
1060    /**
1061     * Sets the default timeout value
1062     *
1063     * @param timeout timeout value (in seconds)
1064     */

1065
1066    public void setDefaultTimeout(int timeout) {
1067
1068        if (TraceTm.jta.isDebugEnabled()) {
1069            TraceTm.jta.debug("timeout= " + timeout);
1070        }
1071
1072        if (timeout != 0) {
1073            defaultTimeout = timeout;
1074        }
1075        
1076        if (TraceTm.jta.isDebugEnabled()) {
1077            TraceTm.jta.debug("default timeout= " + defaultTimeout);
1078        }
1079
1080    }
1081
1082    /**
1083      * Gets the default timeout value
1084      *
1085      * @return default timeout value (in seconds)
1086      */

1087
1088    public int getDefaultTimeout() {
1089
1090        return defaultTimeout;
1091    }
1092    
1093    /**
1094     * Sets the default recovery value
1095     *
1096     * @param recovery recovery value (true or false)
1097     */

1098
1099    public static void setDefaultRecovery(boolean recovery) {
1100
1101        TraceTm.recovery.info("Jotm Recovery= " + recovery);
1102
1103        transactionRecovery = recovery;
1104    }
1105
1106    /**
1107      * Gets the default recovery value
1108      *
1109      * @return default recovery value (true or false)
1110      */

1111
1112    public static boolean getDefaultRecovery() {
1113
1114        return transactionRecovery;
1115    }
1116
1117    /**
1118      * Associate to the current thread a transaction represented by its
1119      * transaction context.
1120      * This is used internally by the implicit propagation of the
1121      * transactional context:
1122      * <ul>
1123      * <li>in the skeleton, before calling the request (<code>isReply =
1124      * false</code>)</li>
1125      * <li>in the stub, after receiving the reply (<code>isReply =
1126      * true</code>)</li>
1127      * </ul>
1128      *
1129      * @param pctx TransactionContext
1130      * @param isReply <code>true</code> before calling a request,
1131      * <code>false</code> after receiving a reply
1132      */

1133
1134    public void setPropagationContext(TransactionContext pctx, boolean isReply) {
1135
1136        if (TraceTm.jotm.isDebugEnabled()) {
1137            TraceTm.jotm.debug("pctx=" + pctx + ", isReply=" + isReply);
1138        }
1139
1140        if (pctx == null) { // never isReply when pctx=null
1141

1142            if (TraceTm.jta.isDebugEnabled()) {
1143                TraceTm.jta.debug("detach tx");
1144            }
1145
1146            TransactionImpl tx = (TransactionImpl) threadTx.get();
1147
1148            if (TraceTm.jta.isDebugEnabled()) {
1149                TraceTm.jta.debug("threadTx.get= " + threadTx.toString());
1150            }
1151
1152            if (tx != null) {
1153                // Free TransactionImpl, if not used only!!!
1154
// This is to avoid memory leaks.
1155

1156                if (tx.isRemovable()) {
1157                    forgetTx(tx.getXid());
1158                }
1159
1160                // Detaches thread from any transaction
1161
threadTx.set(null);
1162
1163                if (TraceTm.jta.isDebugEnabled()) {
1164                    TraceTm.jta.debug("threadTx.set= null");
1165                }
1166            }
1167
1168            return;
1169        }
1170
1171        // Get the Transaction matching this Xid if it exists
1172
Xid xid = pctx.getXid();
1173        TransactionImpl tx = getTxXid(xid);
1174
1175        if (tx == null) {
1176
1177            if (!isReply) { // create a Transaction object
1178

1179                if (TraceTm.jta.isDebugEnabled()) {
1180                    TraceTm.jta.debug("new Tx");
1181                }
1182
1183                tx = new TransactionImpl(pctx);
1184                putTxXid(xid, tx);
1185
1186                // sets the time stamp for the transaction
1187
Date JavaDoc myDate = new Date JavaDoc();
1188                tx.setTxDate(myDate.toString());
1189
1190            } else {
1191
1192                // This may happen with Jeremie and distributed transactions with
1193
// no dammage.
1194

1195                if (TraceTm.jta.isDebugEnabled()) {
1196                    TraceTm.jta.debug("unknown tx:" + xid);
1197                }
1198            }
1199
1200        } else {
1201
1202            if (isReply) {
1203                // This thread is already associated to a transaction.
1204
// A proper PropagationContext exists yet, but it may have been changed
1205
// in case of distributed transaction.
1206

1207                if (TraceTm.jta.isDebugEnabled()) {
1208                    TraceTm.jta.debug("updating Xid=" + xid);
1209                }
1210
1211                tx.updatePropagationContext(pctx);
1212            } else {
1213
1214                if (TraceTm.jta.isDebugEnabled()) {
1215                    TraceTm.jta.debug("transaction already known:" + xid);
1216                }
1217            }
1218        }
1219
1220        // Associates this Tx with the current thread (= resume)
1221
// In case of Jeremy, if isReply, we are not in the correct thread, so
1222
// never touch threadTx in that case!!!
1223

1224       if (!isReply) {
1225            threadTx.set(tx);
1226
1227            if (TraceTm.jta.isDebugEnabled()) {
1228                TraceTm.jta.debug("threadTx.set= " + threadTx.toString());
1229            }
1230       }
1231    }
1232
1233    /**
1234      * Get the transaction context associated with the current thread or null
1235      * if the thread is not involved in a transaction.
1236      */

1237
1238    public TransactionContext getPropagationContext(boolean hold) {
1239
1240        if (TraceTm.jotm.isDebugEnabled()) {
1241            TraceTm.jotm.debug("hold=" + hold);
1242        }
1243
1244        try {
1245            TransactionImpl tx = (TransactionImpl) getTransaction();
1246
1247            if (tx != null) { // will return null if Tx not valid.
1248
return tx.getPropagationContext(hold);
1249            }
1250        } catch (SystemException JavaDoc e) {
1251            TraceTm.jotm.error("getPropagationContext system exception:", e);
1252        }
1253
1254        return null;
1255    }
1256
1257    /**
1258      * Forget all about this transaction.
1259      * References to <code>TransactionImpl</code> must be destroyed to allow
1260      * the garbage collector to free memory allocated to this transaction.
1261      *
1262      * @param xid <code>Xid</code> of the transaction
1263      */

1264
1265    public void forgetTx(Xid xid) {
1266
1267        // Only clear threadTx if this thread is working on its Xid
1268

1269        TransactionImpl txCur = (TransactionImpl) txXids.get (xid);
1270
1271        if (txCur != null && txCur.equals((TransactionImpl) threadTx.get())) {
1272            threadTx.set(null);
1273            
1274            if (TraceTm.jta.isDebugEnabled()) {
1275                TraceTm.jta.debug("threadTx.set = null");
1276            }
1277        }
1278        removeTxXid(xid);
1279    }
1280
1281    /**
1282      * Get the transaction referenced by Xid.
1283      *
1284      * @param xid <code>Xid</code> of the transaction
1285      */

1286
1287    public TransactionImpl getTxByXid(Xid xid) {
1288
1289        TransactionImpl tx = (TransactionImpl) txXids.get (xid);
1290        return tx;
1291    }
1292
1293    /**
1294      * Get the Xid's of all prepared transactions.
1295      *
1296      * @return array of all Xids in the prepared state
1297      */

1298
1299    public javax.transaction.xa.Xid JavaDoc[] getPreparedHeuristicXid() {
1300
1301        Vector JavaDoc xidlist;
1302        int xidcount;
1303        javax.transaction.xa.Xid JavaDoc xid = null;
1304
1305        xidcount = txXids.size(); /* Xid count */
1306
1307        if (xidcount == 0) {
1308            return null;
1309        }
1310
1311        xidlist = new Vector JavaDoc();
1312
1313        Set JavaDoc txXidsSet = txXids.keySet();
1314
1315        synchronized(txXids) {
1316
1317            Iterator JavaDoc txXidsIterator = txXidsSet.iterator();
1318
1319            while (txXidsIterator.hasNext()){
1320                TransactionImpl tx = (TransactionImpl) txXids.get(txXidsIterator.next());
1321
1322                try {
1323
1324                    if (tx.getStatus() == Status.STATUS_PREPARED) {
1325                        xid = (javax.transaction.xa.Xid JavaDoc) tx.getXid();
1326                        xidlist.add(xid);
1327                    }
1328                } catch (SystemException JavaDoc e) {
1329                    TraceTm.jotm.error("getPreparedHeuristicsXid system exception:", e);
1330                }
1331            }
1332        }
1333
1334        Vector JavaDoc mytxrecovered = JotmRecovery.getTxRecovered();
1335        
1336        return (javax.transaction.xa.Xid JavaDoc[]) xidlist.toArray();
1337    }
1338
1339    /**
1340      * Get all Xid's associated with this transaction.
1341      *
1342      * @return array of all Xids
1343      */

1344
1345    public javax.transaction.xa.Xid JavaDoc[] getAllXid() {
1346
1347        Vector JavaDoc xidlist;
1348        int xidcount;
1349        javax.transaction.xa.Xid JavaDoc xid = null;
1350
1351        xidcount = txXids.size(); /* Xid count */
1352
1353        if (xidcount == 0) {
1354            return null;
1355        }
1356
1357        xidlist = new Vector JavaDoc();
1358
1359        Set JavaDoc txXidsSet = txXids.keySet();
1360
1361        synchronized(txXids) {
1362
1363            Iterator JavaDoc txXidsIterator = txXidsSet.iterator();
1364
1365            while (txXidsIterator.hasNext()){
1366                TransactionImpl mytx = (TransactionImpl) txXids.get(txXidsIterator.next());
1367                xid = (javax.transaction.xa.Xid JavaDoc) mytx.getXid();
1368                xidlist.add(xid);
1369            }
1370        }
1371
1372        return (javax.transaction.xa.Xid JavaDoc[]) xidlist.toArray();
1373    }
1374
1375    /**
1376      * Get all executing transactions.
1377      *
1378      * @return array of all Transactions in execution
1379      */

1380
1381    public String JavaDoc [] getAllTx() {
1382
1383        Vector JavaDoc txList;
1384        List JavaDoc txResourceList;
1385        int txCount;
1386        int txResourceCount;
1387        String JavaDoc txStatusName;
1388
1389        txCount = txXids.size(); /* transaction count */
1390
1391        if (txCount == 0) {
1392            return null;
1393        }
1394
1395        txList = new Vector JavaDoc();
1396
1397        Set JavaDoc txXidsSet = txXids.keySet();
1398
1399        synchronized(txXids) {
1400
1401            Iterator JavaDoc txXidsIterator = txXidsSet.iterator();
1402
1403            while (txXidsIterator.hasNext()){
1404                TransactionImpl mytx = (TransactionImpl) txXids.get(txXidsIterator.next());
1405
1406                try {
1407                     txStatusName = StatusHelper.getStatusName (mytx.getStatus());
1408                } catch (SystemException JavaDoc e) {
1409                     txStatusName = "No State Defined";
1410                }
1411
1412                txResourceList = mytx.getEnlistedXAResource();
1413                txResourceCount = txResourceList.size();
1414
1415                if (txResourceCount == 0) {
1416                    txList.add(mytx.getTxDate() + "????" +
1417                               mytx.toString() + "????" +
1418                               "NO Resource Defined" + "????" +
1419                               txStatusName);
1420                } else {
1421
1422                    for (int i=0; i < txResourceCount; i++) {
1423                         txList.add(mytx.getTxDate() + "????" +
1424                                    mytx.toString() + "????" +
1425                                    txResourceList.get(i).toString() + "????" +
1426                                    txStatusName);
1427                    }
1428                }
1429            }
1430        }
1431
1432        String JavaDoc [] myTxString = new String JavaDoc [txCount] ;
1433
1434        for (int i=0; i < txCount; i++) {
1435            myTxString[i] = txList.get(i).toString();
1436        }
1437
1438        return myTxString;
1439    }
1440
1441    /**
1442     * Get all Transactions that may require recovery.
1443     *
1444     * @return array of all Transactions that may require recovery
1445     */

1446
1447   public String JavaDoc [] getAllRcTx() {
1448
1449       Vector JavaDoc vTxRecovered = null;
1450       Vector JavaDoc txList;
1451       int txCount;
1452
1453       JotmRecovery myjr = null;
1454
1455       if (tr == null) {
1456           if (TraceTm.recovery.isDebugEnabled()) {
1457               TraceTm.recovery.debug("tr= null");
1458           }
1459           return null;
1460       }
1461
1462       myjr = tr.getJotmRecovery();
1463       
1464       if (myjr == null) {
1465           return null;
1466       }
1467
1468       vTxRecovered = JotmRecovery.getTxRecovered();
1469       
1470       txCount = vTxRecovered.size();
1471       
1472       if (TraceTm.recovery.isDebugEnabled()) {
1473          TraceTm.recovery.debug("txcount= " + txCount);
1474       }
1475       
1476       if (txCount == 0) {
1477           return null;
1478       }
1479       
1480       txList = new Vector JavaDoc();
1481       TxRecovered mytxRecovered = null;
1482
1483       for (int i=0; i<txCount; i++){
1484           mytxRecovered = (TxRecovered) vTxRecovered.elementAt(i);
1485           
1486           Xid temptxxid = new XidImpl(mytxRecovered.gettxxid());
1487           
1488           // We must send the complete transaction Xid string along
1489
// with the truncated. The complete will be used for further
1490
// searching while the truncated will be used in the display
1491
// of the JSP.
1492

1493           txList.add(new String JavaDoc(mytxRecovered.gettxxid()) + "????" +
1494                temptxxid.toString() + "????" +
1495                mytxRecovered.gettxdatetime() + "????" +
1496                mytxRecovered.getxidcount());
1497       }
1498
1499       String JavaDoc [] myTxString = new String JavaDoc [txCount] ;
1500
1501       for (int i=0; i < txCount; i++) {
1502           myTxString[i] = txList.get(i).toString();
1503       }
1504
1505       return myTxString;
1506   }
1507   
1508   /**
1509    * Get all XAResources that may require recovery.
1510    *
1511    * @return array of all XAResources that may require recovery
1512    */

1513
1514  public String JavaDoc [] getAllXaTx(String JavaDoc stx) {
1515
1516      Vector JavaDoc xaList;
1517      Vector JavaDoc rmList;
1518      int txCount;
1519      int rmiCount;
1520      int myxacount = 0;
1521      boolean mytxfound = false;
1522      boolean myrmifound = false;
1523      boolean myrmregistered = false;
1524      boolean myxaresfound = false;
1525      String JavaDoc mytxstatusname;
1526
1527      JotmRecovery myjr = null;
1528
1529      if (tr == null) {
1530          return null;
1531      }
1532
1533      myjr = tr.getJotmRecovery();
1534      
1535      if (myjr == null) {
1536          if (TraceTm.recovery.isDebugEnabled()) {
1537              TraceTm.recovery.debug("myjr= null");
1538          }
1539          return null;
1540      }
1541      
1542      xaList = new Vector JavaDoc();
1543      TxxidRecovered mytxxidRecovered = null;
1544      TxRecovered mytxRecovered = null;
1545      Vector JavaDoc vTxRecovered = null;
1546      Vector JavaDoc vRecoverRmInfo = null;
1547      RmRegistration myRmRegistration = null;
1548      String JavaDoc myxares = null;
1549      
1550      vTxRecovered = JotmRecovery.getTxRecovered();
1551
1552      txCount = vTxRecovered.size();
1553      
1554      if (TraceTm.recovery.isDebugEnabled()) {
1555          TraceTm.recovery.debug("txcount= " + txCount);
1556      }
1557      
1558      for (int i=0; i<txCount; i++){
1559          mytxRecovered = (TxRecovered) vTxRecovered.elementAt(i);
1560          
1561          if (TraceTm.recovery.isDebugEnabled()) {
1562              TraceTm.recovery.debug("gettxxid= " + new String JavaDoc(mytxRecovered.gettxxid()));
1563              TraceTm.recovery.debug("stx=" + stx);
1564          }
1565          
1566          if (new String JavaDoc(mytxRecovered.gettxxid()).equals(stx)) {
1567              mytxfound = true;
1568              break;
1569          }
1570      }
1571      
1572      rmList = new Vector JavaDoc();
1573      RecoverRmInfo rmInfo = null;
1574      vRecoverRmInfo = JotmRecovery.getRecoverRmInfo();
1575      String JavaDoc myrm = null;
1576      Vector JavaDoc vRmRegistration = tr.getRmRegistration();
1577      
1578      if (mytxfound) {
1579          myxacount = mytxRecovered.getxidcount();
1580          
1581          if (TraceTm.recovery.isDebugEnabled()) {
1582              TraceTm.recovery.debug("myxacount= " + myxacount);
1583          }
1584          
1585          for (int i=0; i<myxacount; i++) {
1586              myrmregistered = false;
1587              myrmifound = false;
1588              myxaresfound = false;
1589              mytxxidRecovered = mytxRecovered.getRecoverTxXidInfo(i);
1590
1591              if (mytxxidRecovered == null) {
1592                  xaList.add("NotFound" + "????" +
1593                             "NotFound" + "????" +
1594                             "NotFound" + "????" +
1595                             "NotFound" + "????" +
1596                             "NotFound");
1597              } else {
1598                  rmiCount = vRecoverRmInfo.size();
1599                  
1600                  if (TraceTm.recovery.isDebugEnabled()) {
1601                      TraceTm.recovery.debug("rmiCount= " + rmiCount);
1602                  }
1603                
1604                  for (int j=0; j<rmiCount; j++){
1605                      rmInfo = (RecoverRmInfo) vRecoverRmInfo.elementAt(j);
1606                      
1607                      if (TraceTm.recovery.isDebugEnabled()) {
1608                          TraceTm.recovery.debug("getRecoverXaResName()= " + rmInfo.getRecoverXaResName());
1609                          TraceTm.recovery.debug("getRecoverxaresname()=" + mytxxidRecovered.getRecoverxaresname());
1610                          TraceTm.recovery.debug("getRecoverXaRes()= " + new String JavaDoc(rmInfo.getRecoverXaRes()));
1611                          TraceTm.recovery.debug("getRecoverxares()=" + new String JavaDoc(mytxxidRecovered.getRecoverxares()));
1612                      }
1613                     
1614                      // if (rmInfo.getRecoverXaResName().equals(mytxxidRecovered.getRecoverxaresname())) {
1615
if ((new String JavaDoc(rmInfo.getRecoverXaRes())).equals(new String JavaDoc(mytxxidRecovered.getRecoverxares()))) {
1616                          myrm = rmInfo.getRecoverRm();
1617                          myrmifound = true;
1618                          myxares = new String JavaDoc(mytxxidRecovered.getRecoverxares());
1619                          
1620                          if (TraceTm.recovery.isDebugEnabled()) {
1621                              TraceTm.recovery.debug("myrm= " + myrm);
1622                              TraceTm.recovery.debug("myxares= " + myxares);
1623                          }
1624                          break;
1625                      }
1626                  }
1627              
1628                  if (!myrmifound) {
1629                      myrm = "NotFound";
1630                  }
1631                    
1632                  if (vRmRegistration == null) {
1633                      if (TraceTm.recovery.isDebugEnabled()) {
1634                          TraceTm.recovery.debug("vRmRegistration is null");
1635                      }
1636                      myxares = "NotRegistered";
1637                  } else {
1638                      int rmregcount = vRmRegistration.size();
1639                      
1640                      if (TraceTm.recovery.isDebugEnabled()) {
1641                          TraceTm.recovery.debug("rmregcount= " + rmregcount);
1642                      }
1643                      
1644                      for (int j=0; j<rmregcount; j++){
1645                          myRmRegistration = (RmRegistration) vRmRegistration.elementAt(j);
1646                          
1647                          if (TraceTm.recovery.isDebugEnabled()) {
1648                              TraceTm.recovery.debug("myrm= " + myrm);
1649                              TraceTm.recovery.debug("rmGetName= " + myRmRegistration.rmGetName());
1650                          }
1651                          
1652                          if (myrm.equals(myRmRegistration.rmGetName())) {
1653                              myrmregistered = true;
1654                              
1655                              if (myRmRegistration.rmGetXaRes() == null) {
1656                                  myxares = "IsNull";
1657                              } else {
1658                                  myxares = myRmRegistration.rmGetXaRes().toString();
1659                                  myxaresfound = true;
1660                                  
1661                                  if (TraceTm.recovery.isDebugEnabled()) {
1662                                      TraceTm.recovery.debug("myxares= " + myxares);
1663                                  }
1664                              }
1665                              break;
1666                          }
1667                      }
1668                        
1669                      if (!myrmregistered) {
1670                          myxares = "NotRegistered";
1671                      }
1672                      
1673                      if (TraceTm.recovery.isDebugEnabled()) {
1674                          TraceTm.recovery.debug("myxares= " + myxares);
1675                      }
1676                  }
1677                  
1678                  Xid tempxid = new XidImpl(mytxxidRecovered.getRecoverxid());
1679                  
1680                  // We must send the complete Xid string along with the truncated.
1681
// The complete will be used for further searching while the
1682
// truncated will be used in the display of the JSP.
1683
xaList.add(myrm + "????" +
1684                        myxares + "????" +
1685                        new String JavaDoc(mytxxidRecovered.getRecoverxid()) + "????" +
1686                        new String JavaDoc(tempxid.toString()) + "????" +
1687                        StatusHelper.getStatusName (mytxxidRecovered.getRecoverstatus()));
1688              }
1689          }
1690      }
1691
1692      String JavaDoc [] myTxString = new String JavaDoc [myxacount] ;
1693
1694      for (int i=0; i < myxacount; i++) {
1695          myTxString[i] = xaList.get(i).toString();
1696      }
1697
1698      return myTxString;
1699  }
1700  
1701  /**
1702   * @return Returns all XAResources that require administrator recovery action.
1703   */

1704  public int actionXAResource (String JavaDoc xaAction, String JavaDoc xatx) {
1705      int commiterror;
1706      
1707      Vector JavaDoc vRmRegistration = null;
1708      Vector JavaDoc vRecoverRmInfo = null;
1709      int rmregcount;
1710      boolean mytxfound = false;
1711      boolean myrmifound = false;
1712      String JavaDoc mytxstatusname;
1713      JotmRecovery myjr = null;
1714      RmRegistration myRmRegistration = null;
1715      XAResource JavaDoc xaresource = null;
1716
1717      if (tr == null) {
1718          return 0;
1719      }
1720
1721      myjr = tr.getJotmRecovery();
1722      
1723      if (myjr == null) {
1724          return 0;
1725      }
1726
1727      vRmRegistration = tr.getRmRegistration();
1728      
1729      if (vRmRegistration == null) {
1730           return 0;
1731      }
1732      
1733      // Given the passed Resource Manager, find it in the RMRegistered vector.
1734
// When the Resource Manager is found, use the XAResource associated with
1735
// the RMRegistered Resource Manager to perform a XAResource.recover call
1736
// to return all XIDs that require recovery.
1737
// With the list of XIDs to be recovered, verify that the Xid passes in
1738
// the list. If the Xid passed is in the recover list, then we can attempt
1739
// the commit of the Xid (i.e., XAResource.Commit(Xid)).
1740
// When the commit is completed, we can remove the TxXidRecovered array
1741
// entry associated with the Xid and decrement the count in its respective
1742
// TxRecovered vector entry. If the count in the TxRecovered vector entry
1743
// is zero, we can then remove the TxRecovered entry from the vector.
1744

1745      String JavaDoc mys = xatx;
1746      int myix1 = mys.indexOf('\n');
1747      String JavaDoc sResmgr = mys.substring(0, myix1);
1748      int myix2 = mys.indexOf('\n', myix1 + 1);
1749      String JavaDoc sResource = mys.substring(myix1 + 1, myix2);
1750      int myix3 = mys.indexOf('\n', myix2 + 1);
1751      String JavaDoc sFullXid = mys.substring(myix2 + 1, myix3);
1752      String JavaDoc sXidstate = mys.substring(myix3 + 1);
1753
1754      rmregcount = vRmRegistration.size();
1755      
1756      for (int i=0; i<rmregcount; i++){
1757        myRmRegistration = (RmRegistration) vRmRegistration.elementAt(i);
1758
1759        if (sResmgr.equals(myRmRegistration.rmGetName())) {
1760            xaresource = myRmRegistration.rmGetXaRes();
1761            break;
1762        }
1763      }
1764      
1765      int rcflag = 0;
1766      
1767      javax.transaction.xa.Xid JavaDoc javaxid [] = new javax.transaction.xa.Xid JavaDoc[100];
1768      
1769      try {
1770          // recover returns javax.transaction.xa.Xid objects
1771
// we must cast to org.objectweb.jotm.Xid objects
1772
javaxid = xaresource.recover(rcflag);
1773      } catch (XAException JavaDoc e) {
1774          if (TraceTm.jta.isDebugEnabled()) {
1775              TraceTm.recovery.debug("xaResource.recover call failed during recovery " + e.getMessage());
1776          }
1777      }
1778      
1779      if (javaxid == null) {
1780
1781          if (TraceTm.recovery.isDebugEnabled()) {
1782              TraceTm.recovery.debug("No XIDs to recover for Xares javaxid is null");
1783          }
1784          
1785          cleanuptxrecovery(sFullXid);
1786          return 0;
1787      }
1788      
1789      if (javaxid.length == 0) {
1790
1791          if (TraceTm.recovery.isDebugEnabled()) {
1792              TraceTm.recovery.debug("No XIDs to recover for Xares= "+ xaresource);
1793          }
1794          
1795          cleanuptxrecovery(sFullXid);
1796          return 0;
1797      }
1798
1799      Xid rcxid [] = new Xid[javaxid.length];
1800      
1801      for (int xx=0; xx<javaxid.length; xx++) {
1802        
1803          if (javaxid[xx] == null) break;
1804
1805          if (new String JavaDoc(javaxid[xx].toString()).equals(sFullXid)) {
1806            
1807              if (xaAction == "commit") {
1808                  try {
1809                      xaresource.commit(javaxid[xx], false);
1810                  } catch (XAException JavaDoc e) {
1811                      TraceTm.recovery.error("Unable to commit Xid during Admin Recovery " + e.getMessage());
1812                  }
1813              } else {
1814                  if (xaAction == "rollback") {
1815                      try {
1816                          xaresource.rollback(javaxid[xx]);
1817                      } catch (XAException JavaDoc e) {
1818                          TraceTm.recovery.error("Unable to rollback Xid during Admin Recovery " + e.getMessage());
1819                      }
1820                  } else {
1821                       if (xaAction == "forget") {
1822                           try {
1823                               xaresource.rollback(javaxid[xx]);
1824                           } catch (XAException JavaDoc e) {
1825                               TraceTm.recovery.error("Unable to rollback Xid during Admin Recovery " + e.getMessage());
1826                           }
1827                       }
1828                  }
1829              }
1830          }
1831          break;
1832      }
1833      
1834      cleanuptxrecovery(sFullXid);
1835      return 0;
1836  }
1837  
1838  private void cleanuptxrecovery(String JavaDoc pFullXid) {
1839      
1840      // We can now remove the TxXidRecovered array entry associated with the
1841
// Xid and decrement the count in its respective TxRecovered vector entry.
1842
// If the count in the TxRecovered vector entry is zero, we can then remove
1843
// the TxRecovered entry from the vector.
1844

1845      Vector JavaDoc vTxRecovered = null;
1846      TxRecovered mytxRecovered = null;
1847      TxxidRecovered mytxxidRecovered = null;
1848      int txCount;
1849      int myxacount = 0;
1850      boolean mytxxidrecoveredfound = false;
1851    
1852      byte [] jotmDone = new byte [11];
1853      byte [] [] jotmDoneRecord = new byte [1] [11];
1854
1855      jotmDone = "RR3JOTMDONE".getBytes();
1856      
1857      vTxRecovered = JotmRecovery.getTxRecovered();
1858      txCount = vTxRecovered.size();
1859      
1860      for (int i=0; i<txCount; i++){
1861          mytxRecovered = (TxRecovered) vTxRecovered.elementAt(i);
1862          myxacount = mytxRecovered.getxidcount();
1863          
1864          for (int j=0; j<myxacount; j++) {
1865              mytxxidRecovered = mytxRecovered.getRecoverTxXidInfo(j);
1866              
1867              if (mytxxidRecovered != null) {
1868                
1869                  if (pFullXid.equals(new String JavaDoc(mytxxidRecovered.getRecoverxid()))) {
1870                      // mytxxidRecovered.setRecoverstatus(Status.STATUS_NO_TRANSACTION);
1871
mytxxidRecovered.setRecoverstatus(Status.STATUS_COMMITTED);
1872                      mytxxidrecoveredfound = true;
1873                      break;
1874                  }
1875              }
1876          }
1877          
1878          boolean allcompleted = true;
1879          
1880          for (int j=0; j<myxacount; j++) {
1881              mytxxidRecovered = mytxRecovered.getRecoverTxXidInfo(j);
1882            
1883              // if (mytxxidRecovered.getRecoverstatus() != Status.STATUS_NO_TRANSACTION) { // something other than completed
1884
if (mytxxidRecovered.getRecoverstatus() != Status.STATUS_COMMITTED) { // something other than completed
1885
allcompleted = false;
1886                  break;
1887              }
1888          }
1889          
1890          if (allcompleted) {
1891            XACommittingTx xaCommitTx = mytxRecovered.getXACommittingTx();
1892            jotmDoneRecord [0] = jotmDone;
1893            
1894            if (Current.getDefaultRecovery()) {
1895                try {
1896                    if (TraceTm.recovery.isDebugEnabled()) {
1897                        TraceTm.recovery.debug("Done howl log, after admin action");
1898                    }
1899                    
1900                    TransactionRecoveryImpl.getTransactionRecovery().howlDoneLog(jotmDoneRecord, xaCommitTx);
1901                } catch (Exception JavaDoc f) {
1902                    String JavaDoc howlerror =
1903                        "Cannot howlDoneLog:"
1904                        + f
1905                        + "--"
1906                        + f.getMessage();
1907                    TraceTm.jotm.error("Got LogException from howlDoneLog: "+ howlerror);
1908                }
1909            }
1910            
1911            vTxRecovered.remove(i);
1912            break;
1913          }
1914          
1915          if (mytxxidrecoveredfound) return;
1916      }
1917  }
1918  
1919    /**
1920     * Associate Thread to this transaction.
1921     * (used by iiop interceptor)
1922     */

1923
1924    public void associateThreadTx(Xid xid) {
1925  
1926        TransactionImpl tx = getTxXid(xid);
1927        threadTx.set(tx);
1928
1929        if (TraceTm.jta.isDebugEnabled()) {
1930            TraceTm.jta.debug("threadTx.set= " + threadTx.toString());
1931        }
1932    }
1933
1934    /**
1935     * Clear transaction from this thread if not known.
1936     * Useful when another thread completes the current thread's transaction
1937     */

1938    public void clearThreadTx() {
1939  
1940        TransactionImpl tx = (TransactionImpl) threadTx.get();
1941
1942        if (tx != null) {
1943            threadTx.set(null);
1944            if (TraceTm.jta.isDebugEnabled()) {
1945                TraceTm.jta.debug("threadTx.set=null");
1946            }
1947        }
1948    }
1949
1950    // ------------------------------------------------------------------
1951
// private methods
1952
// ------------------------------------------------------------------
1953

1954    /*
1955     * put the Tx/Xid mapping into the hashtable.
1956     */

1957
1958    private void putTxXid( Xid xid, TransactionImpl tx ) {
1959
1960        if ( TraceTm.jta.isDebugEnabled() ) {
1961            TraceTm.jta.debug("Associate tx to xid (xid=" + xid + ")");
1962        }
1963
1964        txXids.put(xid, tx);
1965    }
1966
1967    /*
1968     * given the Xid, get the corresponding Tx from the hashtable.
1969     */

1970
1971    private TransactionImpl getTxXid( Xid xid ) {
1972
1973        if ( TraceTm.jta.isDebugEnabled() ) {
1974            TraceTm.jta.debug("get tx from xid (xid="+ xid +")");
1975        }
1976
1977        TransactionImpl tx = (TransactionImpl) txXids.get(xid);
1978        return tx;
1979    }
1980
1981    /*
1982     * removeTxXid method.
1983     */

1984
1985    private void removeTxXid( Xid xid ) {
1986
1987        if ( TraceTm.jta.isDebugEnabled() ) {
1988            TraceTm.jta.debug("remove tx from xid (xid="+ xid +")");
1989        }
1990
1991        txXids.remove (xid);
1992    }
1993
1994    /**
1995     * remove the Transaction from the ThreadLocal
1996     */

1997
1998    void forget() throws Exception JavaDoc {
1999        threadTx.set(null);
2000
2001        if (TraceTm.jta.isDebugEnabled()) {
2002            TraceTm.jta.debug("threadTx.set= null");
2003        }
2004    }
2005
2006    /* Management methods */
2007
2008    /**
2009      * Returns the current number of transactions.
2010      *
2011      * @return current number of transaction
2012      */

2013
2014    public int getTotalCurrentTransactions() {
2015        return txXids.size();
2016    }
2017
2018    /**
2019     * Increments number of begun transactions by one.
2020     */

2021
2022    synchronized void incrementBeginCounter() {
2023        nb_bg_tx++;
2024    }
2025
2026    /**
2027     * Returns the total number of begun transactions.
2028     *
2029     * @return total number of begun transactions
2030     */

2031
2032    public int getTotalBegunTransactions() {
2033        return nb_bg_tx;
2034    }
2035
2036    /**
2037     * Increments the number of rolled back transaction by one.
2038     */

2039
2040    synchronized void incrementRollbackCounter() {
2041        nb_rb_tx++;
2042    }
2043
2044    /**
2045     * Returns the total number of rolled back transactions.
2046     *
2047     * @return total number of rolled back transactions
2048     */

2049
2050    public int getTotalRolledbackTransactions() {
2051        return nb_rb_tx;
2052    }
2053
2054    /**
2055     * Increments the number of of committed transactions by one.
2056     */

2057
2058    synchronized void incrementCommitCounter() {
2059        nb_cm_tx++;
2060    }
2061
2062    /**
2063     * Returns the total number of committed transactions.
2064     *
2065     * @return total number of commited transactions
2066     */

2067
2068    public int getTotalCommittedTransactions() {
2069        return nb_cm_tx;
2070    }
2071
2072    /**
2073     * Resets total number of transactions.
2074     */

2075
2076    public synchronized void resetAllTxTotalCounters() {
2077        nb_bg_tx = 0;
2078        nb_cm_tx = 0;
2079        nb_rb_tx = 0;
2080        nb_to = 0;
2081    }
2082
2083    /**
2084     * Increments number of rolled back transactions due to timeout by one.
2085     */

2086
2087    synchronized void incrementExpiredCounter() {
2088        nb_to++;
2089    }
2090
2091    /**
2092     * Returns the total number of rolled back transactions due to timeout.
2093     *
2094     * @return number of rolled back transactions due to timeout
2095     */

2096
2097    public int getTotalExpiredTransactions() {
2098        return nb_to;
2099    }
2100
2101    /**
2102     * Returns all counters.
2103     *
2104     * @return an array of all counters (current tx, begun tx, committed tx,
2105     * rolled back tx, timeouted tx)
2106     */

2107
2108    public synchronized Integer JavaDoc[] getTransactionCounters() {
2109        Integer JavaDoc[] result = new Integer JavaDoc[5];
2110        result[0] = new Integer JavaDoc(txXids.size());
2111        result[1] = new Integer JavaDoc(nb_bg_tx);
2112        result[2] = new Integer JavaDoc(nb_cm_tx);
2113        result[3] = new Integer JavaDoc(nb_rb_tx);
2114        result[4] = new Integer JavaDoc(nb_to);
2115        return result;
2116    }
2117
2118}
2119
Popular Tags