KickJava   Java API By Example, From Geeks To Geeks.

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


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.lang.reflect.Proxy JavaDoc;
25 import java.rmi.NoSuchObjectException JavaDoc;
26 import java.rmi.RemoteException JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Set JavaDoc;
35
36 import javax.resource.spi.work.Work JavaDoc;
37 import javax.resource.spi.work.WorkCompletedException JavaDoc;
38 import javax.resource.spi.work.WorkException JavaDoc;
39 import javax.transaction.HeuristicCommitException JavaDoc;
40 import javax.transaction.HeuristicMixedException JavaDoc;
41 import javax.transaction.HeuristicRollbackException JavaDoc;
42 import javax.transaction.RollbackException JavaDoc;
43 import javax.transaction.Status JavaDoc;
44 import javax.transaction.Synchronization JavaDoc;
45 import javax.transaction.SystemException JavaDoc;
46 import javax.transaction.Transaction JavaDoc;
47 import javax.transaction.TransactionRolledbackException JavaDoc;
48 import javax.transaction.xa.XAException JavaDoc;
49 import javax.transaction.xa.XAResource JavaDoc;
50 import javax.transaction.xa.Xid JavaDoc;
51
52 import org.jboss.logging.Logger;
53 import org.jboss.tm.integrity.TransactionIntegrity;
54 import org.jboss.tm.recovery.HeuristicStatus;
55 import org.jboss.tm.recovery.LogRecord;
56 import org.jboss.tm.recovery.RecoveryLogger;
57 import org.jboss.tm.recovery.RecoveryTestingException;
58 import org.jboss.tm.recovery.TxCompletionHandler;
59 import org.jboss.tm.recovery.XAResourceAccess;
60 import org.jboss.tm.recovery.XAWork;
61 import org.jboss.tm.remoting.interfaces.Coordinator;
62 import org.jboss.tm.remoting.interfaces.HeuristicHazardException;
63 import org.jboss.tm.remoting.interfaces.RecoveryCoordinator;
64 import org.jboss.tm.remoting.interfaces.Resource;
65 import org.jboss.tm.remoting.interfaces.TransactionAlreadyPreparedException;
66 import org.jboss.tm.remoting.interfaces.TransactionInactiveException;
67 import org.jboss.tm.remoting.interfaces.TransactionNotPreparedException;
68 import org.jboss.tm.remoting.interfaces.TxPropagationContext;
69 import org.jboss.tm.remoting.interfaces.Vote;
70 import org.jboss.util.timeout.Timeout;
71 import org.jboss.util.timeout.TimeoutFactory;
72 import org.jboss.util.timeout.TimeoutTarget;
73
74 /**
75  * Our <code>Transaction</code> implementation.
76  *
77  * @author <a HREF="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>
78  * @author <a HREF="mailto:marc.fleury@telkel.com">Marc Fleury</a>
79  * @author <a HREF="mailto:osh@sparre.dk">Ole Husgaard</a>
80  * @author <a HREF="mailto:toby.allsopp@peace.com">Toby Allsopp</a>
81  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
82  * @author <a HREF="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
83  * @author <a HREF="mailto:bill@jboss.org">Bill Burke</a>
84  * @author <a HREF="mailto:adrian@jboss.com">Adrian Brock</a>
85  * @author <a HREF="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
86  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
87  * @version $Revision: 43490 $
88  * @see TxManager
89  */

