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         return tx;
1010      }
1011      else if (tpc instanceof TxPropagationContext && dtmEnabled)
1012      {
1013         TxPropagationContext fullTpc = (TxPropagationContext) tpc;
1014         Transaction JavaDoc tx = importExternalTransaction(fullTpc.formatId,
1015                                                    fullTpc.globalId,
1016                                                    fullTpc.coordinator,
1017                                                    fullTpc.timeout * 1000);
1018         if (trace)
1019         {
1020            if (tx != null)
1021               log.trace("Successfully imported transaction context " + tpc);
1022            else
1023               log.trace("Could not import transaction context " + tpc);
1024         }
1025         return tx;
1026      }
1027      log.warn("Cannot import transaction propagation context: " + tpc);
1028      return null;
1029   }
1030
1031   // Implements TransactionPropagationContextFactory ---------------
1032

1033   /**
1034    * Return a TPC for the current transaction.
1035    */

1036   public Object JavaDoc getTransactionPropagationContext()
1037   {
1038      return getTransactionPropagationContext(getThreadInfo().tx);
1039   }
1040
1041   /**
1042    * Return a TPC for the argument transaction.
1043    */

1044   public Object JavaDoc getTransactionPropagationContext(Transaction JavaDoc t)
1045   {
1046      // If no transaction or unknown transaction class, return null.
1047
if (t == null)
1048         return null;
1049      if (!(t instanceof TransactionImpl))
1050      {
1051         log.warn("Cannot export transaction propagation context: " + t);
1052         return null;
1053      }
1054      
1055      TransactionImpl tx = (TransactionImpl) t;
1056         
1057      if (!dtmEnabled)
1058      {
1059         return tx.getLocalId();
1060      }
1061      else
1062      {
1063         return tx.getPropagationContext();
1064      }
1065   }
1066
1067   // Implements XATerminator ----------------------------------
1068

