KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > tm > TxManager


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.tm;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import javax.resource.spi.work.Work JavaDoc;
33 import javax.resource.spi.work.WorkCompletedException JavaDoc;
34 import javax.resource.spi.work.WorkException JavaDoc;
35 import javax.transaction.HeuristicMixedException JavaDoc;
36 import javax.transaction.HeuristicRollbackException JavaDoc;
37 import javax.transaction.InvalidTransactionException JavaDoc;
38 import javax.transaction.NotSupportedException JavaDoc;
39 import javax.transaction.RollbackException JavaDoc;
40 import javax.transaction.Status JavaDoc;
41 import javax.transaction.SystemException JavaDoc;
42 import javax.transaction.Transaction JavaDoc;
43 import javax.transaction.TransactionManager JavaDoc;
44 import javax.transaction.xa.XAException JavaDoc;
45 import javax.transaction.xa.Xid JavaDoc;
46
47 import org.jboss.logging.Logger;
48 import org.jboss.tm.integrity.TransactionIntegrity;
49 import org.jboss.tm.recovery.LogRecord;
50 import org.jboss.tm.recovery.RecoveryLogger;
51 import org.jboss.tm.recovery.TxCompletionHandler;
52 import org.jboss.tm.remoting.interfaces.Coordinator;
53 import org.jboss.tm.remoting.interfaces.RecoveryCoordinator;
54 import org.jboss.tm.remoting.interfaces.Resource;
55 import org.jboss.tm.remoting.interfaces.TxPropagationContext;
56 import org.jboss.util.UnexpectedThrowable;
57 import org.jboss.util.UnreachableStatementException;
58
59 /**
60  * Our TransactionManager implementation.
61  *
62  * @author <a HREF="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>
63  * @author <a HREF="mailto:marc.fleury@telkel.com">Marc Fleury</a>
64  * @author <a HREF="mailto:osh@sparre.dk">Ole Husgaard</a>
65  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
66  * @author <a HREF="reverbel@ime.usp.br">Francisco Reverbel</a>
67  * @author <a HREF="adrian@jboss.com">Adrian Brock</a>
68  * @author <a HREF="dimitris@jboss.org">Dimitris Andreadis</a>
69  * @version $Revision: 43424 $
70  * @deprecated Do not reference directly, use org.jboss.tm.TransactionManagerLocator
71  */