90 public class TransactionImpl
91         implements Transaction JavaDoc, TimeoutTarget
92 {
93    // Constants -----------------------------------------------------
94

95    /**
96     * Code meaning "no heuristics seen",
97     * must not be XAException.XA_HEURxxx
98     */

99    private static final int HEUR_NONE = 0;
100
101    /**
102     * Code meaning "heuristics seen, but no additional info is available",
103     * must not be XAException.XA_HEURxxx
104     */

105    private static final int HEUR_UNKNOWN = XAException.XA_RETRY;
106
107    // Resource states
108
private final static int RS_NEW = 0; // not yet enlisted
109
private final static int RS_ENLISTED = 1; // enlisted
110
private final static int RS_SUSPENDED = 2; // suspended
111
private final static int RS_ENDED = 3; // not associated
112
private final static int RS_VOTE_READONLY = 4; // voted read-only
113
private final static int RS_VOTE_OK = 5; // voted ok
114
private final static int RS_FORGOT = 6; // RM has forgotten
115
private final static int RS_COMMITTED = 7; // committed
116
private final static int RS_ROLLEDBACK = 8; // rolledback
117
private final static int RS_HEUR_OUTCOME = 8; // had an heuristic outcome
118
private final static int RS_ERROR = 9; // error condition (no use retrying)
119

120    // Attributes ----------------------------------------------------
121

122    /**
123     * True if trace messages should be logged.
124     */

125    private boolean trace = log.isTraceEnabled();
126
127    /**
128     * The ID of this transaction.
129     */

130    private XidImpl xid;
131
132    private HashSet JavaDoc threads = new HashSet JavaDoc(1);
133
134    private Map JavaDoc transactionLocalMap = Collections.synchronizedMap(new HashMap JavaDoc());
135
136    private Throwable JavaDoc cause;
137
138    /**
139     * True for a foreign transaction that has been imported either through an
140     * DTM/OTS transaction propagation context or via JCA transaction inflow;
141     * false for a locally started transaction.
142     */

143    private final boolean foreignTx;
144
145    /**
146     * This transaction's parent coordinator, or null if this transaction does
147     * not have a parent coordinator. A transaction with no parent coodinator
148     * is either a (locally started) root transaction or a foreign transaction
149     * that has been imported via JCA transaction inflow.
150     */

151    private Coordinator parentCoordinator = null;
152
153    /**
154     * The resource registered by transaction with the parent coordinator.
155     */

156    private Resource JavaDoc registeredResource = null;
157    
158    /**
159     * This transaction's recovery coordinator, or null this transaction did not
160     * register itself as a remote resource with the parent coordinator.
161     */

162    private RecoveryCoordinator recoveryCoordinator = null;
163    
164    /**
165     * The inbound branch qualifier, if this is a foreign transaction that has
166     * been imported via JCA transaction inflow, or null otherwise.
167     */

168    private byte[] inboundBranchQualifier = null;
169
170    /**
171     * The synchronizations to call back.
172     */

173    private Synchronization JavaDoc[] sync = new Synchronization JavaDoc[3];
174
175    /**
176     * Size of allocated synchronization array.
177     */

178    private int syncAllocSize = 3;
179
180    /**
181     * Count of synchronizations for this transaction.
182     */

183    private int syncCount = 0;
184
185    /**
186     * A list of the XAResources that have participated in this transaction.
187     */

188    private ArrayList JavaDoc xaResources = new ArrayList JavaDoc(3);
189
190    /**
191     * A list of the remote resources that have participated in this transaction.
192     */

193    private ArrayList JavaDoc remoteResources = new ArrayList JavaDoc(3);
194
195    /**
196     * The XAResource used in the last resource gambit
197     */

198    private EnlistedXAResource lastResource;
199
200    /**
201     * Flags that it is too late to enlist new resources.
202     */

203    private boolean resourcesEnded = false;
204
205    /**
206     * Last branch id used.
207     */

208    private long lastBranchId = 0;
209
210    /**
211     * Status of this transaction.
212     */

213    private int status;
214
215    /**
216     * The heuristics status of this transaction.
217     */

218    private int heuristicCode = HEUR_NONE;
219
220    /**
221     * The time when this transaction was started.
222     */

223    private long start;
224
225    /**
226     * The timeout handle for this transaction.
227     */

228    private Timeout timeout;
229
230    /**
231     * Timeout in millisecs
232     */

233    private long timeoutPeriod;
234
235    /**
236     * Mutex for thread-safety. This should only be changed in the
237     * <code>lock()</code> and <code>unlock()</code> methods.
238     */

239    private Thread JavaDoc locked = null;
240    
241    /**
242     * The lock depth
243     */

244    private int lockDepth = 0;
245
246    /**
247     * Any current work associated with the transaction
248     */

249    private Work JavaDoc work;
250
251    /**
252     * Flags that we are done with this transaction and that it can be reused.
253     */

254    private boolean done = false;
255
256    /**
257     * This transaction's DTM propagation context.
258     */

259    private TxPropagationContext dtmPropagationContext = null;
260
261    /**
262     * This transaction's OTS propagation context.
263     */

264    private Object JavaDoc otsPropagationContext = null;
265
266    /**
267     * This transaction's TxCompletionHandler.
268     */

269    private TxCompletionHandler completionHandler = null;
270    
271    /**
272     * Number of XA resources that reported transient problems.
273     */

274    private int xaResourcesToRetry = 0;
275    
276    /**
277     * Number of remote resources that reported transient problems.
278     */

279    private int remoteResourcesToRetry = 0;
280    
281    /**
282     * Timeout before calling <code>replayCompletion</code> on the recovery
283     * the coordinator when waiting for the coordinator in the prepared state.
284     */

285    private Timeout preparedTimeout = null;
286    
287    /**
288     * Timeout before retrying commit or rollback calls on XA resources that
289     * reported transient problems.
290     */

291    private Timeout xaRetryTimeout = null;
292    
293    /**
294     * List of <code>EnlistedXAResource</code> instances with heuristic
295     * decisions.
296     */

297    private List JavaDoc xaResourcesWithHeuristicDecisions = null;
298    
299    /**
300     * List of <code>EnlistedRemoteResource</code> instances with heuristic
301     * decisions.
302     */

303    private List JavaDoc remoteResourcesWithHeuristicDecisions = null;
304    
305    /**
306     * Counts how many resources were committed.
307     */

308    private int committedResources = 0;
309    
310    /**
311     * Counts how many resources were rolled back.
312     */

313    private int rolledbackResources = 0;
314    
315    /**
316     * True if this <code>TransactionImpl</code> could not reach a resource
317     * during the second phase of 2PC.
318     */

319    private boolean heuristicHazard = false;
320       
321    // Static --------------------------------------------------------
322

323    /**
324     * Class logger, we don't want a new logger with every transaction.
325     */

326    private static Logger log = Logger.getLogger(TransactionImpl.class);
327
328    /**
329     * Factory for Xid instances of specified class.
330     * This is set from the <code>TransactionManagerService</code>
331     * MBean.
332     */

333    static XidFactoryBase xidFactory;
334
335    static XAExceptionFormatter xaExceptionFormatter;
336
337    /** The timeout factory */
338    static TimeoutFactory timeoutFactory = TimeoutFactory.getSingleton();
339    
340    /**
341     * CoordinatorFactory that creates remote references to DTM coordinators,
342     * or null if the DTM is not employed.
343     */

344    private static CoordinatorFactory dtmCoordinatorFactory = null;
345
346    /**
347     * ResourceFactory that creates remote references to DTM resources,
348     * or null if the DTM is not employed.
349     */

350    private static ResourceFactory dtmResourceFactory = null;
351
352    /**
353     * ResourceFactory that creates remote references to OTS resources,
354     * or null if OTS is not employed.
355     */

356    private static ResourceFactory otsResourceFactory = null;
357
358    /**
359     * Factory that creates OTS transaction propagation contexts,
360     * or null if OTS is not employed.
361     */

362    private static OTSContextFactory otsContextFactory = null;
363
364    /**
365     * True if coordinator interposition is enabled.
366     */

367    private static boolean interpositionEnabled = false;
368
369    /**
370     * Object that converts between strings and remote references for
371     * DTM objects, or null if DTM is not employed.
372     */

373    private static StringRemoteRefConverter dtmStrRemoteRefConverter = null;
374    
375    /**
376     * Object that converts between strings and remote references for
377     * OTS objects, or null if OTS is not employed.
378     */

379    private static StringRemoteRefConverter otsStrRemoteRefConverter = null;
380    
381    /**
382     * This static code is only present for testing purposes so a
383     * tm can be usable without a lot of setup.
384     */

385    public static XidFactoryBase defaultXidFactory()
386    {
387       if (xidFactory == null)
388       {
389          XidFactoryImpl impl = new XidFactoryImpl();
390          impl.start();
391          xidFactory = impl;
392       }
393       return xidFactory;
394    }
395
396    /**
397     * Setter for <code>dtmCoordinatorFactory</code>.
398     */

399    static void setDTMCoordinatorFactory(CoordinatorFactory dtmCoordinatorFactory)
400    {
401       TransactionImpl.dtmCoordinatorFactory = dtmCoordinatorFactory;
402    }
403
404    /**
405     * Setter for <code>dtmResourceFactory</code>.
406     */

407    static void setDTMResourceFactory(ResourceFactory dtmResourceFactory)
408    {
409       TransactionImpl.dtmResourceFactory = dtmResourceFactory;
410    }
411
412    /**
413     * Setter for <code>otsResourceFactory</code>.
414     */

415    static void setOTSResourceFactory(ResourceFactory otsResourceFactory)
416    {
417       TransactionImpl.otsResourceFactory = otsResourceFactory;
418    }
419
420    /**
421     * Setter for <code>otsContextFactory</code>.
422     */

423    static void setOTSContextFactory(OTSContextFactory otsContextFactory)
424    {
425       TransactionImpl.otsContextFactory = otsContextFactory;
426    }
427
428    /**
429     * Setter for <code>interpositionEnabled</code>.
430     */

431    static void setInterpositionEnabled(boolean interpositionEnabled)
432    {
433       TransactionImpl.interpositionEnabled = interpositionEnabled;
434    }
435
436    /**
437     * Getter for <code>interpositionEnabled</code>.
438     */

439    static boolean getInterpositionEnabled()
440    {
441       return TransactionImpl.interpositionEnabled;
442    }
443
444    /**
445     * Setter for <code>dtmStrRemoteRefConverter</code>.
446     */

447    static void setDTMStrRemoteRefConverter(
448          StringRemoteRefConverter dtmStrRemoteRefConverter)
449    {
450       TransactionImpl.dtmStrRemoteRefConverter = dtmStrRemoteRefConverter;
451    }
452
453    /**
454     * Setter for <code>otsStrRemoteRefConverter</code>.
455     */

456    static void setOTSStrRemoteRefConverter(
457          StringRemoteRefConverter otsStrRemoteRefConverter)
458    {
459       TransactionImpl.otsStrRemoteRefConverter = otsStrRemoteRefConverter;
460    }
461
462    /**
463     * Converts a stringfied reference to a remote resource back to a remote
464     * reference.
465     *
466     * @param strResource a stringfied reference to a remote resource
467     * @return a remote reference to the resource.
468     */

469    static Resource JavaDoc stringToResource(String JavaDoc strResource)
470    {
471       if (strResource.startsWith("IOR:"))
472       {
473          if (otsStrRemoteRefConverter != null)
474             return otsStrRemoteRefConverter.stringToResource(strResource);
475          else
476             throw new IllegalArgumentException JavaDoc();
477       }
478       else
479       {
480          if (dtmStrRemoteRefConverter != null)
481             return dtmStrRemoteRefConverter.stringToResource(strResource);
482          else
483             throw new IllegalArgumentException JavaDoc();
484       }
485    }
486
487    /**
488     * Converts a stringfied reference to a remote recovery coordinator back
489     * to a remote reference.
490     *
491     * @param strRecCoordinator a stringfied reference to a remote recovery
492     * coordinator
493     * @return a remote reference to the recovery coordinator.
494     */

495    static RecoveryCoordinator stringToRecoveryCoordinator(
496                                                    String JavaDoc strRecCoordinator)
497    {
498       if (strRecCoordinator.startsWith("IOR:"))
499       {
500          if (otsStrRemoteRefConverter != null)
501             return otsStrRemoteRefConverter.stringToRecoveryCoordinator(
502                                                             strRecCoordinator);
503          else
504             throw new IllegalArgumentException JavaDoc();
505       }
506       else
507       {
508          if (dtmStrRemoteRefConverter != null)
509             return dtmStrRemoteRefConverter.stringToRecoveryCoordinator(
510                                                             strRecCoordinator);
511          else
512             throw new IllegalArgumentException JavaDoc();
513       }
514    }
515
516    /**
517     * Takes a remote reference to a resource and converts it to a string.
518     *
519     * @param res a remote reference to a resource
520     * @return a string that represents the remote resource.
521     */

522    static String JavaDoc resourceToString(Resource JavaDoc res)
523    {
524       if (Proxy.isProxyClass(res.getClass()))
525       {
526          if (dtmStrRemoteRefConverter != null)
527             return dtmStrRemoteRefConverter.resourceToString(res);
528          else
529             throw new IllegalArgumentException JavaDoc();
530       }
531       else
532       {
533          if (otsStrRemoteRefConverter != null)
534             return otsStrRemoteRefConverter.resourceToString(res);
535          else
536             throw new IllegalArgumentException JavaDoc();
537       }
538    }
539
540    /**
541     * Takes a remote reference to a recovery coordinator and converts it to a
542     * string.
543     *
544     * @param recoveryCoord a remote reference to a recovery coordinator
545     * @return a string that represents the remote recovery coordinator.
546     */

547    static String JavaDoc recoveryCoordinatorToString(RecoveryCoordinator recoveryCoord)
548    {
549       if (Proxy.isProxyClass(recoveryCoord.getClass()))
550       {
551          if (dtmStrRemoteRefConverter != null)
552             return dtmStrRemoteRefConverter.recoveryCoordinatorToString(
553                                                                recoveryCoord);
554          else
555             throw new IllegalArgumentException JavaDoc();
556       }
557       else
558       {
559          if (otsStrRemoteRefConverter != null)
560             return otsStrRemoteRefConverter.recoveryCoordinatorToString(
561                                                                recoveryCoord);
562          else
563             throw new IllegalArgumentException JavaDoc();
564       }
565    }
566    
567    // Constructors --------------------------------------------------
568

569    /**
570     * Constructor for transactions started locally.
571     */

572    TransactionImpl(long timeout)
573    {
574       foreignTx = false;
575       xid = xidFactory.newXid();
576
577       status = Status.STATUS_ACTIVE;
578
579       start = System.currentTimeMillis();
580       this.timeout = timeoutFactory.createTimeout(start + timeout, this);
581       this.timeoutPeriod = timeout;
582       if (trace)
583          log.trace("Created new instance for tx=" + toString());
584    }
585
586    /**
587     * Constructor for foreign transactions imported through DTM/OTS transaction
588     * propagation contexts.
589     */

590    TransactionImpl(GlobalId gid, Coordinator parentCoordinator, long timeout)
591    {
592       foreignTx = true;
593       xid = xidFactory.newBranch(gid);
594
595       this.parentCoordinator = parentCoordinator;
596
597       status = Status.STATUS_ACTIVE;
598
599       start = System.currentTimeMillis();
600       this.timeout = timeoutFactory.createTimeout(start + timeout, this);
601       this.timeoutPeriod = timeout;
602       if (trace)
603          log.trace("Created new instance for tx=" + toString());
604    }
605
606    /**
607     * Constructor for foreign transactions imported through the JCA transaction
608     * inflow mechanism.
609     */

610    TransactionImpl(GlobalId gid, byte[] inboundBranchQualifier, long timeout)
611    {
612       foreignTx = true;
613       xid = xidFactory.newBranch(gid);
614
615       this.inboundBranchQualifier = inboundBranchQualifier;
616
617       status = Status.STATUS_ACTIVE;
618
619       start = System.currentTimeMillis();
620       this.timeout = timeoutFactory.createTimeout(start + timeout, this);
621       this.timeoutPeriod = timeout;
622       if (trace)
623          log.trace("Created new instance for tx=" + toString());
624       
625    }
626    
627    /**
628     * Constructor to recreate a locally-started transaction that does not
629     * involve other transaction managers. It is intended to be called at
630     * recovery time, for recreating transactions that were in the committing
631     * state when the server crashed. Such a transaction completed the first
632     * phase of the 2PC protocol and logged the commit decision, but it must
633     * still send commit messages to some or all of its <code>XAResource</code>s.
634     *
635     * @param localId the local id of a locally-started transaction that is in
636     * the committing state and does not involve other transaction
637     * managers
638     * @param preparedXidBranches a list of <code>org.jboss.tm.XAWork</code>
639     * instances containing one element for each
640     * <code>XAResource</code> that is enlisted with the transaction
641     * and is still in the prepared state
642     * @param completionHandler the
643     * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
644     * notifed when the second phase of the 2PC completes
645     * @param heurData either null or a <code>LogRecord.HeurData</code> instance
646     * contaning information on a locally-detected heuristic hazard.
647     */

648    TransactionImpl(long localId,
649                    List JavaDoc preparedXAWorkList,
650                    TxCompletionHandler completionHandler,
651                    LogRecord.HeurData heurData)
652    {
653       foreignTx = false;
654       xid = xidFactory.recreateXid(localId);
655       status = Status.STATUS_COMMITTING;
656       if (heurData != null)
657       {
658          heuristicCode = heurData.heuristicStatusCode;
659          heuristicHazard = heurData.locallyDetectedHeuristicHazard;
660       }
661       this.completionHandler = completionHandler;
662       for (Iterator JavaDoc it = preparedXAWorkList.iterator(); it.hasNext(); )
663       {
664          XAWork preparedXAWork = (XAWork) it.next();
665          EnlistedXAResource r = new EnlistedXAResource(preparedXAWork);
666          xaResources.add(r);
667
668       }
669       commitXAResourcesAfterTimeout();
670    }
671          
672    /**
673     * Constructor to recreate a locally-started transaction that involves other
674     * transaction managers. Involving other transaction managers means that
675     * there are remote <code>Resource</code>s enlisted with the transaction.
676     * This constructor is intended to be called at recovery time, for recreating
677     * transactions that were in the committing state when the server crashed.
678     * Such a transaction completed the first phase of the 2PC protocol and
679     * logged the commit decision, but it must still send commit messages to
680     * some or all of its resources (<code>XAResource</code>s and remote
681     * <code>Resource</code>s).
682     *
683     * @param localId the local id of a locally-started transaction that is in
684     * the committing state and involves other transaction managers
685     * @param preparedXAWorkList list of <code>org.jboss.tm.XAWork</code>
686     * instances containing one element for each
687     * <code>XAResource</code> that is enlisted with the transaction
688     * and is still in the prepared state
689     * @param resources an array with stringfied references for the remote
690     * <code>Resource</code>s enlisted with the transaction
691     * @param completionHandler the
692     * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
693     * notifed when the second phase of the 2PC completes
694     * @param heurData either null or a <code>LogRecord.HeurData</code> instance
695     * contaning information on a locally-detected heuristic hazard.
696     */

697    TransactionImpl(long localId,
698                    List JavaDoc preparedXAWorkList,
699                    String JavaDoc[] resources,
700                    TxCompletionHandler completionHandler,
701                    LogRecord.HeurData heurData)
702    {
703       foreignTx = false;
704       xid = xidFactory.recreateXid(localId);
705       status = Status.STATUS_COMMITTING;
706       this.completionHandler = completionHandler;
707       if (heurData != null)
708       {
709          heuristicCode = heurData.heuristicStatusCode;
710          heuristicHazard = heurData.locallyDetectedHeuristicHazard;
711       }
712       for (Iterator JavaDoc it = preparedXAWorkList.iterator(); it.hasNext(); )
713       {
714          XAWork preparedXAWork = (XAWork) it.next();
715          EnlistedXAResource r = new EnlistedXAResource(preparedXAWork);
716          xaResources.add(r);
717       }
718       for (int i = 0; i < resources.length; i++)
719       {
720          EnlistedRemoteResource r =
721             new EnlistedRemoteResource(stringToResource(resources[i]), true);
722          remoteResources.add(r);
723       }
724       lock();
725       try
726       {
727          retryCommitRemoteResources();
728       }
729       finally
730       {
731          unlock();
732       }
733       if (preparedXAWorkList.size() > 0)
734       {
735          // Keep this TransactionImpl around to
736
// commit its XAResources at a later time.
737
commitXAResourcesAfterTimeout();
738       }
739       else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE)
740       {
741          // This TransactionImpl is not needed anymore.
742
lock();
743          try
744          {
745             completeTransaction();
746          }
747          finally
748          {
749             unlock();
750          }
751       }
752       else
753       {
754          // Do nothing. Just keep this TransactionImpl around to receive
755
// replayCompletion calls from remote resources.
756
}
757    }
758
759    /**
760     * Constructor to recreate a foreign transaction that entered this virtual
761     * machine in a transaction context propagated along with a remote method
762     * invocation. This constructor is intended to be called at recovery time,
763     * for recreating transactions that were in the prepared state when the
764     * server crashed.
765     *
766     * @param localId the local id of a foreign transaction that entered this
767     * virtual machine in a transaction propagation context and is
768     * propagated along with a remote method invocation and is in
769     * the prepared state
770     * @param inboundFormatId format id part of the foreign transaction
771     * identifier that entered this virtual machine
772     * @param globalTransactionId global id part of the foreign transaction
773     * identifier that entered this virtual machine
774     * @param recoveryCoord an stringfied reference to the transaction branch's
775     * <code>RecovertyCoordinator</code>
776     * @param preparedXAWorkList a list of <code>org.jboss.tm.XAWork</code>
777     * instances containing one element for each
778     * <code>XAResource</code> enlisted with the transaction
779     * @param resources an array with stringfied references for the remote
780     * <code>Resource</code>s enlisted with the transaction
781     * @param completionHandler the
782     * <code>org.jboss.tm.recovery.TxCompletionHandler</code> to be
783     * notifed when the second phase of the 2PC completes
784     * @param heurData either null or a <code>LogRecord.HeurData</code> instance
785     * contaning information on a locally-detected heuristic hazard.
786     */