1069   public void registerWork(Work JavaDoc work, Xid JavaDoc xid, long timeout)
1070         throws WorkCompletedException JavaDoc
1071   {
1072      if (trace)
1073         log.trace("registering work=" + work + " xid=" + xid +
1074                   " timeout=" + timeout);
1075      try
1076      {
1077         TransactionImpl tx = importExternalTransaction(xid, timeout);
1078         tx.setWork(work);
1079      }
1080      catch (WorkCompletedException JavaDoc e)
1081      {
1082         throw e;
1083      }
1084      catch (Throwable JavaDoc t)
1085      {
1086         WorkCompletedException JavaDoc e =
1087            new WorkCompletedException JavaDoc("Error registering work", t);
1088         e.setErrorCode(WorkException.TX_RECREATE_FAILED);
1089         throw e;
1090      }
1091      if (trace)
1092         log.trace("registered work= " + work + " xid=" + xid +
1093                   " timeout=" + timeout);
1094   }
1095
1096   public void startWork(Work JavaDoc work, Xid JavaDoc xid)
1097         throws WorkCompletedException JavaDoc
1098   {
1099      if (trace)
1100         log.trace("starting work=" + work + " xid=" + xid);
1101      TransactionImpl tx = getExternalTransaction(xid);
1102      associateThread(tx);
1103      if (trace)
1104         log.trace("started work= " + work + " xid=" + xid);
1105   }
1106
1107   public void endWork(Work JavaDoc work, Xid JavaDoc xid)
1108   {
1109      if (trace)
1110         log.trace("ending work=" + work + " xid=" + xid);
1111      try
1112      {
1113         TransactionImpl tx = getExternalTransaction(xid);
1114         tx.setWork(null);
1115         disassociateThread();
1116      }
1117      catch (WorkCompletedException JavaDoc e)
1118      {
1119         log.error("Unexpected error from endWork ", e);
1120         throw new UnexpectedThrowable(e.toString());
1121      }
1122      if (trace)
1123         log.trace("ended work=" + work + " xid=" + xid);
1124   }
1125
1126   public void cancelWork(Work JavaDoc work, Xid JavaDoc xid)
1127   {
1128      if (trace)
1129         log.trace("cancling work=" + work + " xid=" + xid);
1130      try
1131      {
1132         TransactionImpl tx = getExternalTransaction(xid);
1133         tx.setWork(null);
1134      }
1135      catch (WorkCompletedException JavaDoc e)
1136      {
1137         log.error("Unexpected error from cancelWork ", e);
1138         throw new UnexpectedThrowable(e.toString());
1139      }
1140      if (trace)
1141         log.trace("cancled work=" + work + " xid=" + xid);
1142   }
1143
1144   public int prepare(Xid JavaDoc xid)
1145         throws XAException JavaDoc
1146   {
1147      if (trace)
1148         log.trace("preparing xid=" + xid);
1149      try
1150      {
1151         TransactionImpl tx = getExternalTransaction(xid);
1152         resume(tx);
1153         int result = tx.prepare(xid);
1154         if (trace)
1155            log.trace("prepared xid=" + xid + " result=" + result);
1156         return result;
1157      }
1158      catch (Throwable JavaDoc t)
1159      {
1160         JBossXAException.rethrowAsXAException("Error during prepare", t);
1161         throw new UnreachableStatementException();
1162      }
1163      finally
1164      {
1165         try
1166         {
1167            suspend();
1168         }
1169         catch (SystemException JavaDoc e)
1170         {
1171            JBossXAException.rethrowAsXAException("Error during prepare", e);
1172            throw new UnreachableStatementException();
1173         }
1174      }
1175   }
1176
1177   public void rollback(Xid JavaDoc xid)
1178         throws XAException JavaDoc
1179   {
1180      if (trace)
1181         log.trace("rolling back xid=" + xid);
1182      try
1183      {
1184         TransactionImpl tx = getExternalTransaction(xid);
1185         tx.rollback();
1186      }
1187      catch (Throwable JavaDoc t)
1188      {
1189         JBossXAException.rethrowAsXAException("Error during rollback", t);
1190      }
1191      if (trace)
1192         log.trace("rolled back xid=" + xid);
1193   }
1194
1195   public void commit(Xid JavaDoc xid, boolean onePhase)
1196         throws XAException JavaDoc
1197   {
1198      if (trace)
1199         log.trace("committing xid=" + xid + " onePhase=" + onePhase);
1200      try
1201      {
1202         TransactionImpl tx = getExternalTransaction(xid);
1203         tx.commit(onePhase);
1204      }
1205      catch (Throwable JavaDoc t)
1206      {
1207         JBossXAException.rethrowAsXAException("Error during commit", t);
1208      }
1209      if (trace)
1210         log.trace("committed xid=" + xid);
1211   }
1212
1213   public void forget(Xid JavaDoc xid)
1214         throws XAException JavaDoc
1215   {
1216      if (trace)
1217         log.trace("forgetting xid=" + xid);
1218      try
1219      {
1220         TransactionImpl tx = getExternalTransaction(xid);
1221         tx.forget();
1222      }
1223      catch (Throwable JavaDoc t)
1224      {
1225         JBossXAException.rethrowAsXAException("Error during forget", t);
1226      }
1227      if (trace)
1228         log.trace("forgot xid=" + xid);
1229   }
1230
1231   public Xid JavaDoc[] recover(int flag)
1232         throws XAException JavaDoc
1233   {
1234      List JavaDoc xidList = new ArrayList JavaDoc();
1235      Collection JavaDoc txCollection = localIdTx.values();
1236      synchronized (localIdTx)
1237      {
1238         Iterator JavaDoc i = txCollection.iterator();
1239         while (i.hasNext())
1240         {
1241            TransactionImpl tx = (TransactionImpl) i.next();
1242            if (tx.isPreparedOrHeuristicallyCompletedJCAInboundTx())
1243               xidList.add(tx.getInboundXid());
1244         }
1245      }
1246      return (Xid JavaDoc[]) xidList.toArray(new Xid JavaDoc[xidList.size()]);
1247   }
1248
1249   /**
1250    * Imports an external transaction. This method is called for foreign
1251    * transaction imported through DTM or OTS transaction propagation contexts.
1252    */