72 public class TxManager
73       implements TransactionManager JavaDoc,
74                  TransactionPropagationContextImporter,
75                  TransactionPropagationContextFactory,
76                  TransactionLocalDelegate,
77                  TransactionTimeoutConfiguration,
78                  JBossXATerminator,
79                  StringRemoteRefConverter
80 {
81    // Constants -----------------------------------------------------
82

83    // Attributes ----------------------------------------------------
84

85    /**
86     * True if the TxManager should keep a map from GlobalIds to transactions.
87     */

88    private boolean globalIdsEnabled = false;
89
90    /**
91     * True if distributed transaction management is enabled.
92     */

93    private boolean dtmEnabled = false;
94
95    /**
96     * Whether to interrupt threads at transaction timeout
97     */

98    private boolean interruptThreads = false;
99
100    /**
101     * Instance logger.
102     */

103    private Logger log = Logger.getLogger(this.getClass());
104
105    /**
106     * True if trace messages should be logged.
107     */

108    private boolean trace = log.isTraceEnabled();
109
110    /**
111     * Default timeout in milliseconds.
112     * Must be >= 1000!
113     */

114    private long timeOut = 5 * 60 * 1000;
115
116    // The following two fields are ints (not longs) because
117
// volatile 64Bit types are broken (i.e. access is not atomic) in most VMs, and we
118
// don't want to lock just for a statistic. Additionaly,
119
// it will take several years on a highly loaded system to
120
// exceed the int range. Note that we might loose an
121
// increment every now and then, since the ++ operation is
122
// not atomic on volatile data types.
123
/**
124     * A count of the transactions that have been committed
125     */

126    private volatile int commitCount;
127    /**
128     * A count of the transactions that have been rolled back
129     */

130    private volatile int rollbackCount;
131
132    /** The recovery logger */
133    private RecoveryLogger recoveryLogger;
134
135    /** Indicates that the recovery process was not yet performed */
136    private boolean recoveryPending = true;
137
138    /** The transaction integrity policy */
139    private TransactionIntegrity integrity;
140    
141    /** Number of completion retries before reporting a heuristic hazard. */
142    private int completionRetryLimit = 0; // default: no retries
143

144    /** Blocking timeout between completion retries. */
145    private int completionRetryTimeout = 1 * 1000; // default: one sec
146

147    /** Timeout (in milliseconds) for retrying operations on XA resources */
148    private int xaRetryTimeout = 60 * 1000;
149    
150    /** Timeout (in milliseconds) for a tx branch in the prepared state */
151    private int preparedTimeout = 60 * 1000;
152
153    /** True if the root branch should remember heuristic decisions */
154    private boolean rootBranchRemembersHeuristicDecisions = true;
155    
156    /** True if heuristic hazards generate JTA heuristic mixed exceptions */
157    private boolean reportHeuristicHazardAsHeuristicMixed = false;
158
159    // Static --------------------------------------------------------
160

161    /**
162     * The singleton instance.
163     */

164    private static TxManager singleton = new TxManager();
165
166    /**
167     * Get a reference to the singleton instance.
168     */

169    public static TxManager getInstance()
170    {
171       return singleton;
172    }
173
174    // Constructors --------------------------------------------------
175

176    /**
177     * Private constructor for singleton. Use getInstance() to obtain
178     * a reference to the singleton.
179     */

180    private TxManager()
181    {
182       //make sure TxCapsule can be used
183
TransactionImpl.defaultXidFactory();
184    }
185
186    // Public --------------------------------------------------------
187

188    /**
189     * Clears all transactions. <p/>
190     * This method exists for testing purposes only. It should not be
191     * called during normal operation.
192     */

193    public void clear()
194    {
195       Collection JavaDoc txCollection = localIdTx.values();
196       synchronized (localIdTx)
197       {
198          Iterator JavaDoc i = txCollection.iterator();
199          while (i.hasNext())
200          {
201             TransactionImpl tx = (TransactionImpl) i.next();
202             tx.deactivate();
203          }
204       }
205       localIdTx.clear();
206       if (globalIdsEnabled)
207          globalIdTx.clear();
208    }
209    
210    /**
211     * Setter for attribute <code>globalIdsEnabled</code>.
212     */

213    public void setGlobalIdsEnabled(boolean newValue)
214    {
215       trace = log.isTraceEnabled(); // hack!
216
XidImpl.setTrulyGlobalIdsEnabled(newValue);
217       globalIdsEnabled = newValue;
218    }
219
220    /**
221     * Getter for attribute <code>globalIdsEnabled</code>.
222     */

223    public boolean getGlobalIdsEnabled()
224    {
225       return globalIdsEnabled;
226    }
227
228    /**
229     * Enable/disable thread interruption at transaction timeout.
230     *
231     * @param interruptThreads pass true to interrupt threads, false otherwise
232     */

233    public void setInterruptThreads(boolean interruptThreads)
234    {
235       this.interruptThreads = interruptThreads;
236    }
237
238    /**
239     * Is thread interruption enabled at transaction timeout
240     *
241     * @return true for interrupt threads, false otherwise
242     */

243    public boolean isInterruptThreads()
244    {
245       return interruptThreads;
246    }
247
248    /**
249     * Set the recovery logger
250     *
251     * @param recoveryLogger the recovery logger
252     */

253    public void setRecoveryLogger(RecoveryLogger recoveryLogger)
254    {
255       this.recoveryLogger = recoveryLogger;
256    }
257
258    /**
259     * Get the recovery logger
260     *
261     * @return the recovery logger
262     */

263    public RecoveryLogger getRecoveryLogger()
264    {
265       return recoveryLogger;
266    }
267
268    /**
269     * Clears the recovery pending flag. Called by the recovery manager, at
270     * the end of the recovery proccess.
271     */

272    public void clearRecoveryPending()
273    {
274       this.recoveryPending = false;
275    }
276    
277    /**
278     * Returns the value of the recovery pending flag.
279     *
280     * @return true is recovery is pending, false otherwise.
281     */

282    public boolean isRecoveryPending()
283    {
284       return recoveryPending;
285    }
286    
287    /**
288     * Set the transaction integrity policy
289     *
290     * @param integrity the transaction integrity policy
291     */

292    public void setTransactionIntegrity(TransactionIntegrity integrity)
293    {
294       this.integrity = integrity;
295    }
296
297    /**
298     * Get the transaction integrity policy
299     *
300     * @return the transaction integrity policy
301     */

302    public TransactionIntegrity getTransactionIntegrity()
303    {
304       return integrity;
305    }
306    
307    /**
308     * Sets the completion retry limit. This is the maximum number of times that
309     * the transaction manager retries a completion operation (either commit or
310     * rollback) on a resource (either a remote <code>Resource</code> or an
311     * <code>XAResource</code>) that raised a transient exception. Whoever called
312     * the transaction manager is blocked while the completion retries are
313     * performed. If the completion retry limit is reached, the transaction
314     * manager abandons the retries and throws a heuristic hazard exception.
315     *
316     * @param maxCompletionRetries the completion retry limit.
317     */

318    public void setCompletionRetryLimit(int maxCompletionRetries)
319    {
320       this.completionRetryLimit = maxCompletionRetries;
321    }
322    
323    /**
324     * Gets the completion retry limit. This is the maximum number of times that
325     * the transaction manager retries a completion operation (either commit or
326     * rollback) on a resource (either a remote <code>Resource</code> or an
327     * <code>XAResource</code>) that raised a transient exception. Whoever called
328     * the transaction manager is blocked while the completion retries are
329     * performed. If the completion retry limit is reached, the transaction
330     * manager abandons the retries and throws a heuristic hazard exception.
331     *
332     * @return the completion retry limit.
333     */

334    public int getCompletionRetryLimit()
335    {
336       return completionRetryLimit;
337    }
338    
339    /**
340     * Sets the completion retry timeout. The completion retry timeout is the
341     * number of seconds that the transaction manager waits before retrying a
342     * completion operation (either commit or rollback) on a resource (either a
343     * remote <code>Resource</code> or an <code>XAResource</code>) that raised a
344     * transient exception. This is a blocking timeout (whoever called the
345     * transaction manager is blocked until the commit or rollback is retried)
346     * and is applicable if the transaction manager did not report a heuristic
347     * hazard for the transaction. If a heuristic hazard has been reported, then
348     * the applicable timouts are the non-blocking ones: the XA retry timeout and
349     * the prepared timeout.
350     *
351     * @param seconds the timeout (in seconds) for retrying a completion
352     * operation after a transient exception and before the
353     * transaction manager reports a heuristic hazard.
354     */

355    public void setCompletionRetryTimeout(int seconds)
356    {
357       this.completionRetryTimeout = 1000 * seconds;
358    }
359    
360    /**
361     * Gets the completion retry timeout. The completion retry timeout is the
362     * number of seconds that the transaction manager waits before retrying a
363     * completion operation (either commit or rollback) on a resource (either a
364     * remote <code>Resource</code> or an <code>XAResource</code>) that raised a
365     * transient exception. This is a blocking timeout (whoever called the
366     * transaction manager is blocked until the commit or rollback is retried)
367     * and is applicable if the transaction manager did not report a heuristic
368     * hazard for the transaction. If a heuristic hazard has been reported, then
369     * the applicable timouts are the non-blocking ones: the XA retry timeout and
370     * the prepared timeout.
371     *
372     * @return the timeout (in seconds) for retrying a completion operation
373     * after a transient exception and before the transaction manager
374     * reports a heuristic hazard.
375     */

376    public int getCompletionRetryTimeout()
377    {
378       return completionRetryTimeout / 1000;
379    }
380
381    /**
382     * Gets the completion retry timeout in milliseconds.
383     *
384     * @return the timeout (in milliseconds) for retrying a completion operation
385     * after a transient exception and before the transaction manager
386     * reports a heuristic hazard.
387     */

388    public int getCompletionRetryTimeoutMillis()
389    {
390       return xaRetryTimeout;
391    }
392    
393    /**
394     * Sets the XA retry timeout.
395     *
396     * @param seconds the timeout (in seconds) for retrying operations on XA
397     * resources.
398     */

399    public void setXARetryTimeout(int seconds)
400    {
401       this.xaRetryTimeout = 1000 * seconds;
402    }
403    
404    /**
405     * Gets the XA retry timeout.
406     *
407     * @return the timeout (in seconds) for retrying operations on XA resources.
408     */

409    public int getXARetryTimeout()
410    {
411       return xaRetryTimeout / 1000;
412    }
413    
414    /**
415     * Gets the XA retry timeout in milliseconds.
416     *
417     * @return the timeout (in milliseconds) for retrying operations on XA
418     * resources.
419     */

420    public int getXARetryTimeoutMillis()
421    {
422       return xaRetryTimeout;
423    }
424    
425    /**
426     * Sets the prepared timeout. A transaction branch that is the prepared
427     * state waits for an amount of time equal to the prepared timeout before
428     * generating a call to <code>replayCompletion</code> on its recovery
429     * coordinator.
430     *
431     * @param seconds the timeout (in seconds) for a transaction branch in the
432     * the prepared state.
433     */

434    public void setPreparedTimeout(int seconds)
435    {
436       this.preparedTimeout = 1000 * seconds;
437    }
438    
439    /**
440     * Gets the prepared timeout. A transaction branch that is the prepared
441     * state waits for an amount of time equal to the prepared timeout before
442     * generating a call to <code>replayCompletion</code> on its recovery
443     * coordinator.
444     *
445     * @return the timeout (in seconds) for a transaction branch in the prepared
446     * state.
447     */

448    public int getPreparedTimeout()
449    {
450       return preparedTimeout / 1000;
451    }
452    
453    /**
454     * Gets the prepared timeout in milliseconds.
455     *
456     * @return the timeout (in milliseconds) for a transaction branch in the
457     * prepared state.
458     */

459   public int getPreparedTimeoutMillis()
460    {
461       return preparedTimeout;
462    }
463    
464   /**
465    * Sets the boolean attribute "root branch remembers heuristic decisions".
466    * If this attribute is true, the root branch remembers a heuristically
467    * completed transaction until explicitly told (through a call to the MBean
468    * operation <code>forget</code>) to forget that transaction. If this
469    * attribute is false, the root branch immediately forgets a transaction
470    * when the transaction completes.
471    *
472    * @param newValue true if the root branch should remember heuristic
473    * decisions, false otherwise.
474    */

475   public void setRootBranchRemembersHeuristicDecisions(boolean newValue)
476   {
477      rootBranchRemembersHeuristicDecisions = newValue;
478   }
479   
480   /**
481    * Gets the boolean attribute "root branch remembers heuristic decisions".
482    * If this attribute is true, the root branch remembers a heuristically
483    * completed transaction until explicitly told (through a call to the MBean
484    * operation <code>forget</code>) to forget that transaction. If this
485    * attribute is false, the root branch immediately forgets a transaction
486    * when the transaction completes.
487    *
488    * @return true if the root branch remember heuristic decisions,
489    * false otherwise.
490    */

491   public boolean isRootBranchRemembersHeuristicDecisions()
492   {
493      return rootBranchRemembersHeuristicDecisions;
494   }
495   
496   /**
497    * Sets the boolean attribute "report heuristic hazard as heuristic mixed".
498    * If this attribute is true, each of the commit methods of the JTA API
499    * (<code>javax.transaction.Transaction.commit()</code>,
500    * <code>javax.transaction.TransactionManager.commit()</code>, and
501    * <code>javax.transaction.UserTransaction.commit()</code>) throws a
502    * <code>HeuristicMixedException</code> to report a heuristic hazard to its
503    * caller. If the attribute is false, those methods do not report heuristic
504    * hazards to their callers. In any case, transactions with heuristic hazard
505    * status are listed by the MBean operation
506    * <code>listHeuristicallyCompletedTransactions()</code>.
507    *
508    * @param newValue true if a JTA commit should throw
509    * <code>HeuristicMixedException</code> to report a heuristic hazard
510    * to its caller, or false if a JTA commit should not report a
511    * heuristic hazard to its caller.
512    */

513   public void setReportHeuristicHazardAsHeuristicMixed(boolean newValue)
514   {
515      reportHeuristicHazardAsHeuristicMixed = newValue;
516   }
517   
518   /**
519    * Gets the boolean attribute "report heuristic hazard as heuristic mixed".
520    * If this attribute is true, each of the commit methods of the JTA API
521    * (<code>javax.transaction.Transaction.commit()</code>,
522    * <code>javax.transaction.TransactionManager.commit()</code>, and
523    * <code>javax.transaction.UserTransaction.commit()</code>) throws a
524    * <code>HeuristicMixedException</code> to report a heuristic hazard to its
525    * caller. If the attribute is false, those methods do not report heuristic
526    * hazards to their callers. In any case, transactions with heuristic hazard
527    * status are listed by the MBean operation
528    * <code>listHeuristicallyCompletedTransactions()</code>.
529    *
530    * @return true if a JTA commit throws <code>HeuristicMixedException</code>
531    * to report a heuristic hazard to its caller, or false if a JTA
532    * commit does not report a heuristic hazard to its caller.
533    */

534   public boolean isReportHeuristicHazardAsHeuristicMixed()
535   {
536      return reportHeuristicHazardAsHeuristicMixed;
537   }
538   
539    /**
540     * Begin a new transaction.
541     * The new transaction will be associated with the calling thread.
542     */

543    public void begin()
544          throws NotSupportedException JavaDoc,
545                 SystemException JavaDoc
546    {
547       trace = log.isTraceEnabled(); // hack!
548

549       ThreadInfo ti = getThreadInfo();
550       TransactionImpl current = ti.tx;
551
552       if (current != null)
553       {
554          if (current.isDone())
555             disassociateThread(ti);
556          else
557             throw new NotSupportedException JavaDoc
558             ("Transaction already active, cannot nest transactions.");
559       }
560
561       long timeout = (ti.timeout == 0) ? timeOut : ti.timeout;
562       TransactionImpl tx = new TransactionImpl(timeout);
563       associateThread(ti, tx);
564       localIdTx.put(tx.getLocalId(), tx);
565       if (globalIdsEnabled)
566          globalIdTx.put(tx.getGlobalId(), tx);
567
568       if (trace)
569          log.trace("began tx: " + tx);
570    }
571
572    /**
573     * Commit the transaction associated with the currently running thread.
574     */

575    public void commit()
576          throws RollbackException JavaDoc,
577                 HeuristicMixedException JavaDoc,
578                 HeuristicRollbackException JavaDoc,
579                 SecurityException JavaDoc,
580                 IllegalStateException JavaDoc,
581                 SystemException JavaDoc
582    {
583       ThreadInfo ti = getThreadInfo();
584       TransactionImpl current = ti.tx;
585
586       if (current != null)
587       {
588          current.commit();
589          disassociateThread(ti);
590          if (trace)
591             log.trace("commited tx: " + current);
592       }
593       else
594          throw new IllegalStateException JavaDoc("No transaction.");
595    }
596
597    /**
598     * Return the status of the transaction associated with the currently
599     * running thread, or <code>Status.STATUS_NO_TRANSACTION</code> if no
600     * active transaction is currently associated.
601     */

602    public int getStatus()
603          throws SystemException JavaDoc
604    {
605       ThreadInfo ti = getThreadInfo();
606       TransactionImpl current = ti.tx;
607
608       if (current != null)
609       {
610          if (current.isDone())
611             disassociateThread(ti);
612          else
613             return current.getStatus();
614       }
615       return Status.STATUS_NO_TRANSACTION;
616    }
617
618    /**
619     * Return the transaction currently associated with the invoking thread,
620     * or <code>null</code> if no active transaction is currently associated.
621     */

622    public Transaction JavaDoc getTransaction()
623          throws SystemException JavaDoc
624    {
625       ThreadInfo ti = getThreadInfo();
626       TransactionImpl current = ti.tx;
627
628       if (current != null && current.isDone())
629       {
630          current = null;
631          disassociateThread(ti);
632       }
633
634       return current;
635    }
636
637    /**
638     * Resume a transaction.
639     * <p/>
640     * Note: This will not enlist any resources involved in this
641     * transaction. According to JTA1.0.1 specification section 3.2.3,
642     * that is the responsibility of the application server.
643     */

644    public void resume(Transaction JavaDoc transaction)
645          throws InvalidTransactionException JavaDoc,
646                 IllegalStateException JavaDoc,
647                 SystemException JavaDoc
648    {
649       if (transaction != null && !(transaction instanceof TransactionImpl))
650          throw new RuntimeException JavaDoc("Not a TransactionImpl, but a " +
651          transaction.getClass().getName());
652
653       ThreadInfo ti = getThreadInfo();
654       TransactionImpl current = ti.tx;
655
656       if (current != null)
657       {
658          if (current.isDone())
659             current = ti.tx = null;
660          else
661             throw new IllegalStateException JavaDoc("Already associated with a tx");
662       }
663
664       if (current != transaction)
665       {
666          associateThread(ti, (TransactionImpl) transaction);
667       }
668
669       if (trace)
670          log.trace("resumed tx: " + ti.tx);
671    }
672
673    /**
674     * Suspend the transaction currently associated with the current
675     * thread, and return it.
676     * <p/>
677     * Note: This will not delist any resources involved in this
678     * transaction. According to JTA1.0.1 specification section 3.2.3,
679     * that is the responsibility of the application server.
680     */

681    public Transaction JavaDoc suspend()
682          throws SystemException JavaDoc
683    {
684       ThreadInfo ti = getThreadInfo();
685       TransactionImpl current = ti.tx;
686
687       if (current != null)
688       {
689          current.disassociateCurrentThread();
690          ti.tx = null;
691
692          if (trace)
693             log.trace("suspended tx: " + current);
694
695          if (current.isDone())
696             current = null;
697       }
698
699       return current;
700    }
701
702    /**
703     * Roll back the transaction associated with the currently running thread.
704     */

705    public void rollback()
706          throws IllegalStateException JavaDoc,
707                 SecurityException JavaDoc,
708                 SystemException JavaDoc
709    {
710       ThreadInfo ti = getThreadInfo();
711       TransactionImpl current = ti.tx;
712
713       if (current != null)
714       {
715          if (!current.isDone())
716          {
717             current.rollback();
718
719             if (trace)
720                log.trace("rolled back tx: " + current);
721             return;
722          }
723          disassociateThread(ti);
724       }
725       throw new IllegalStateException JavaDoc("No transaction.");
726    }
727
728    /**
729     * Mark the transaction associated with the currently running thread
730     * so that the only possible outcome is a rollback.
731     */

732    public void setRollbackOnly()
733          throws IllegalStateException JavaDoc,
734                 SystemException JavaDoc
735    {
736       ThreadInfo ti = getThreadInfo();
737       TransactionImpl current = ti.tx;
738
739       if (current != null)
740       {
741          if (!current.isDone())
742          {
743             current.setRollbackOnly();
744
745             if (trace)
746                log.trace("tx marked for rollback only: " + current);
747             return;
748          }
749          ti.tx = null;
750       }
751       throw new IllegalStateException JavaDoc("No transaction.");
752    }
753
754    public int getTransactionTimeout()
755    {
756       return (int) (getThreadInfo().timeout / 1000);
757    }
758
759    /**
760     * Set the transaction timeout for new transactions started by the
761     * calling thread.
762     */

763    public void setTransactionTimeout(int seconds)
764          throws SystemException JavaDoc
765    {
766       getThreadInfo().timeout = 1000 * seconds;
767
768       if (trace)
769          log.trace("tx timeout is now: " + seconds + "s");
770    }
771
772    /**
773     * Set the default transaction timeout for new transactions.
774     * This default value is used if <code>setTransactionTimeout()</code>
775     * was never called, or if it was called with a value of <code>0</code>.
776     */

777    public void setDefaultTransactionTimeout(int seconds)
778    {
779       timeOut = 1000L * seconds;
780
781       if (trace)
782          log.trace("default tx timeout is now: " + seconds + "s");
783    }
784
785    /**
786     * Get the default transaction timeout.
787     *
788     * @return Default transaction timeout in seconds.
789     */

790    public int getDefaultTransactionTimeout()
791    {
792       return (int) (timeOut / 1000);
793    }
794
795    public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException JavaDoc
796    {
797       try
798       {
799          ThreadInfo ti = getThreadInfo();
800          TransactionImpl current = ti.tx;
801          if (current != null && current.isDone())
802          {
803             disassociateThread(ti);
804             return -1;
805          }
806          return current.getTimeLeftBeforeTimeout(errorRollback);
807       }
808       catch (RollbackException JavaDoc e)
809       {
810          throw e;
811       }
812       catch (Exception JavaDoc ignored)
813       {
814          return -1;
815       }
816    }
817
818    /**
819     * The following 2 methods are here to provide association and
820     * disassociation of the thread.
821     */

822    public Transaction JavaDoc disassociateThread()
823    {
824       return disassociateThread(getThreadInfo());
825    }
826
827    private Transaction JavaDoc disassociateThread(ThreadInfo ti)
828    {
829       TransactionImpl current = ti.tx;
830       ti.tx = null;
831       current.disassociateCurrentThread();
832       return current;
833    }
834
835    public void associateThread(Transaction JavaDoc transaction)
836    {
837       if (transaction != null && !(transaction instanceof TransactionImpl))
838          throw new RuntimeException JavaDoc("Not a TransactionImpl, but a " +
839          transaction.getClass().getName());
840
841       // Associate with the thread
842
TransactionImpl transactionImpl = (TransactionImpl) transaction;
843       ThreadInfo ti = getThreadInfo();
844       ti.tx = transactionImpl;
845       transactionImpl.associateCurrentThread();
846    }
847
848    private void associateThread(ThreadInfo ti, TransactionImpl transaction)
849    {
850       // Associate with the thread
851
ti.tx = transaction;
852       transaction.associateCurrentThread();
853    }
854
855    /**
856     * Return the number of active transactions
857     */

858    public int getTransactionCount()
859    {
860       return localIdTx.size();
861    }
862
863    /**
864     * A count of the transactions that have been committed
865     */

866    public long getCommitCount()
867    {
868       return commitCount;
869    }
870
871    /**
872     * A count of the transactions that have been rolled back
873     */

874    public long getRollbackCount()
875    {
876       return rollbackCount;
877    }
878
879    /**
880     * Lists the in-doubt transactions.
881     *
882     * @return a string with a text listing of in-doubt transactions.
883     */

884    public String JavaDoc listInDoubtTransactions()
885    {
886       // TODO
887
throw new org.jboss.util.NotImplementedException();
888    }
889    
890    /**
891     * Heuristically commits an in-doubt transaction.
892     *
893     * @param localTransactionId the local id of the in-doubt transaction to be
894     * heuristically committed.
895     */

896    public void heuristicallyCommit(long localTransactionId)
897    {
898       // TODO
899
throw new org.jboss.util.NotImplementedException();
900    }
901    
902    /**
903     * Heuristically commits all in-doubt transactions.
904     */

905   public void heuristicallyCommitAll()
906   {
907      // TODO
908
throw new org.jboss.util.NotImplementedException();
909   }
910    
911    /**
912     * Heuristically rolls back an in-doubt transaction.
913     *
914     * @param localTransactionId the local id of the in-doubt transaction to be
915     * heuristically rolled back.
916     */

917    public void heuristicallyRollback(long localTransactionId)
918    {
919       // TODO
920
throw new org.jboss.util.NotImplementedException();
921    }
922    
923    /**
924     * Heuristically rolls back all in-doubt transactions.
925     */

926    public void heuristicallyRollbackAll()
927    {
928       // TODO
929
throw new org.jboss.util.NotImplementedException();
930    }
931    
932    /**
933     * Lists the heuristically completed transactions coordinated by this
934     * transaction manager. A transaction that was heuristically completed
935     * by a call to <code>heuristicallyCommit(long localTransactionId)</code>,
936     * <code>heuristicallyCommitAll()</code>,
937     * <code>heuristicallyRollback(long localTransactionId)</code>, or
938     * <code>heuristicallyRollbackAll()</code> does not appear in the listing,
939     * as that transaction had a foreign coordinator.
940     *
941     * @return a string with a text listing of heuristically completed
942     * transactions.
943     */

944    public String JavaDoc listHeuristicallyCompletedTransactions()
945    {
946       // TODO
947
throw new org.jboss.util.NotImplementedException();
948    }
949    
950    /**
951     * Forgets a heuristically completed transaction coordinated by this
952     * transaction manager.
953     *
954     * @param localTransactionId the local id of a heuristically completed
955     * transaction coordinated by this transaction
956     * manager.
957     */

958    public void forget(long localTransactionId)
959    {
960       // TODO
961
throw new org.jboss.util.NotImplementedException();
962    }
963    
964    /**
965     * Forgets all heuristically completed transactions coordinated by this
966     * transaction manager.
967     */

968    public void forgetAll()
969    {
970       // TODO
971
throw new org.jboss.util.NotImplementedException();
972    }
973
974    // Implements TransactionPropagationContextImporter ---------------
975

976    /**
977     * Import a transaction propagation context into this TM.
978     * The TPC is loosely typed, as we may (at a later time) want to
979     * import TPCs that come from other transaction domains without
980     * offloading the conversion to the client.
981     *
982     * @param tpc The transaction propagation context that we want to
983     * import into this TM. Currently this is an instance
984     * of LocalId. At some later time this may be an instance
985     * of a transaction propagation context from another
986     * transaction domain like
987     * org.omg.CosTransactions.PropagationContext.
988     * @return a transaction representing this transaction propagation
989     * context, or null if this TPC cannot be imported.
990     */

991    public Transaction JavaDoc importTransactionPropagationContext(Object JavaDoc tpc)
992    {
993       if (tpc instanceof LocalId)
994       {
995          LocalId id = (LocalId) tpc;
996          return (Transaction JavaDoc) localIdTx.get(id);
997       }
998       else if (tpc instanceof GlobalId && globalIdsEnabled)
999       {
1000         GlobalId id = (GlobalId) tpc;
1001         Transaction JavaDoc tx = (Transaction JavaDoc) globalIdTx.get(id);
1002         if (trace)
1003         {
1004            if (tx != null)
1005               log.trace("Successfully imported transaction context " + tpc);
1006            else
1007               log.trace("Could not import transaction context " + tpc);
1008         }
1009   &nbs