787    TransactionImpl(long localId,
788                    int inboundFormatId,
789                    byte[] globalTransactionId,
790                    String JavaDoc recoveryCoord,
791                    List JavaDoc preparedXAWorkList,
792                    String JavaDoc[] resources,
793                    TxCompletionHandler completionHandler,
794                    LogRecord.HeurData heurData)
795    {
796       foreignTx = true;
797       GlobalId globalId = new GlobalId(inboundFormatId, globalTransactionId);
798       xid = xidFactory.recreateXid(localId, globalId);
799       recoveryCoordinator = stringToRecoveryCoordinator(recoveryCoord);
800       if (heurData == null)
801          status = Status.STATUS_PREPARED;
802       else
803       {
804          status = heurData.transactionStatus;
805          heuristicCode = heurData.heuristicStatusCode;
806          heuristicHazard = heurData.locallyDetectedHeuristicHazard;
807       }
808       this.completionHandler = completionHandler;
809       for (Iterator JavaDoc it = preparedXAWorkList.iterator(); it.hasNext(); )
810       {
811          XAWork preparedXAWork = (XAWork) it.next();
812          EnlistedXAResource r = new EnlistedXAResource(preparedXAWork);
813          xaResources.add(r);
814       }
815       for (int i = 0; i < resources.length; i++)
816       {
817          EnlistedRemoteResource r =
818             new EnlistedRemoteResource(stringToResource(resources[i]), true);
819          remoteResources.add(r);
820       }
821       
822       // Set my registeredResource using the appropriate resource factory.
823
if (Proxy.isProxyClass(recoveryCoordinator.getClass()))
824       {
825          // DTM coordinator case
826
if (dtmResourceFactory != null)
827             registeredResource = dtmResourceFactory.createResource(localId);
828          else
829             log.warn("Error reconstructing TransactionImpl instance for tx="
830                      + toString() + " -- DTM resource factory missing." );
831       }
832       else
833       {
834          // OTS coordinator case
835
if (otsResourceFactory != null)
836             registeredResource = otsResourceFactory.createResource(localId);
837          else
838             log.warn("Error reconstructing TransactionImpl instance for tx=" +
839                      toString() + " -- OTS resource factory missing." );
840       }
841
842       if (status == Status.STATUS_PREPARED)
843       {
844          if (registeredResource != null)
845          {
846             createPreparedTimeout();
847             if (trace)
848                log.trace("Calling replayCompletion " +
849                          "on the recovery coordinator, tx=" + toString());
850             try
851             {
852                recoveryCoordinator.replayCompletion(registeredResource);
853             }
854             catch (NoSuchObjectException JavaDoc noCoordinator)
855             {
856                if (trace)
857                {
858                   log.trace("Exception in replayCompletion: no coordinator for tx="
859                             + toString(), noCoordinator);
860                   log.trace("Rolling back transaction branch, tx=" + toString());
861                }
862                try
863                {
864                   rollbackBranch();
865                }
866                catch (Exception JavaDoc e)
867                {
868                   if (trace)
869                      log.trace("Exception in transaction branch rollback, tx=" +
870                                toString(), e);
871                }
872             }
873             catch (Exception JavaDoc ignore)
874             {
875                if (trace)
876                   log.trace("Ignoring exception in replayCompletion, tx=" +
877                             toString(), ignore);
878             }
879          }
880          else
881             log.warn("Error reconstructing TransactionImpl instance for tx=" +
882                      toString() + " -- registeredResource not set.\n" +
883                      "The remote coordinator will NOT be contacted.");
884       }
885       else if (status == Status.STATUS_COMMITTING)
886       {
887          lock();
888          try
889          {
890             retryCommitRemoteResources();
891             
892             if (preparedXAWorkList.size() > 0)
893             {
894                // Keep this TransactionImpl around to
895
// commit its XAResources at a later time.
896
commitXAResourcesAfterTimeout();
897             }
898             else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE)
899             {
900                // This TransactionImpl is not needed anymore.
901
completeTransaction();
902             }
903             else
904             {
905                // Do nothing. Just keep this TransactionImpl around to
906
// receive replayCompletion calls from remote resources.
907
}
908          }
909          finally
910          {
911             unlock();
912          }
913       }
914