1253   public TransactionImpl importExternalTransaction(int formatId,
1254                                                    byte[] globalId,
1255                                                    Coordinator coordinator,
1256                                                    long txTimeOut)
1257   {
1258      GlobalId gid = new GlobalId(formatId, globalId);
1259      TransactionImpl tx = (TransactionImpl) globalIdTx.get(gid);
1260      if (tx != null)
1261      {
1262         if (trace)
1263            log.trace("imported existing transaction gid: " + gid +
1264                      " tx=" + tx);
1265      }
1266      else
1267      {
1268         ThreadInfo ti = getThreadInfo();
1269         long timeout = (ti.timeout == 0) ? txTimeOut : ti.timeout;
1270         tx = new TransactionImpl(gid, coordinator, timeout);
1271         localIdTx.put(tx.getLocalId(), tx);
1272         if (globalIdsEnabled)
1273            globalIdTx.put(gid, tx);
1274
1275         if (trace)
1276            log.trace("imported new transaction gid: " + gid + " tx=" + tx +
1277                      " timeout=" + timeout);
1278      }
1279      return tx;
1280   }
1281
1282   /**
1283    * Imports an external transaction. This method is called for foreign
1284    * transactions imported through the JCA transaction inflow mechanism.
1285    */

1286   TransactionImpl importExternalTransaction(Xid JavaDoc xid, long txTimeOut)
1287   {
1288      GlobalId gid = new GlobalId(xid.getFormatId(),
1289                                  xid.getGlobalTransactionId());
1290      TransactionImpl tx = (TransactionImpl) globalIdTx.get(gid);
1291      if (tx != null)
1292      {
1293         if (trace)
1294            log.trace("imported existing transaction gid: " + gid +
1295                      " tx=" + tx);
1296      }
1297      else
1298      {
1299         ThreadInfo ti = getThreadInfo();
1300         long timeout = (ti.timeout == 0) ? txTimeOut : ti.timeout;
1301         tx = new TransactionImpl(gid, xid.getBranchQualifier(), timeout);
1302         localIdTx.put(tx.getLocalId(), tx);
1303         if (globalIdsEnabled)
1304            globalIdTx.put(gid, tx);
1305
1306         if (trace)
1307            log.trace("imported new transaction gid: " + gid + " tx=" + tx +
1308                      " timeout=" + timeout);
1309      }
1310      return tx;
1311   }
1312
1313   TransactionImpl getExternalTransaction(Xid JavaDoc xid)
1314         throws WorkCompletedException JavaDoc
1315   {
1316      GlobalId gid = new GlobalId(xid);
1317      TransactionImpl tx = (TransactionImpl) globalIdTx.get(gid);
1318      if (tx == null)
1319         throw new WorkCompletedException JavaDoc("Xid not found " + xid,
1320                                          WorkException.TX_RECREATE_FAILED);
1321      return tx;
1322   }
1323
1324   /**
1325    * Recreates a locally-started transaction that does not involve other
1326    * transaction managers. This method is intended to be called at recovery
1327    * time, for recreating transactions that were in the committing state when
1328    * the server crashed. Such a transaction completed the first phase of the
1329    * 2PC protocol and logged the commit decision, but it must still send
1330    * commit messages to some or all of its <code>XAResource</code>s.
1331    *
1332    * @param localId the local id of a locally-started transaction that is in
1333    * the committing state and does not involve other transaction
1334    * managers
1335    * @param pendingXAWorkList a list of <code>org.jboss.tm.XAWork</code>
1336    * instances containing one element for each
1337    * <code>XAResource</code> that is enlisted with the transaction
1338    * and is still in the prepared state
1339    * @param completionHandler the
1340    * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
1341    * notifed when the second phase of the 2PC completes
1342    * @param heurData either null or a <code>LogRecord.HeurData</code> instance
1343    * contaning information on a locally-detected heuristic hazard.
1344    */

1345   public void recreateTransaction(long localId,
1346                                   List JavaDoc pendingXAWorkList,
1347                                   TxCompletionHandler completionHandler,
1348                                   LogRecord.HeurData heurData)
1349   {
1350      LocalId localIdObject = new LocalId(localId);
1351      TransactionImpl tx = (TransactionImpl) localIdTx.get(localIdObject);
1352      if (tx != null)
1353      {
1354         if (trace)
1355            log.trace("recreateTransaction called for existing transaction, " +
1356                      "localId=" + localId + ", tx=" + tx,
1357                      new Throwable JavaDoc("[Stack trace]"));
1358      }
1359      else
1360      {
1361         tx = new TransactionImpl(localId,
1362                                  pendingXAWorkList,
1363                                  completionHandler,
1364                                  heurData);
1365         localIdTx.put(tx.getLocalId(), tx);
1366         if (globalIdsEnabled)
1367            globalIdTx.put(tx.getGlobalId(), tx);
1368
1369         if (trace)
1370            log.trace("recreated transaction with localId=" + localId +
1371                      ", tx=" + tx +
1372                      ", status=" + TxUtils.getStatusAsString(tx.getStatus()));
1373      }
1374   }
1375
1376   /**
1377    * Recreates a locally-started transaction that involves other transaction
1378    * managers. Involving other transaction managers means that there are
1379    * remote <code>Resource</code>s enlisted with the transaction. This method
1380    * is intended to be called at recovery time, for recreating transactions
1381    * that were in the committing state when the server crashed. Such a
1382    * transaction completed the first phase of the 2PC protocol and logged the
1383    * commit decision, but it must still send commit messages to some or all of
1384    * its resources (<code>XAResource</code>s and remote
1385    * <code>Resource</code>s).
1386    *
1387    * @param localId the local id of a locally-started transaction that is in
1388    * the committing state and involves other transaction managers
1389    * @param pendingXAWorkList a list of <code>org.jboss.tm.XAWork</code>
1390    * instances containing one element for each
1391    * <code>XAResource</code> that is enlisted with the transaction
1392    * and is still in the prepared state
1393    * @param resources an array with stringfied references for the remote
1394    * <code>Resource</code>s enlisted with the transaction
1395    * @param completionHandler the
1396    * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
1397    * notifed when the second phase of the 2PC completes
1398    * @param heurData either null or a <code>LogRecord.HeurData</code> instance
1399    * contaning information on a locally-detected heuristic hazard.
1400    */

1401   public void recreateTransaction(long localId,
1402                                   List JavaDoc pendingXAWorkList,
1403                                   String JavaDoc[] resources,
1404                                   TxCompletionHandler completionHandler,
1405                                   LogRecord.HeurData heurData)
1406   {
1407      LocalId localIdObject = new LocalId(localId);
1408      TransactionImpl tx = (TransactionImpl) localIdTx.get(localIdObject);
1409      if (tx != null)
1410      {
1411         if (trace)
1412            log.trace("recreateTransaction called for existing transaction, " +
1413                      "localId=" + localId + ", tx=" + tx,
1414                      new Throwable JavaDoc("[Stack trace]"));
1415      }
1416      else
1417      {
1418         tx = new TransactionImpl(localId,
1419                                  pendingXAWorkList,
1420                                  resources,
1421                                  completionHandler,
1422                                  heurData);
1423         localIdTx.put(tx.getLocalId(), tx);
1424         if (globalIdsEnabled)
1425            globalIdTx.put(tx.getGlobalId(), tx);
1426
1427         if (trace)
1428            log.trace("recreated transaction with localId=" + localId +
1429                      ", tx=" + tx +
1430                      ", status=" + TxUtils.getStatusAsString(tx.getStatus()));
1431      }
1432   }
1433   
1434   /**
1435    * Recreates a foreign transaction that entered this virtual machine in a
1436    * transaction context propagated along with a remote method invocation.
1437    * This method is intended to be called at recovery time, for recreating
1438    * transactions that were in the prepared state when the server crashed.
1439    *
1440    * @param localId the local id of a foreign transaction that entered this
1441    * virtual machine in a transaction propagation context and is
1442    * propagated along with a remote method invocation and is in
1443    * the prepared state
1444    * @param inboundFormatId format id part of the foreign transaction
1445    * identifier that entered this virtual machine
1446    * @param globalTransactionId global id part of the foreign transaction
1447    * identifier that entered this virtual machine
1448    * @param recoveryCoord an stringfied reference to the transaction branch's
1449    * <code>RecovertyCoordinator</code>
1450    * @param pendingXAWorkList a list of <code>org.jboss.tm.XAWork</code>
1451    * instances containing one element for each
1452    * <code>XAResource</code> enlisted with the transaction
1453    * @param resources an array with stringfied references for the remote
1454    * <code>Resource</code>s enlisted with the transaction
1455    * @param completionHandler the
1456    * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
1457    * notifed when the second phase of the 2PC completes
1458    * @param heurData either null or a <code>LogRecord.HeurData</code> instance
1459    * contaning information on a locally-detected heuristic hazard.
1460    */

1461   public void recreateTransaction(long localId,
1462                                   int inboundFormatId,
1463                                   byte[] globalTransactionId,
1464                                   String JavaDoc recoveryCoord,
1465                                   List JavaDoc pendingXAWorkList,
1466                                   String JavaDoc[] resources,
1467                                   TxCompletionHandler completionHandler,
1468                                   LogRecord.HeurData heurData)
1469   {
1470      LocalId localIdObject = new LocalId(localId);
1471      TransactionImpl tx = (TransactionImpl) localIdTx.get(localIdObject);
1472      if (tx != null)
1473      {
1474         if (trace)
1475            log.trace("recreateTransaction called for existing transaction, " +
1476                      "localId=" + localId + ", tx=" + tx,
1477                      new Throwable JavaDoc("[Stack trace]"));
1478      }
1479      else
1480      {
1481         tx = new TransactionImpl(localId,
1482                                  inboundFormatId,
1483                                  globalTransactionId,
1484                                  recoveryCoord,
1485                                  pendingXAWorkList,
1486                                  resources,
1487                                  completionHandler,
1488                                  heurData);
1489         localIdTx.put(tx.getLocalId(), tx);
1490         if (globalIdsEnabled)
1491            globalIdTx.put(tx.getGlobalId(), tx);
1492
1493         if (trace)
1494            log.trace("recreated transaction with localId=" + localId +
1495                      " tx=" + tx +
1496                      ", status=" + TxUtils.getStatusAsString(tx.getStatus()));
1497      }
1498   }
1499   
1500   /**
1501    * Recreates a foreign transaction that entered this virtual machine through
1502    * JCA transaction inflow. This method is intended to be called at recovery
1503    * time, for recreating transactions that were in the prepared state when
1504    * the server crashed.
1505    *
1506    * @param localId the local id of a foreign transaction that entered this
1507    * virtual machine in a transaction propagation context and is
1508    * propagated along with a remote method invocation and is in
1509    * the prepared state
1510    * @param inboundFormatId format id part of the foreign <code>Xid</code>
1511    * @param globalTransactionId global id part of the foreign <code>Xid</code>
1512    * @param inboundBranchQualifier the branch qualifier part of the foreign
1513    * <code>Xid</code>
1514    * @param pendingXAWorkList a list of <code>org.jboss.tm.XAWork</code>
1515    * instances containing one element for each
1516    * <code>XAResource</code> enlisted with the transaction
1517    * @param resources an array with stringfied references for the remote
1518    * <code>Resource</code>s enlisted with the transaction
1519    * @param completionHandler the
1520    * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
1521    * notifed when the second phase of the 2PC completes
1522    * @param heurData either null or a <code>LogRecord.HeurData</code> instance
1523    * contaning information on a locally-detected heuristic hazard.
1524    */

1525   public void recreateTransaction(long localId,
1526                                   int inboundFormatId,
1527                                   byte[] globalTransactionId,
1528                                   byte[] inboundBranchQualifier,
1529                                   List JavaDoc pendingXAWorkList,
1530                                   String JavaDoc[] resources,
1531                                   TxCompletionHandler completionHandler,
1532                                   LogRecord.HeurData heurData)
1533   {
1534      LocalId localIdObject = new LocalId(localId);
1535      TransactionImpl tx = (TransactionImpl) localIdTx.get(localIdObject);
1536      if (tx != null)
1537      {
1538         if (trace)
1539            log.trace("recreateTransaction called for existing transaction, " +
1540                      "localId=" + localId + ", tx=" + tx,
1541                      new Throwable JavaDoc("[Stack trace]"));
1542      }
1543      else
1544      {
1545         tx = new TransactionImpl(localId,
1546                                  inboundFormatId,
1547                                  globalTransactionId,
1548                                  inboundBranchQualifier,
1549                                  pendingXAWorkList,
1550                                  resources,
1551                                  completionHandler,
1552                                  heurData);
1553         localIdTx.put(tx.getLocalId(), tx);
1554         if (globalIdsEnabled)
1555            globalIdTx.put(tx.getGlobalId(), tx);
1556
1557         if (trace)
1558            log.trace("recreated transaction with localId=" + localId +
1559                      ", tx=" + tx +
1560                      ", status=" + TxUtils.getStatusAsString(tx.getStatus()));
1561      }
1562   }
1563
1564   /**
1565    * Recreates a transaction that is in a heuristically completed state
1566    * (either committed or rolledback). This method is intended to be called
1567    * at recovery time, for recreating heuristically completed transactions
1568    * that were not yet forgotten when the server crashed.
1569    *
1570    * @param heurData an instance of <code>LogRecord.HeurData</code> with
1571    * information on the heuristically completed transaction
1572    * @param xaResourcesWithHeuristics a list of
1573    * <code>org.jboss.tm.XAWork</code>
1574    * instances containing one element for each
1575    * <code>XAResource</code> that is in a a heuristic status
1576    * @param completionHandler the
1577    * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
1578    * notifed when the second phase of the 2PC completes.
1579    */

1580   public void recreateTransaction(LogRecord.HeurData heurData,
1581                                   List JavaDoc xaResourcesWithHeuristics,
1582                                   TxCompletionHandler completionHandler)
1583   {
1584      LocalId localIdObject = new LocalId(heurData.localTransactionId);
1585      TransactionImpl tx = (TransactionImpl) localIdTx.get(localIdObject);
1586      if (tx != null)
1587      {
1588         if (trace)
1589            log.trace("recreateTransaction called for existing transaction, " +
1590                      "localId=" + heurData.localTransactionId + ", tx=" + tx +
1591                      ", status=" + TxUtils.getStatusAsString(tx.getStatus()) +
1592                      ", heuristicStatus=" + TxUtils.getXAErrorCodeAsString(
1593                                                 heurData.heuristicStatusCode),
1594                      new Throwable JavaDoc("[Stack trace]"));
1595      }
1596      else
1597      {
1598         tx = new TransactionImpl(heurData,
1599                                  xaResourcesWithHeuristics,
1600                                  completionHandler);
1601         localIdTx.put(tx.getLocalId(), tx);
1602         if (globalIdsEnabled)
1603            globalIdTx.put(tx.getGlobalId(), tx);
1604
1605         if (trace)
1606            log.trace("recreated transaction with localId=" +
1607                      heurData.localTransactionId + ", tx=" + tx +
1608                      ", status=" + TxUtils.getStatusAsString(tx.getStatus()) +
1609                      ", heuristicStatus=" + TxUtils.getXAErrorCodeAsString(
1610                                                 heurData.heuristicStatusCode));
1611
1612         //if (!tx.isImported())
1613
//{
1614
// tx.forget();
1615
//}
1616
}
1617   }
1618   
1619   // Implements TransactionLocalDelegate ----------------------
1620

1621   public void lock(TransactionLocal local, Transaction JavaDoc tx) throws InterruptedException JavaDoc
1622   {
1623      TransactionImpl tximpl = (TransactionImpl) tx;
1624      tximpl.lock();
1625   }
1626
1627   public void unlock(TransactionLocal local, Transaction JavaDoc tx)
1628   {
1629      TransactionImpl tximpl = (TransactionImpl) tx;
1630      tximpl.unlock();
1631   }
1632
1633   public Object JavaDoc getValue(TransactionLocal local, Transaction JavaDoc tx)
1634   {
1635      TransactionImpl tximpl = (TransactionImpl) tx;
1636      return tximpl.getTransactionLocalValue(local);
1637   }
1638
1639   public void storeValue(TransactionLocal local, Transaction JavaDoc tx, Object JavaDoc value)
1640   {
1641      TransactionImpl tximpl = (TransactionImpl) tx;
1642      tximpl.putTransactionLocalValue(local, value);
1643   }
1644
1645   public boolean containsValue(TransactionLocal local, Transaction JavaDoc tx)
1646   {
1647      TransactionImpl tximpl = (TransactionImpl) tx;
1648      return tximpl.containsTransactionLocal(local);
1649   }
1650
1651   // Implements StringRemoteRefConverter ----------------------------
1652

1653   public Resource stringToResource(String JavaDoc strResource)
1654   {
1655      return TransactionImpl.stringToResource(strResource);
1656   }
1657
1658   public RecoveryCoordinator stringToRecoveryCoordinator(
1659                                                   String JavaDoc strRecCoordinator)
1660   {
1661      return TransactionImpl.stringToRecoveryCoordinator(strRecCoordinator);
1662   }
1663
1664   public String JavaDoc resourceToString(Resource res)
1665   {
1666      return TransactionImpl.resourceToString(res);
1667   }
1668
1669   public String JavaDoc recoveryCoordinatorToString(RecoveryCoordinator recoveryCoord)
1670   {
1671      return TransactionImpl.recoveryCoordinatorToString(recoveryCoord);
1672   }
1673
1674   // Attribute getters and setters ----------------------------------
1675

1676   /**
1677    * Setter for attribute <code>dtmEnabled</code>.
1678    */

1679   public void setDTMEnabled(boolean newValue)
1680   {
1681      if (newValue == true && !globalIdsEnabled)
1682      {
1683         // DTM requires global ids
1684
setGlobalIdsEnabled(newValue);
1685      }
1686      dtmEnabled = newValue;
1687   }
1688
1689   /**
1690    * Setter for the DTM <code>CoordinatorFactory</code>.
1691    */

1692   public void setDTMCoordinatorFactory(
1693         CoordinatorFactory dtmCoordinatorFactory)
1694   {
1695      TransactionImpl.setDTMCoordinatorFactory(dtmCoordinatorFactory);
1696   }
1697
1698   /**
1699    * Setter for the DTM <code>ResourceFactory</code>.
1700    */

1701   public void setDTMResourceFactory(ResourceFactory dtmResourceFactory)
1702   {
1703      TransactionImpl.setDTMResourceFactory(dtmResourceFactory);
1704   }
1705
1706   /**
1707    * Setter for the OTS <code>ResourceFactory</code>.
1708    */

1709   public void setOTSResourceFactory(ResourceFactory otsResourceFactory)
1710   {
1711      TransactionImpl.setOTSResourceFactory(otsResourceFactory);
1712   }
1713
1714   /**
1715    * Setter for the <code>OTSContextFactory</code>.
1716    */

1717   public void setOTSContextFactory(OTSContextFactory otsContextFactory)
1718   {
1719      TransactionImpl.setOTSContextFactory(otsContextFactory);
1720   }
1721
1722   /**
1723    * Setter for the <code>interpositionEnabled</code> flag.
1724    */

1725   public void setInterpositionEnabled(boolean newValue)
1726   {
1727      TransactionImpl.setInterpositionEnabled(newValue);
1728   }
1729
1730   /**
1731    * Getter for the <code>interpositionEnabled</code> flag.
1732    */

1733   public boolean getInterpositionEnabled()
1734   {
1735      return TransactionImpl.getInterpositionEnabled();
1736   }
1737   
1738   public void setDTMStringRemoteRefConverter(
1739                           StringRemoteRefConverter otsStrRemoteRefConverter)
1740   {
1741      TransactionImpl.setDTMStrRemoteRefConverter(otsStrRemoteRefConverter);
1742   }
1743
1744   public void setOTSStringRemoteRefConverter(
1745                           StringRemoteRefConverter otsStrRemoteRefConverter)
1746   {
1747      TransactionImpl.setOTSStrRemoteRefConverter(otsStrRemoteRefConverter);
1748   }
1749
1750   // Package protected ---------------------------------------------
1751

1752   /**
1753    * Release the given TransactionImpl.
1754    */

1755   void releaseTransactionImpl(TransactionImpl tx)
1756   {
1757      localIdTx.remove(tx.getLocalId());
1758      if (globalIdsEnabled)
1759         globalIdTx.remove(tx.getGlobalId());
1760   }
1761
1762   /**
1763    * Increment the commit count
1764    */

1765   void incCommitCount()
1766   {
1767      ++commitCount;
1768   }
1769
1770   /**
1771    * Increment the rollback count
1772    */

1773   void incRollbackCount()
1774   {
1775      ++rollbackCount;
1776   }
1777
1778   // Protected -----------------------------------------------------
1779

1780   // Private -------------------------------------------------------
1781

1782   /**
1783    * This keeps track of the thread association with transactions
1784    * and timeout values.
1785    * In some cases terminated transactions may not be cleared here.
1786    */

1787   private ThreadLocal JavaDoc threadTx = new ThreadLocal JavaDoc();
1788
1789   /**
1790    * This map contains the active transactions as values.
1791    * The keys are the <code>LocalId</code>s of the transactions.
1792    */

1793   private Map JavaDoc localIdTx = Collections.synchronizedMap(new HashMap JavaDoc());
1794
1795
1796   /**
1797    * If <code>globalIdsEnabled</code> is true, this map associates
1798    * <code>GlobalId</code>s to active transactions.
1799    */

1800   private Map JavaDoc globalIdTx = Collections.synchronizedMap(new HashMap JavaDoc());
1801
1802
1803   /**
1804    * Return the ThreadInfo for the calling thread, and create if not
1805    * found.
1806    */

1807   private ThreadInfo getThreadInfo()
1808   {
1809      ThreadInfo ret = (ThreadInfo) threadTx.get();
1810
1811      if (ret == null)
1812      {
1813         ret = new ThreadInfo();
1814         ret.timeout = timeOut;
1815         threadTx.set(ret);
1816      }
1817
1818      return ret;
1819   }
1820
1821   // Inner classes -------------------------------------------------
1822

1823   /**
1824    * A simple aggregate of a thread-associated timeout value
1825    * and a thread-associated transaction.
1826    */

1827   static class ThreadInfo
1828   {
1829      long timeout;
1830      TransactionImpl tx;
1831   }
1832
1833}
1834
Popular Tags