Source Code Cross Referenced for TransactionImpl.java in  » EJB-Server-JBoss-4.2.1 » transaction » org » jboss » tm » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » EJB Server JBoss 4.2.1 » transaction » org.jboss.tm 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * JBoss, Home of Professional Open Source.
0003:         * Copyright 2006, Red Hat Middleware LLC, and individual contributors
0004:         * as indicated by the @author tags. See the copyright.txt file in the
0005:         * distribution for a full listing of individual contributors.
0006:         *
0007:         * This is free software; you can redistribute it and/or modify it
0008:         * under the terms of the GNU Lesser General Public License as
0009:         * published by the Free Software Foundation; either version 2.1 of
0010:         * the License, or (at your option) any later version.
0011:         *
0012:         * This software is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015:         * Lesser General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU Lesser General Public
0018:         * License along with this software; if not, write to the Free
0019:         * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
0021:         */
0022:        package org.jboss.tm;
0023:
0024:        import java.util.ArrayList;
0025:        import java.util.Collections;
0026:        import java.util.HashMap;
0027:        import java.util.HashSet;
0028:        import java.util.Iterator;
0029:        import java.util.Map;
0030:        import java.util.Set;
0031:
0032:        import javax.resource.spi.work.Work;
0033:        import javax.resource.spi.work.WorkCompletedException;
0034:        import javax.resource.spi.work.WorkException;
0035:        import javax.transaction.HeuristicMixedException;
0036:        import javax.transaction.HeuristicRollbackException;
0037:        import javax.transaction.RollbackException;
0038:        import javax.transaction.Status;
0039:        import javax.transaction.Synchronization;
0040:        import javax.transaction.SystemException;
0041:        import javax.transaction.Transaction;
0042:        import javax.transaction.xa.XAException;
0043:        import javax.transaction.xa.XAResource;
0044:        import javax.transaction.xa.Xid;
0045:
0046:        import org.jboss.logging.Logger;
0047:        import org.jboss.tm.integrity.TransactionIntegrity;
0048:        import org.jboss.util.timeout.Timeout;
0049:        import org.jboss.util.timeout.TimeoutFactory;
0050:        import org.jboss.util.timeout.TimeoutTarget;
0051:
0052:        /**
0053:         *  Our <code>Transaction</code> implementation.
0054:         *
0055:         *  @see TxManager
0056:         *
0057:         *  @author <a href="mailto:rickard.oberg@telkel.com">Rickard Öberg</a>
0058:         *  @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
0059:         *  @author <a href="mailto:osh@sparre.dk">Ole Husgaard</a>
0060:         *  @author <a href="mailto:toby.allsopp@peace.com">Toby Allsopp</a>
0061:         *  @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
0062:         *  @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
0063:         *  @author <a href="mailto:bill@jboss.org">Bill Burke</a>
0064:         *  @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
0065:         *  @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
0066:         *  @version $Revision: 57208 $
0067:         */
0068:        public class TransactionImpl implements  Transaction, TimeoutTarget {
0069:            // Constants -----------------------------------------------------
0070:
0071:            /**
0072:             * Code meaning "no heuristics seen",
0073:             * must not be XAException.XA_HEURxxx
0074:             */
0075:            private static final int HEUR_NONE = XAException.XA_RETRY;
0076:
0077:            // Resource states
0078:            private final static int RS_NEW = 0; // not yet enlisted
0079:            private final static int RS_ENLISTED = 1; // enlisted
0080:            private final static int RS_SUSPENDED = 2; // suspended
0081:            private final static int RS_ENDED = 3; // not associated
0082:            private final static int RS_VOTE_READONLY = 4; // voted read-only
0083:            private final static int RS_VOTE_OK = 5; // voted ok
0084:            private final static int RS_FORGOT = 6; // RM has forgotten     
0085:
0086:            // Attributes ----------------------------------------------------
0087:
0088:            /** Class logger, we don't want a new logger with every transaction. */
0089:            private static Logger log = Logger.getLogger(TransactionImpl.class);
0090:
0091:            /** True if trace messages should be logged. */
0092:            private boolean trace = log.isTraceEnabled();
0093:
0094:            /** The ID of this transaction. */
0095:            private XidImpl xid;
0096:
0097:            /** The global id */
0098:            private GlobalId gid;
0099:
0100:            private HashSet threads = new HashSet(1);
0101:
0102:            private Map transactionLocalMap = Collections
0103:                    .synchronizedMap(new HashMap());
0104:
0105:            private Throwable cause;
0106:
0107:            /**
0108:             *  The synchronizations to call back.
0109:             */
0110:            private Synchronization[] sync = new Synchronization[3];
0111:
0112:            /**
0113:             *  Size of allocated synchronization array.
0114:             */
0115:            private int syncAllocSize = 3;
0116:
0117:            /**
0118:             *  Count of synchronizations for this transaction.
0119:             */
0120:            private int syncCount = 0;
0121:
0122:            /**
0123:             *  A list of the XAResources that have participated in this transaction.
0124:             */
0125:            private ArrayList resources = new ArrayList(3);
0126:
0127:            /**
0128:             * The XAResource used in the last resource gambit
0129:             */
0130:            private Resource lastResource;
0131:
0132:            /**
0133:             *  Flags that it is too late to enlist new resources.
0134:             */
0135:            private boolean resourcesEnded = false;
0136:
0137:            /**
0138:             *  Last branch id used.
0139:             */
0140:            private long lastBranchId = 0;
0141:
0142:            /**
0143:             *  Status of this transaction.
0144:             */
0145:            private int status;
0146:
0147:            /**
0148:             *  The heuristics status of this transaction.
0149:             */
0150:            private int heuristicCode = HEUR_NONE;
0151:
0152:            /**
0153:             *  The time when this transaction was started.
0154:             */
0155:            private long start;
0156:
0157:            /**
0158:             *  The timeout handle for this transaction.
0159:             */
0160:            private Timeout timeout;
0161:
0162:            /**
0163:             * Timeout in millisecs
0164:             */
0165:            private long timeoutPeriod;
0166:
0167:            /**
0168:             *  Mutex for thread-safety. This should only be changed in the
0169:             *  <code>lock()</code> and <code>unlock()</code> methods.
0170:             */
0171:            private Thread locked = null;
0172:
0173:            /**
0174:             * The lock depth
0175:             */
0176:            private int lockDepth = 0;
0177:
0178:            /** Any current work associated with the transaction */
0179:            private Work work;
0180:
0181:            /**
0182:             *  Flags that we are done with this transaction and that it can be reused.
0183:             */
0184:            private boolean done = false;
0185:
0186:            // Static --------------------------------------------------------
0187:
0188:            /**
0189:             *  Factory for Xid instances of specified class.
0190:             *  This is set from the <code>TransactionManagerService</code>
0191:             *  MBean.
0192:             */
0193:            static XidFactoryMBean xidFactory;
0194:
0195:            static TransactionManagerService txManagerService;
0196:
0197:            /** The timeout factory */
0198:            static TimeoutFactory timeoutFactory = TimeoutFactory
0199:                    .getSingleton();
0200:
0201:            /**
0202:             * This static code is only present for testing purposes so a
0203:             * tm can be usable without a lot of setup.
0204:             */
0205:            static void defaultXidFactory() {
0206:                if (xidFactory == null)
0207:                    xidFactory = new XidFactory();
0208:            }
0209:
0210:            // Constructors --------------------------------------------------
0211:
0212:            TransactionImpl(long timeout) {
0213:                xid = xidFactory.newXid();
0214:                gid = xid.getTrulyGlobalId();
0215:
0216:                status = Status.STATUS_ACTIVE;
0217:
0218:                start = System.currentTimeMillis();
0219:                this .timeout = timeoutFactory.createTimeout(start + timeout,
0220:                        this );
0221:                this .timeoutPeriod = timeout;
0222:                if (trace)
0223:                    log.trace("Created new instance for tx=" + toString());
0224:            }
0225:
0226:            TransactionImpl(GlobalId gid, long timeout) {
0227:                this .gid = gid;
0228:                xid = xidFactory.newXid();
0229:
0230:                status = Status.STATUS_ACTIVE;
0231:
0232:                start = System.currentTimeMillis();
0233:                this .timeout = timeoutFactory.createTimeout(start + timeout,
0234:                        this );
0235:                this .timeoutPeriod = timeout;
0236:                if (trace)
0237:                    log.trace("Created new instance for tx=" + toString());
0238:            }
0239:
0240:            // Implements TimeoutTarget --------------------------------------
0241:
0242:            /**
0243:             *  Called when our timeout expires.
0244:             */
0245:            public void timedOut(Timeout timeout) {
0246:                lock();
0247:                try {
0248:
0249:                    log.warn("Transaction " + toString() + " timed out."
0250:                            + " status=" + getStringStatus(status));
0251:
0252:                    if (this .timeout == null)
0253:                        return; // Don't race with timeout cancellation.
0254:                    this .timeout = null;
0255:
0256:                    switch (status) {
0257:                    case Status.STATUS_ROLLEDBACK:
0258:                    case Status.STATUS_COMMITTED:
0259:                    case Status.STATUS_NO_TRANSACTION:
0260:                        return; // Transaction done.
0261:
0262:                    case Status.STATUS_ROLLING_BACK:
0263:                        return; // Will be done shortly.
0264:
0265:                    case Status.STATUS_COMMITTING:
0266:                        // This is _very_ bad:
0267:                        // We are in the second commit phase, and have decided
0268:                        // to commit, but now we get a timeout and should rollback.
0269:                        // So we end up with a mixed decision.
0270:                        gotHeuristic(null, XAException.XA_HEURMIX);
0271:                        status = Status.STATUS_MARKED_ROLLBACK;
0272:                        return; // commit will fail
0273:
0274:                    case Status.STATUS_PREPARED:
0275:                        // This is bad:
0276:                        // We are done with the first phase, and are persistifying
0277:                        // our decision. Fortunately this case is currently never
0278:                        // hit, as we do not release the lock between the two phases.
0279:                    case Status.STATUS_ACTIVE:
0280:                        status = Status.STATUS_MARKED_ROLLBACK;
0281:                        // fall through..
0282:                    case Status.STATUS_MARKED_ROLLBACK:
0283:                        // don't rollback for now, this messes up with the TxInterceptor.
0284:                        interruptThreads();
0285:                        return;
0286:
0287:                    case Status.STATUS_PREPARING:
0288:                        status = Status.STATUS_MARKED_ROLLBACK;
0289:                        return; // commit will fail
0290:
0291:                    default:
0292:                        log.warn("Unknown status at timeout, tx=" + toString());
0293:                        return;
0294:                    }
0295:                } finally {
0296:                    unlock();
0297:                }
0298:            }
0299:
0300:            // Implements Transaction ----------------------------------------
0301:
0302:            public void commit() throws RollbackException,
0303:                    HeuristicMixedException, HeuristicRollbackException,
0304:                    java.lang.SecurityException,
0305:                    java.lang.IllegalStateException, SystemException {
0306:                lock();
0307:                try {
0308:                    if (trace)
0309:                        log.trace("Committing, tx=" + this  + ", status="
0310:                                + getStringStatus(status));
0311:
0312:                    beforePrepare();
0313:
0314:                    if (status == Status.STATUS_ACTIVE) {
0315:                        switch (getCommitStrategy()) {
0316:                        case 0:
0317:                            // Zero phase commit is really fast ;-)
0318:                            if (trace)
0319:                                log.trace("Zero phase commit " + this 
0320:                                        + ": No resources.");
0321:                            status = Status.STATUS_COMMITTED;
0322:                            break;
0323:                        case 1:
0324:                            // One phase commit
0325:                            if (trace)
0326:                                log.trace("One phase commit " + this 
0327:                                        + ": One resource.");
0328:                            commitResources(true);
0329:                            break;
0330:                        default:
0331:                            // Two phase commit
0332:                            if (trace)
0333:                                log.trace("Two phase commit " + this 
0334:                                        + ": Many resources.");
0335:
0336:                            if (!prepareResources()) {
0337:                                boolean commitDecision = status == Status.STATUS_PREPARED
0338:                                        && (heuristicCode == HEUR_NONE || heuristicCode == XAException.XA_HEURCOM);
0339:
0340:                                // TODO: Save decision to stable storage for recovery
0341:                                //       after system crash.
0342:
0343:                                if (commitDecision)
0344:                                    commitResources(false);
0345:                            } else
0346:                                status = Status.STATUS_COMMITTED; // all was read-only
0347:                        }
0348:                    }
0349:
0350:                    if (status != Status.STATUS_COMMITTED) {
0351:                        Throwable causedByThrowable = cause;
0352:                        rollbackResources();
0353:                        completeTransaction();
0354:
0355:                        // throw jboss rollback exception with the saved off cause
0356:                        throw new JBossRollbackException(
0357:                                "Unable to commit, tx=" + toString()
0358:                                        + " status=" + getStringStatus(status),
0359:                                causedByThrowable);
0360:                    }
0361:
0362:                    completeTransaction();
0363:                    checkHeuristics();
0364:
0365:                    if (trace)
0366:                        log.trace("Committed OK, tx=" + this );
0367:
0368:                } finally {
0369:                    unlock();
0370:                }
0371:            }
0372:
0373:            public void rollback() throws java.lang.IllegalStateException,
0374:                    java.lang.SecurityException, SystemException {
0375:                lock();
0376:                try {
0377:
0378:                    if (trace)
0379:                        log.trace("rollback(): Entered, tx=" + toString()
0380:                                + " status=" + getStringStatus(status));
0381:
0382:                    checkWork();
0383:
0384:                    switch (status) {
0385:                    case Status.STATUS_ACTIVE:
0386:                        status = Status.STATUS_MARKED_ROLLBACK;
0387:                        // fall through..
0388:                    case Status.STATUS_MARKED_ROLLBACK:
0389:                        endResources();
0390:                        rollbackResources();
0391:                        completeTransaction();
0392:                        // Cannot throw heuristic exception, so we just have to
0393:                        // clear the heuristics without reporting.
0394:                        heuristicCode = HEUR_NONE;
0395:                        return;
0396:                    case Status.STATUS_PREPARING:
0397:                        // Set status to avoid race with prepareResources().
0398:                        status = Status.STATUS_MARKED_ROLLBACK;
0399:                        return; // commit() will do rollback.
0400:                    default:
0401:                        throw new IllegalStateException("Cannot rollback(), "
0402:                                + "tx=" + toString() + " status="
0403:                                + getStringStatus(status));
0404:                    }
0405:                } finally {
0406:                    Thread.interrupted();// clear timeout that did an interrupt
0407:                    unlock();
0408:                }
0409:            }
0410:
0411:            public boolean delistResource(XAResource xaRes, int flag)
0412:                    throws java.lang.IllegalStateException, SystemException {
0413:                if (xaRes == null)
0414:                    throw new IllegalArgumentException("null xaRes tx=" + this );
0415:                if (flag != XAResource.TMSUCCESS
0416:                        && flag != XAResource.TMSUSPEND
0417:                        && flag != XAResource.TMFAIL)
0418:                    throw new IllegalArgumentException("Bad flag: " + flag
0419:                            + " tx=" + this );
0420:
0421:                lock();
0422:                try {
0423:                    if (trace)
0424:                        log.trace("delistResource(): Entered, tx=" + toString()
0425:                                + " status=" + getStringStatus(status));
0426:
0427:                    Resource resource = findResource(xaRes);
0428:                    if (resource == null)
0429:                        throw new IllegalArgumentException(
0430:                                "xaRes not enlisted " + xaRes);
0431:
0432:                    switch (status) {
0433:                    case Status.STATUS_ACTIVE:
0434:                    case Status.STATUS_MARKED_ROLLBACK:
0435:                        break;
0436:                    case Status.STATUS_PREPARING:
0437:                        throw new IllegalStateException(
0438:                                "Already started preparing. " + this );
0439:                    case Status.STATUS_ROLLING_BACK:
0440:                        throw new IllegalStateException(
0441:                                "Already started rolling back. " + this );
0442:                    case Status.STATUS_PREPARED:
0443:                        throw new IllegalStateException("Already prepared. "
0444:                                + this );
0445:                    case Status.STATUS_COMMITTING:
0446:                        throw new IllegalStateException(
0447:                                "Already started committing. " + this );
0448:                    case Status.STATUS_COMMITTED:
0449:                        throw new IllegalStateException("Already committed. "
0450:                                + this );
0451:                    case Status.STATUS_ROLLEDBACK:
0452:                        throw new IllegalStateException("Already rolled back. "
0453:                                + this );
0454:                    case Status.STATUS_NO_TRANSACTION:
0455:                        throw new IllegalStateException("No transaction. "
0456:                                + this );
0457:                    case Status.STATUS_UNKNOWN:
0458:                        throw new IllegalStateException("Unknown state " + this );
0459:                    default:
0460:                        throw new IllegalStateException("Illegal status: "
0461:                                + getStringStatus(status) + " tx=" + this );
0462:                    }
0463:
0464:                    try {
0465:                        return resource.delistResource(xaRes, flag);
0466:                    } catch (XAException xae) {
0467:                        logXAException(xae);
0468:                        status = Status.STATUS_MARKED_ROLLBACK;
0469:                        cause = xae;
0470:                        return false;
0471:                    }
0472:                } finally {
0473:                    unlock();
0474:                }
0475:            }
0476:
0477:            public boolean enlistResource(XAResource xaRes)
0478:                    throws RollbackException, java.lang.IllegalStateException,
0479:                    SystemException {
0480:                if (xaRes == null)
0481:                    throw new IllegalArgumentException("null xaRes tx=" + this );
0482:
0483:                lock();
0484:                try {
0485:
0486:                    if (trace)
0487:                        log.trace("enlistResource(): Entered, tx=" + toString()
0488:                                + " status=" + getStringStatus(status)
0489:                                + " xaRes=" + xaRes);
0490:
0491:                    switch (status) {
0492:                    case Status.STATUS_ACTIVE:
0493:                    case Status.STATUS_PREPARING:
0494:                        break;
0495:                    case Status.STATUS_PREPARED:
0496:                        throw new IllegalStateException("Already prepared. "
0497:                                + this );
0498:                    case Status.STATUS_COMMITTING:
0499:                        throw new IllegalStateException(
0500:                                "Already started committing. " + this );
0501:                    case Status.STATUS_COMMITTED:
0502:                        throw new IllegalStateException("Already committed. "
0503:                                + this );
0504:                    case Status.STATUS_MARKED_ROLLBACK:
0505:                        throw new RollbackException(
0506:                                "Already marked for rollback " + this );
0507:                    case Status.STATUS_ROLLING_BACK:
0508:                        throw new RollbackException(
0509:                                "Already started rolling back. " + this );
0510:                    case Status.STATUS_ROLLEDBACK:
0511:                        throw new RollbackException("Already rolled back. "
0512:                                + this );
0513:                    case Status.STATUS_NO_TRANSACTION:
0514:                        throw new IllegalStateException("No transaction. "
0515:                                + this );
0516:                    case Status.STATUS_UNKNOWN:
0517:                        throw new IllegalStateException("Unknown state " + this );
0518:                    default:
0519:                        throw new IllegalStateException("Illegal status: "
0520:                                + getStringStatus(status) + " tx=" + this );
0521:                    }
0522:
0523:                    if (resourcesEnded)
0524:                        throw new IllegalStateException(
0525:                                "Too late to enlist resources " + this );
0526:
0527:                    // Add resource
0528:                    try {
0529:                        Resource resource = findResource(xaRes);
0530:
0531:                        // Existing resource
0532:                        if (resource != null) {
0533:                            if (resource.isEnlisted()) {
0534:                                if (trace)
0535:                                    log.trace("Already enlisted: tx="
0536:                                            + toString() + " status="
0537:                                            + getStringStatus(status)
0538:                                            + " xaRes=" + xaRes);
0539:                                return true; // already enlisted
0540:                            }
0541:                            if (resource.isDelisted(xaRes))
0542:                                // this is a resource that returns false on all calls to
0543:                                // isSameRM.  Further, the last resource enlisted has
0544:                                // already been delisted, so it is time to enlist it again.
0545:                                resource = null;
0546:                            else
0547:                                return resource.startResource();
0548:                        }
0549:
0550:                        resource = findResourceManager(xaRes);
0551:                        if (resource != null) {
0552:                            // The xaRes is new. We register the xaRes with the Xid
0553:                            // that the RM has previously seen from this transaction,
0554:                            // and note that it has the same RM.
0555:                            resource = addResource(xaRes, resource.getXid(),
0556:                                    resource);
0557:                            return resource.startResource();
0558:                        }
0559:
0560:                        // New resource and new RM: Create a new transaction branch.
0561:                        resource = addResource(xaRes, createXidBranch(), null);
0562:                        return resource.startResource();
0563:                    } catch (XAException xae) {
0564:                        logXAException(xae);
0565:                        cause = xae;
0566:                        return false;
0567:                    }
0568:                } finally {
0569:                    unlock();
0570:                }
0571:
0572:            }
0573:
0574:            public int getStatus() throws SystemException {
0575:                if (done)
0576:                    return Status.STATUS_NO_TRANSACTION;
0577:                return status;
0578:            }
0579:
0580:            public void registerSynchronization(Synchronization s)
0581:                    throws RollbackException, java.lang.IllegalStateException,
0582:                    SystemException {
0583:                if (s == null)
0584:                    throw new IllegalArgumentException("Null synchronization "
0585:                            + this );
0586:
0587:                lock();
0588:                try {
0589:                    if (trace) {
0590:                        log.trace("registerSynchronization(): Entered, "
0591:                                + "tx=" + toString() + " status="
0592:                                + getStringStatus(status));
0593:                    }
0594:
0595:                    switch (status) {
0596:                    case Status.STATUS_ACTIVE:
0597:                    case Status.STATUS_PREPARING:
0598:                        break;
0599:                    case Status.STATUS_PREPARED:
0600:                        throw new IllegalStateException("Already prepared. "
0601:                                + this );
0602:                    case Status.STATUS_COMMITTING:
0603:                        throw new IllegalStateException(
0604:                                "Already started committing. " + this );
0605:                    case Status.STATUS_COMMITTED:
0606:                        throw new IllegalStateException("Already committed. "
0607:                                + this );
0608:                    case Status.STATUS_MARKED_ROLLBACK:
0609:                        throw new RollbackException(
0610:                                "Already marked for rollback " + this );
0611:                    case Status.STATUS_ROLLING_BACK:
0612:                        throw new RollbackException(
0613:                                "Already started rolling back. " + this );
0614:                    case Status.STATUS_ROLLEDBACK:
0615:                        throw new RollbackException("Already rolled back. "
0616:                                + this );
0617:                    case Status.STATUS_NO_TRANSACTION:
0618:                        throw new IllegalStateException("No transaction. "
0619:                                + this );
0620:                    case Status.STATUS_UNKNOWN:
0621:                        throw new IllegalStateException("Unknown state " + this );
0622:                    default:
0623:                        throw new IllegalStateException("Illegal status: "
0624:                                + getStringStatus(status) + " tx=" + this );
0625:                    }
0626:
0627:                    if (syncCount == syncAllocSize) {
0628:                        // expand table
0629:                        syncAllocSize = 2 * syncAllocSize;
0630:
0631:                        Synchronization[] sy = new Synchronization[syncAllocSize];
0632:                        System.arraycopy(sync, 0, sy, 0, syncCount);
0633:                        sync = sy;
0634:                    }
0635:                    sync[syncCount++] = s;
0636:                } finally {
0637:                    unlock();
0638:                }
0639:            }
0640:
0641:            public void setRollbackOnly()
0642:                    throws java.lang.IllegalStateException, SystemException {
0643:                lock();
0644:                try {
0645:                    if (trace)
0646:                        log.trace("setRollbackOnly(): Entered, tx="
0647:                                + toString() + " status="
0648:                                + getStringStatus(status));
0649:
0650:                    switch (status) {
0651:                    case Status.STATUS_ACTIVE:
0652:                    case Status.STATUS_PREPARING:
0653:                    case Status.STATUS_PREPARED:
0654:                        status = Status.STATUS_MARKED_ROLLBACK;
0655:                        // fall through..
0656:                    case Status.STATUS_MARKED_ROLLBACK:
0657:                    case Status.STATUS_ROLLING_BACK:
0658:                        return;
0659:                    case Status.STATUS_COMMITTING:
0660:                        throw new IllegalStateException(
0661:                                "Already started committing. " + this );
0662:                    case Status.STATUS_COMMITTED:
0663:                        throw new IllegalStateException("Already committed. "
0664:                                + this );
0665:                    case Status.STATUS_ROLLEDBACK:
0666:                        throw new IllegalStateException("Already rolled back. "
0667:                                + this );
0668:                    case Status.STATUS_NO_TRANSACTION:
0669:                        throw new IllegalStateException("No transaction. "
0670:                                + this );
0671:                    case Status.STATUS_UNKNOWN:
0672:                        throw new IllegalStateException("Unknown state " + this );
0673:                    default:
0674:                        throw new IllegalStateException("Illegal status: "
0675:                                + getStringStatus(status) + " tx=" + this );
0676:                    }
0677:                } finally {
0678:                    unlock();
0679:                }
0680:            }
0681:
0682:            // Public --------------------------------------------------------
0683:
0684:            public int getAssociatedThreadCount() {
0685:                lock();
0686:                try {
0687:                    return threads.size();
0688:                } finally {
0689:                    unlock();
0690:                }
0691:            }
0692:
0693:            public Set getAssociatedThreads() {
0694:                lock();
0695:                try {
0696:                    return Collections.unmodifiableSet(threads);
0697:                } finally {
0698:                    unlock();
0699:                }
0700:            }
0701:
0702:            public int hashCode() {
0703:                return xid.hashCode();
0704:            }
0705:
0706:            public String toString() {
0707:                return "TransactionImpl:" + xidFactory.toString(xid);
0708:            }
0709:
0710:            public boolean equals(Object obj) {
0711:                if (obj != null && obj instanceof  TransactionImpl)
0712:                    return getLocalIdValue() == (((TransactionImpl) obj)
0713:                            .getLocalIdValue());
0714:                return false;
0715:            }
0716:
0717:            /**
0718:             *  Returns the local id of this transaction. The local id is used as 
0719:             *  a transaction propagation context within the JBoss server, and 
0720:             *  in the TxManager for mapping local transaction ids to transactions.
0721:             */
0722:            public long getLocalIdValue() {
0723:                return xid.getLocalIdValue();
0724:            }
0725:
0726:            /**
0727:             *  Returns the local id of this transaction. The local id is used as 
0728:             *  a transaction propagation context within the JBoss server, and 
0729:             *  in the TxManager for mapping local transaction ids to transactions.
0730:             */
0731:            public LocalId getLocalId() {
0732:                return xid.getLocalId();
0733:            }
0734:
0735:            /**
0736:             *  Returns the global id of this transaction. Ths global id is used in 
0737:             *  the TxManager, which keeps a map from global ids to transactions.
0738:             */
0739:            public GlobalId getGlobalId() {
0740:                return gid;
0741:            }
0742:
0743:            /**
0744:             *  Returns the xid of this transaction.
0745:             */
0746:            public XidImpl getXid() {
0747:                return xid;
0748:            }
0749:
0750:            // Package protected ---------------------------------------------
0751:
0752:            void associateCurrentThread() {
0753:                Thread.interrupted();
0754:                lock();
0755:                try {
0756:                    threads.add(Thread.currentThread());
0757:                } finally {
0758:                    unlock();
0759:                }
0760:            }
0761:
0762:            void disassociateCurrentThread() {
0763:                // Just a tidyup, no need to synchronize
0764:                if (done) {
0765:                    threads.remove(Thread.currentThread());
0766:                } else {
0767:                    // Removing the association for an active transaction
0768:                    lock();
0769:                    try {
0770:                        threads.remove(Thread.currentThread());
0771:                    } finally {
0772:                        unlock();
0773:                    }
0774:                }
0775:                Thread.interrupted();
0776:            }
0777:
0778:            /**
0779:             *  Lock this instance.
0780:             */
0781:            synchronized void lock() {
0782:                if (done)
0783:                    throw new IllegalStateException(
0784:                            "Transaction has terminated " + this );
0785:
0786:                Thread currentThread = Thread.currentThread();
0787:                if (locked != null && locked != currentThread) {
0788:                    log.debug("Lock contention, tx=" + toString()
0789:                            + " otherThread=" + locked);
0790:                    //DEBUG Thread.currentThread().dumpStack();
0791:
0792:                    while (locked != null && locked != currentThread) {
0793:                        try {
0794:                            // Wakeup happens when:
0795:                            // - notify() is called from unlock()
0796:                            // - notifyAll is called from instanceDone()
0797:                            wait();
0798:                        } catch (InterruptedException ex) {
0799:                            // ignore
0800:                        }
0801:
0802:                        if (done)
0803:                            throw new IllegalStateException(
0804:                                    "Transaction has now terminated " + this );
0805:                    }
0806:                }
0807:
0808:                locked = currentThread;
0809:                ++lockDepth;
0810:            }
0811:
0812:            /**
0813:             *  Unlock this instance.
0814:             */
0815:            synchronized void unlock() {
0816:                Thread currentThread = Thread.currentThread();
0817:                if (locked == null || locked != currentThread) {
0818:                    log.warn("Unlocking, but not locked, tx=" + toString()
0819:                            + " otherThread=" + locked, new Throwable(
0820:                            "[Stack trace]"));
0821:                } else {
0822:                    if (--lockDepth == 0) {
0823:                        locked = null;
0824:                        notify();
0825:                    }
0826:                }
0827:            }
0828:
0829:            /**
0830:             * Prepare an external transaction
0831:             * 
0832:             * @return XAResource.XA_RDONLY or XAResource.XA_OK
0833:             */
0834:            int prepare() throws HeuristicMixedException,
0835:                    HeuristicRollbackException, RollbackException {
0836:                lock();
0837:                try {
0838:                    if (trace)
0839:                        log.trace("Preparing, tx=" + this  + ", status="
0840:                                + getStringStatus(status));
0841:
0842:                    checkWork();
0843:
0844:                    beforePrepare();
0845:
0846:                    if (status == Status.STATUS_ACTIVE) {
0847:                        switch (getCommitStrategy()) {
0848:                        case 0: {
0849:                            // Nothing to do
0850:                            if (trace)
0851:                                log.trace("Prepare tx=" + this 
0852:                                        + ": No resources.");
0853:                            status = Status.STATUS_COMMITTED;
0854:                            completeTransaction();
0855:                            return XAResource.XA_RDONLY;
0856:                        }
0857:                        default: {
0858:                            // Two phase commit
0859:                            if (trace)
0860:                                log.trace("Prepare tx=" + this 
0861:                                        + ": Many resources.");
0862:
0863:                            if (!prepareResources()) {
0864:                                /*boolean commitDecision =
0865:                                   status == Status.STATUS_PREPARED &&
0866:                                   (heuristicCode == HEUR_NONE ||
0867:                                    heuristicCode == XAException.XA_HEURCOM);*/
0868:
0869:                                // TODO: Save decision to stable storage for recovery
0870:                                //       after system crash.
0871:                            } else {
0872:                                if (trace)
0873:                                    log.trace("Prepared tx=" + this 
0874:                                            + ": All readonly.");
0875:                                status = Status.STATUS_COMMITTED;
0876:                                completeTransaction();
0877:                                return XAResource.XA_RDONLY;
0878:                            }
0879:                        }
0880:                        }
0881:                    }
0882:
0883:                    if (status != Status.STATUS_PREPARED) {
0884:                        // save off the cause throwable as Instance done resets it to null
0885:                        Throwable causedByThrowable = cause;
0886:                        rollbackResources();
0887:                        completeTransaction();
0888:
0889:                        // throw jboss rollback exception with the saved off cause
0890:                        throw new JBossRollbackException(
0891:                                "Unable to prepare, tx=" + toString()
0892:                                        + " status=" + getStringStatus(status),
0893:                                causedByThrowable);
0894:                    }
0895:
0896:                    // We are ok to commit
0897:                    return XAResource.XA_OK;
0898:                } finally {
0899:                    unlock();
0900:                }
0901:            }
0902:
0903:            /**
0904:             * Commit an external transaction
0905:             *
0906:             * @param onePhase whether the commit is one or two phase 
0907:             */
0908:            void commit(boolean onePhase) throws RollbackException,
0909:                    HeuristicMixedException, HeuristicRollbackException,
0910:                    SystemException {
0911:                checkWork();
0912:
0913:                // One phase commit optimization
0914:                if (onePhase) {
0915:                    commit();
0916:                    return;
0917:                }
0918:
0919:                // Two phase
0920:                lock();
0921:                try {
0922:                    if (trace)
0923:                        log.trace("Committing two phase, tx=" + this 
0924:                                + ", status=" + getStringStatus(status));
0925:
0926:                    switch (status) {
0927:                    case Status.STATUS_PREPARING:
0928:                        throw new IllegalStateException("Still preparing. "
0929:                                + this );
0930:                    case Status.STATUS_ROLLING_BACK:
0931:                        throw new IllegalStateException(
0932:                                "Already started rolling back. " + this );
0933:                    case Status.STATUS_ROLLEDBACK:
0934:                        instanceDone();
0935:                        checkHeuristics();
0936:                        throw new IllegalStateException("Already rolled back. "
0937:                                + this );
0938:                    case Status.STATUS_COMMITTING:
0939:                        throw new IllegalStateException(
0940:                                "Already started committing. " + this );
0941:                    case Status.STATUS_COMMITTED:
0942:                        instanceDone();
0943:                        checkHeuristics();
0944:                        throw new IllegalStateException("Already committed. "
0945:                                + this );
0946:                    case Status.STATUS_NO_TRANSACTION:
0947:                        throw new IllegalStateException("No transaction. "
0948:                                + this );
0949:                    case Status.STATUS_UNKNOWN:
0950:                        throw new IllegalStateException("Unknown state " + this );
0951:                    case Status.STATUS_MARKED_ROLLBACK:
0952:                        endResources();
0953:                        rollbackResources();
0954:                        completeTransaction();
0955:                        checkHeuristics();
0956:                        throw new RollbackException(
0957:                                "Already marked for rollback " + this );
0958:                    case Status.STATUS_PREPARED:
0959:                        break;
0960:                    default:
0961:                        throw new IllegalStateException("Illegal status: "
0962:                                + getStringStatus(status) + " tx=" + this );
0963:                    }
0964:
0965:                    commitResources(false);
0966:
0967:                    if (status != Status.STATUS_COMMITTED) {
0968:                        Throwable causedByThrowable = cause;
0969:                        rollbackResources();
0970:                        completeTransaction();
0971:
0972:                        // throw jboss rollback exception with the saved off cause
0973:                        throw new JBossRollbackException(
0974:                                "Unable to commit, tx=" + toString()
0975:                                        + " status=" + getStringStatus(status),
0976:                                causedByThrowable);
0977:                    }
0978:
0979:                    completeTransaction();
0980:                    checkHeuristics();
0981:
0982:                    if (trace)
0983:                        log.trace("Committed OK, tx=" + this );
0984:
0985:                } finally {
0986:                    unlock();
0987:                }
0988:            }
0989:
0990:            /**
0991:             * Get the work
0992:             * 
0993:             * @return the work
0994:             */
0995:            Work getWork() {
0996:                return work;
0997:            }
0998:
0999:            /**
1000:             * Set the work
1001:             * 
1002:             * @param work the work
1003:             * @throws WorkCompletedException with error code WorkException.TX_CONCURRENT_WORK_DISALLOWED
1004:             *         when work is already present for the xid or whose completion is in progress, only
1005:             *         the global part of the xid must be used for this check. Or with error code
1006:             *         WorkException.TX_RECREATE_FAILED if it is unable to recreate the transaction context
1007:             */
1008:            void setWork(Work work) throws WorkCompletedException {
1009:                lock();
1010:                try {
1011:                    if (work == null) {
1012:                        this .work = null;
1013:                        return;
1014:                    }
1015:
1016:                    if (status == Status.STATUS_NO_TRANSACTION
1017:                            || status == Status.STATUS_UNKNOWN)
1018:                        throw new WorkCompletedException(
1019:                                "The transaction is not active " + this  + ": "
1020:                                        + getStringStatus(status),
1021:                                WorkException.TX_RECREATE_FAILED);
1022:                    else if (status != Status.STATUS_ACTIVE)
1023:                        throw new WorkCompletedException(
1024:                                "Too late to start work " + this  + ": "
1025:                                        + getStringStatus(status),
1026:                                WorkException.TX_CONCURRENT_WORK_DISALLOWED);
1027:                    else if (this .work != null)
1028:                        throw new WorkCompletedException("Already have work "
1029:                                + this  + ": " + this .work,
1030:                                WorkException.TX_CONCURRENT_WORK_DISALLOWED);
1031:
1032:                    this .work = work;
1033:                } finally {
1034:                    unlock();
1035:                }
1036:            }
1037:
1038:            /**
1039:             *  Getter for property done.
1040:             */
1041:            boolean isDone() {
1042:                return done;
1043:            }
1044:
1045:            // Private -------------------------------------------------------
1046:
1047:            /**
1048:             * Before prepare
1049:             */
1050:            private void beforePrepare() throws HeuristicMixedException,
1051:                    HeuristicRollbackException, RollbackException {
1052:                checkIntegrity();
1053:
1054:                doBeforeCompletion();
1055:
1056:                if (trace)
1057:                    log.trace("Before completion done, tx=" + this 
1058:                            + ", status=" + getStringStatus(status));
1059:
1060:                endResources();
1061:            }
1062:
1063:            /**
1064:             * Check the integrity of the transaction
1065:             */
1066:            private void checkIntegrity() throws HeuristicMixedException,
1067:                    HeuristicRollbackException, RollbackException {
1068:                // Spec defined checks for the transaction in a valid state
1069:                checkBeforeStatus();
1070:
1071:                TransactionIntegrity integrity = TxManager.getInstance()
1072:                        .getTransactionIntegrity();
1073:                if (integrity != null) {
1074:                    // Extra integrity checks
1075:                    unlock();
1076:                    try {
1077:                        integrity.checkTransactionIntegrity(this );
1078:                    } finally {
1079:                        lock();
1080:                    }
1081:
1082:                    // Recheck the transaction state
1083:                    checkBeforeStatus();
1084:                }
1085:            }
1086:
1087:            /**
1088:             * Check the before status
1089:             */
1090:            private void checkBeforeStatus() throws HeuristicMixedException,
1091:                    HeuristicRollbackException, RollbackException {
1092:                switch (status) {
1093:                case Status.STATUS_PREPARING:
1094:                    throw new IllegalStateException(
1095:                            "Already started preparing. " + this );
1096:                case Status.STATUS_PREPARED:
1097:                    throw new IllegalStateException("Already prepared. " + this );
1098:                case Status.STATUS_ROLLING_BACK:
1099:                    throw new IllegalStateException(
1100:                            "Already started rolling back. " + this );
1101:                case Status.STATUS_ROLLEDBACK:
1102:                    instanceDone();
1103:                    checkHeuristics();
1104:                    throw new IllegalStateException("Already rolled back."
1105:                            + this );
1106:                case Status.STATUS_COMMITTING:
1107:                    throw new IllegalStateException(
1108:                            "Already started committing. " + this );
1109:                case Status.STATUS_COMMITTED:
1110:                    instanceDone();
1111:                    checkHeuristics();
1112:                    throw new IllegalStateException("Already committed. "
1113:                            + this );
1114:                case Status.STATUS_NO_TRANSACTION:
1115:                    throw new IllegalStateException("No transaction. " + this );
1116:                case Status.STATUS_UNKNOWN:
1117:                    throw new IllegalStateException("Unknown state " + this );
1118:                case Status.STATUS_MARKED_ROLLBACK:
1119:                    endResources();
1120:                    rollbackResources();
1121:                    completeTransaction();
1122:                    checkHeuristics();
1123:                    throw new RollbackException("Already marked for rollback "
1124:                            + this );
1125:                case Status.STATUS_ACTIVE:
1126:                    break;
1127:                default:
1128:                    throw new IllegalStateException("Illegal status: "
1129:                            + getStringStatus(status) + " tx=" + this );
1130:                }
1131:            }
1132:
1133:            /**
1134:             * Complete the transaction 
1135:             */
1136:            private void completeTransaction() {
1137:                cancelTimeout();
1138:                doAfterCompletion();
1139:                instanceDone();
1140:            }
1141:
1142:            /**
1143:             * Interrupt all threads involved with transaction
1144:             * This is called on timeout
1145:             */
1146:            private void interruptThreads() {
1147:                TxManager manager = TxManager.getInstance();
1148:                if (manager.isInterruptThreads()) {
1149:                    HashSet clone = (HashSet) threads.clone();
1150:                    threads.clear();
1151:                    for (Iterator i = clone.iterator(); i.hasNext();) {
1152:                        Thread thread = (Thread) i.next();
1153:                        try {
1154:                            thread.interrupt();
1155:                        } catch (Throwable ignored) {
1156:                            if (trace)
1157:                                log.trace("Ignored error interrupting thread: "
1158:                                        + thread, ignored);
1159:                        }
1160:                    }
1161:                }
1162:            }
1163:
1164:            /**
1165:             *  Return a string representation of the given status code.
1166:             */
1167:            private String getStringStatus(int status) {
1168:                switch (status) {
1169:                case Status.STATUS_PREPARING:
1170:                    return "STATUS_PREPARING";
1171:                case Status.STATUS_PREPARED:
1172:                    return "STATUS_PREPARED";
1173:                case Status.STATUS_ROLLING_BACK:
1174:                    return "STATUS_ROLLING_BACK";
1175:                case Status.STATUS_ROLLEDBACK:
1176:                    return "STATUS_ROLLEDBACK";
1177:                case Status.STATUS_COMMITTING:
1178:                    return "STATUS_COMMITING";
1179:                case Status.STATUS_COMMITTED:
1180:                    return "STATUS_COMMITED";
1181:                case Status.STATUS_NO_TRANSACTION:
1182:                    return "STATUS_NO_TRANSACTION";
1183:                case Status.STATUS_UNKNOWN:
1184:                    return "STATUS_UNKNOWN";
1185:                case Status.STATUS_MARKED_ROLLBACK:
1186:                    return "STATUS_MARKED_ROLLBACK";
1187:                case Status.STATUS_ACTIVE:
1188:                    return "STATUS_ACTIVE";
1189:
1190:                default:
1191:                    return "STATUS_UNKNOWN(" + status + ")";
1192:                }
1193:            }
1194:
1195:            /**
1196:             *  Return a string representation of the given XA error code.
1197:             */
1198:            private String getStringXAErrorCode(int errorCode) {
1199:                switch (errorCode) {
1200:                case XAException.XA_HEURCOM:
1201:                    return "XA_HEURCOM";
1202:                case XAException.XA_HEURHAZ:
1203:                    return "XA_HEURHAZ";
1204:                case XAException.XA_HEURMIX:
1205:                    return "XA_HEURMIX";
1206:                case XAException.XA_HEURRB:
1207:                    return "XA_HEURRB";
1208:
1209:                case XAException.XA_NOMIGRATE:
1210:                    return "XA_NOMIGRATE";
1211:
1212:                case XAException.XA_RBCOMMFAIL:
1213:                    return "XA_RBCOMMFAIL";
1214:                case XAException.XA_RBDEADLOCK:
1215:                    return "XA_RBDEADLOCK";
1216:                case XAException.XA_RBINTEGRITY:
1217:                    return "XA_RBINTEGRITY";
1218:                case XAException.XA_RBOTHER:
1219:                    return "XA_RBOTHER";
1220:                case XAException.XA_RBPROTO:
1221:                    return "XA_RBPROTO";
1222:                case XAException.XA_RBROLLBACK:
1223:                    return "XA_RBROLLBACK";
1224:                case XAException.XA_RBTIMEOUT:
1225:                    return "XA_RBTIMEOUT";
1226:                case XAException.XA_RBTRANSIENT:
1227:                    return "XA_RBTRANSIENT";
1228:
1229:                case XAException.XA_RDONLY:
1230:                    return "XA_RDONLY";
1231:                case XAException.XA_RETRY:
1232:                    return "XA_RETRY";
1233:
1234:                case XAException.XAER_ASYNC:
1235:                    return "XAER_ASYNC";
1236:                case XAException.XAER_DUPID:
1237:                    return "XAER_DUPID";
1238:                case XAException.XAER_INVAL:
1239:                    return "XAER_INVAL";
1240:                case XAException.XAER_NOTA:
1241:                    return "XAER_NOTA";
1242:                case XAException.XAER_OUTSIDE:
1243:                    return "XAER_OUTSIDE";
1244:                case XAException.XAER_PROTO:
1245:                    return "XAER_PROTO";
1246:                case XAException.XAER_RMERR:
1247:                    return "XAER_RMERR";
1248:                case XAException.XAER_RMFAIL:
1249:                    return "XAER_RMFAIL";
1250:
1251:                default:
1252:                    return "XA_UNKNOWN(" + errorCode + ")";
1253:                }
1254:            }
1255:
1256:            private void logXAException(XAException xae) {
1257:                log.warn("XAException: tx=" + toString() + " errorCode="
1258:                        + getStringXAErrorCode(xae.errorCode), xae);
1259:                if (txManagerService != null)
1260:                    txManagerService.formatXAException(xae, log);
1261:            }
1262:
1263:            /**
1264:             *  Mark this transaction as non-existing.
1265:             */
1266:            private synchronized void instanceDone() {
1267:                TxManager manager = TxManager.getInstance();
1268:
1269:                if (status == Status.STATUS_COMMITTED)
1270:                    manager.incCommitCount();
1271:                else
1272:                    manager.incRollbackCount();
1273:
1274:                // Clear tables refering to external objects.
1275:                // Even if a client holds on to this instance forever, the objects
1276:                // that we have referenced may be garbage collected.
1277:                sync = null;
1278:                resources = null;
1279:                transactionLocalMap.clear();
1280:                threads.clear();
1281:
1282:                // Garbage collection
1283:                manager.releaseTransactionImpl(this );
1284:
1285:                // Set the status
1286:                status = Status.STATUS_NO_TRANSACTION;
1287:
1288:                // Notify all threads waiting for the lock.
1289:                notifyAll();
1290:
1291:                // set the done flag
1292:                done = true;
1293:            }
1294:
1295:            /**
1296:             *  Cancel the timeout.
1297:             *  This will release the lock while calling out.
1298:             */
1299:            private void cancelTimeout() {
1300:                if (timeout != null) {
1301:                    unlock();
1302:                    try {
1303:                        timeout.cancel();
1304:                    } catch (Exception e) {
1305:                        if (trace)
1306:                            log.trace("failed to cancel timeout " + this , e);
1307:                    } finally {
1308:                        lock();
1309:                    }
1310:                    timeout = null;
1311:                }
1312:            }
1313:
1314:            /**
1315:             *  Return the resource for the given XAResource 
1316:             */
1317:            private Resource findResource(XAResource xaRes) {
1318:                // A linear search may seem slow, but please note that
1319:                // the number of XA resources registered with a transaction
1320:                // are usually low.
1321:                // Note: This searches backwards intentionally!  It ensures that
1322:                // if this resource was enlisted multiple times, then the last one
1323:                // will be returned.  All others should be in the state RS_ENDED.
1324:                // This allows ResourceManagers that always return false from isSameRM
1325:                // to be enlisted and delisted multiple times.
1326:                for (int idx = resources.size() - 1; idx >= 0; --idx) {
1327:                    Resource resource = (Resource) resources.get(idx);
1328:                    if (xaRes == resource.getXAResource())
1329:                        return resource;
1330:                }
1331:
1332:                return null;
1333:            }
1334:
1335:            private Resource findResourceManager(XAResource xaRes)
1336:                    throws XAException {
1337:                for (int i = 0; i < resources.size(); ++i) {
1338:                    Resource resource = (Resource) resources.get(i);
1339:                    if (resource.isResourceManager(xaRes))
1340:                        return resource;
1341:                }
1342:                return null;
1343:            }
1344:
1345:            /**
1346:             *  Add a resource, expanding tables if needed.
1347:             *
1348:             *  @param xaRes The new XA resource to add. It is assumed that the
1349:             *         resource is not already in the table of XA resources.
1350:             *  @param branchXid The Xid for the transaction branch that is to
1351:             *         be used for associating with this resource.
1352:             *  @param sameRMResource The resource of the first
1353:             *         XA resource having the same resource manager as
1354:             *         <code>xaRes</code>, or <code>null</code> if <code>xaRes</code>
1355:             *         is the first resource seen with this resource manager.
1356:             *
1357:             *  @return the new resource
1358:             */
1359:            private Resource addResource(XAResource xaRes, Xid branchXid,
1360:                    Resource sameRMResource) {
1361:                Resource resource = new Resource(xaRes, branchXid,
1362:                        sameRMResource);
1363:                resources.add(resource);
1364:
1365:                // Remember the first resource that wants the last resource gambit
1366:                if (lastResource == null && xaRes instanceof  LastResource)
1367:                    lastResource = resource;
1368:
1369:                return resource;
1370:            }
1371:
1372:            /**
1373:             *  End Tx association for all resources.
1374:             */
1375:            private void endResources() {
1376:                for (int idx = 0; idx < resources.size(); ++idx) {
1377:                    Resource resource = (Resource) resources.get(idx);
1378:                    try {
1379:                        resource.endResource();
1380:                    } catch (XAException xae) {
1381:                        logXAException(xae);
1382:                        status = Status.STATUS_MARKED_ROLLBACK;
1383:                        cause = xae;
1384:                    }
1385:                }
1386:                resourcesEnded = true; // Too late to enlist new resources.
1387:            }
1388:
1389:            /**
1390:             *  Call synchronization <code>beforeCompletion()</code>.
1391:             *  This will release the lock while calling out.
1392:             */
1393:            private void doBeforeCompletion() {
1394:                unlock();
1395:                try {
1396:                    for (int i = 0; i < syncCount; i++) {
1397:                        try {
1398:                            if (trace)
1399:                                log.trace("calling sync " + i + ", " + sync[i]
1400:                                        + " tx=" + this );
1401:
1402:                            sync[i].beforeCompletion();
1403:                        } catch (Throwable t) {
1404:                            if (trace)
1405:                                log.trace(
1406:                                        "failed before completion " + sync[i],
1407:                                        t);
1408:
1409:                            status = Status.STATUS_MARKED_ROLLBACK;
1410:
1411:                            // save the cause off so the user can inspect it
1412:                            cause = t;
1413:                            break;
1414:                        }
1415:                    }
1416:                } finally {
1417:                    lock();
1418:                }
1419:            }
1420:
1421:            /**
1422:             *  Call synchronization <code>afterCompletion()</code>.
1423:             *  This will release the lock while calling out.
1424:             */
1425:            private void doAfterCompletion() {
1426:                // Assert: Status indicates: Too late to add new synchronizations.
1427:                unlock();
1428:                try {
1429:                    for (int i = 0; i < syncCount; i++) {
1430:                        try {
1431:                            sync[i].afterCompletion(status);
1432:                        } catch (Throwable t) {
1433:                            if (trace)
1434:                                log.trace("failed after completion " + sync[i],
1435:                                        t);
1436:                        }
1437:                    }
1438:                } finally {
1439:                    lock();
1440:                }
1441:            }
1442:
1443:            /**
1444:             *  We got another heuristic.
1445:             *
1446:             *  Promote <code>heuristicCode</code> if needed and tell
1447:             *  the resource to forget the heuristic.
1448:             *  This will release the lock while calling out.
1449:             *
1450:             *  @param resource The resource of the XA resource that got a
1451:             *         heurictic in our internal tables, or <code>null</code>
1452:             *         if the heuristic came from here.
1453:             *  @param code The heuristic code, one of
1454:             *         <code>XAException.XA_HEURxxx</code>.
1455:             */
1456:            private void gotHeuristic(Resource resource, int code) {
1457:                switch (code) {
1458:                case XAException.XA_HEURMIX:
1459:                    heuristicCode = XAException.XA_HEURMIX;
1460:                    break;
1461:                case XAException.XA_HEURRB:
1462:                    if (heuristicCode == HEUR_NONE)
1463:                        heuristicCode = XAException.XA_HEURRB;
1464:                    else if (heuristicCode == XAException.XA_HEURCOM
1465:                            || heuristicCode == XAException.XA_HEURHAZ)
1466:                        heuristicCode = XAException.XA_HEURMIX;
1467:                    break;
1468:                case XAException.XA_HEURCOM:
1469:                    if (heuristicCode == HEUR_NONE)
1470:                        heuristicCode = XAException.XA_HEURCOM;
1471:                    else if (heuristicCode == XAException.XA_HEURRB
1472:                            || heuristicCode == XAException.XA_HEURHAZ)
1473:                        heuristicCode = XAException.XA_HEURMIX;
1474:                    break;
1475:                case XAException.XA_HEURHAZ:
1476:                    if (heuristicCode == HEUR_NONE)
1477:                        heuristicCode = XAException.XA_HEURHAZ;
1478:                    else if (heuristicCode == XAException.XA_HEURCOM
1479:                            || heuristicCode == XAException.XA_HEURRB)
1480:                        heuristicCode = XAException.XA_HEURMIX;
1481:                    break;
1482:                default:
1483:                    throw new IllegalArgumentException();
1484:                }
1485:
1486:                if (resource != null)
1487:                    resource.forget();
1488:            }
1489:
1490:            /**
1491:             *  Check for heuristics, clear and throw exception if any found.
1492:             */
1493:            private void checkHeuristics() throws HeuristicMixedException,
1494:                    HeuristicRollbackException {
1495:                switch (heuristicCode) {
1496:                case XAException.XA_HEURHAZ:
1497:                case XAException.XA_HEURMIX:
1498:                    heuristicCode = HEUR_NONE;
1499:                    if (trace)
1500:                        log.trace("Throwing HeuristicMixedException, tx="
1501:                                + this  + "status=" + getStringStatus(status));
1502:                    throw new HeuristicMixedException();
1503:                case XAException.XA_HEURRB:
1504:                    heuristicCode = HEUR_NONE;
1505:                    if (trace)
1506:                        log.trace("Throwing HeuristicRollbackException, tx="
1507:                                + this  + "status=" + getStringStatus(status));
1508:                    throw new HeuristicRollbackException();
1509:                case XAException.XA_HEURCOM:
1510:                    heuristicCode = HEUR_NONE;
1511:                    // Why isn't HeuristicCommitException used in JTA ?
1512:                    // And why define something that is not used ?
1513:                    // For now we just have to ignore this failure, even if it happened
1514:                    // on rollback.
1515:                    if (trace)
1516:                        log.trace("NOT Throwing HeuristicCommitException, tx="
1517:                                + this  + "status=" + getStringStatus(status));
1518:                    return;
1519:                }
1520:            }
1521:
1522:            /**
1523:             *  Prepare all enlisted resources.
1524:             *  If the first phase of the commit process results in a decision
1525:             *  to commit the <code>status</code> will be
1526:             *  <code>Status.STATUS_PREPARED</code> on return.
1527:             *  Otherwise the <code>status</code> will be
1528:             *  <code>Status.STATUS_MARKED_ROLLBACK</code> on return.
1529:             *  This will release the lock while calling out.
1530:             *
1531:             *  @return True iff all resources voted read-only.
1532:             */
1533:            private boolean prepareResources() {
1534:                boolean readOnly = true;
1535:
1536:                status = Status.STATUS_PREPARING;
1537:
1538:                // Prepare te XAResources   
1539:                for (int i = 0; i < resources.size(); ++i) {
1540:                    // Abort prepare on state change.
1541:                    if (status != Status.STATUS_PREPARING)
1542:                        return false;
1543:
1544:                    Resource resource = (Resource) resources.get(i);
1545:
1546:                    if (resource.isResourceManager() == false)
1547:                        continue; // This RM already prepared.
1548:
1549:                    // Ignore the last resource it is done later
1550:                    if (resource == lastResource)
1551:                        continue;
1552:
1553:                    try {
1554:                        int vote = resource.prepare();
1555:
1556:                        if (vote == RS_VOTE_OK)
1557:                            readOnly = false;
1558:                        else if (vote != RS_VOTE_READONLY) {
1559:                            // Illegal vote: rollback.
1560:                            if (trace)
1561:                                log.trace(
1562:                                        "illegal vote in prepare resources tx="
1563:                                                + this  + " resource="
1564:                                                + resource, new Exception());
1565:                            status = Status.STATUS_MARKED_ROLLBACK;
1566:                            return false;
1567:                        }
1568:                    } catch (XAException e) {
1569:                        readOnly = false;
1570:
1571:                        logXAException(e);
1572:
1573:                        switch (e.errorCode) {
1574:                        case XAException.XA_HEURCOM:
1575:                            // Heuristic commit is not that bad when preparing.
1576:                            // But it means trouble if we have to rollback.
1577:                            gotHeuristic(resource, e.errorCode);
1578:                            break;
1579:                        case XAException.XA_HEURRB:
1580:                        case XAException.XA_HEURMIX:
1581:                        case XAException.XA_HEURHAZ:
1582:                            gotHeuristic(resource, e.errorCode);
1583:                            if (status == Status.STATUS_PREPARING)
1584:                                status = Status.STATUS_MARKED_ROLLBACK;
1585:                            break;
1586:                        default:
1587:                            cause = e;
1588:                            if (status == Status.STATUS_PREPARING)
1589:                                status = Status.STATUS_MARKED_ROLLBACK;
1590:                            break;
1591:                        }
1592:                    } catch (Throwable t) {
1593:                        if (trace)
1594:                            log.trace(
1595:                                    "unhandled throwable in prepareResources "
1596:                                            + this , t);
1597:                        if (status == Status.STATUS_PREPARING)
1598:                            status = Status.STATUS_MARKED_ROLLBACK;
1599:                        cause = t;
1600:                    }
1601:                }
1602:
1603:                // Abort prepare on state change.
1604:                if (status != Status.STATUS_PREPARING)
1605:                    return false;
1606:
1607:                // Are we doing the last resource gambit?
1608:                if (lastResource != null) {
1609:                    try {
1610:                        lastResource.prepareLastResource();
1611:                        lastResource.commit(false);
1612:                    } catch (XAException e) {
1613:                        logXAException(e);
1614:                        switch (e.errorCode) {
1615:                        case XAException.XA_HEURRB:
1616:                        case XAException.XA_HEURCOM:
1617:                        case XAException.XA_HEURMIX:
1618:                        case XAException.XA_HEURHAZ:
1619:                            //usually throws an exception, but not for a couple of cases.
1620:                            gotHeuristic(lastResource, e.errorCode);
1621:                            if (status == Status.STATUS_PREPARING)
1622:                                status = Status.STATUS_MARKED_ROLLBACK;
1623:                            break;
1624:                        default:
1625:                            cause = e;
1626:                            if (status == Status.STATUS_PREPARING)
1627:                                status = Status.STATUS_MARKED_ROLLBACK;
1628:                            break;
1629:                        }
1630:                    } catch (Throwable t) {
1631:                        if (trace)
1632:                            log.trace(
1633:                                    "unhandled throwable in prepareResources "
1634:                                            + this , t);
1635:                        if (status == Status.STATUS_PREPARING)
1636:                            status = Status.STATUS_MARKED_ROLLBACK;
1637:                        cause = t;
1638:                    }
1639:                }
1640:
1641:                if (status == Status.STATUS_PREPARING)
1642:                    status = Status.STATUS_PREPARED;
1643:                else
1644:                    return false;
1645:
1646:                return readOnly;
1647:            }
1648:
1649:            /**
1650:             *  Commit all enlisted resources.
1651:             *  This will release the lock while calling out.
1652:             */
1653:            private void commitResources(boolean onePhase) {
1654:                status = Status.STATUS_COMMITTING;
1655:
1656:                for (int i = 0; i < resources.size(); ++i) {
1657:
1658:                    // Abort commit on state change.
1659:                    if (status != Status.STATUS_COMMITTING)
1660:                        return;
1661:
1662:                    Resource resource = (Resource) resources.get(i);
1663:
1664:                    // Ignore the last resource, it is already committed
1665:                    if (onePhase == false && lastResource == resource)
1666:                        continue;
1667:
1668:                    try {
1669:                        resource.commit(onePhase);
1670:                    } catch (XAException e) {
1671:                        logXAException(e);
1672:                        switch (e.errorCode) {
1673:                        case XAException.XA_HEURRB:
1674:                        case XAException.XA_HEURCOM:
1675:                        case XAException.XA_HEURMIX:
1676:                        case XAException.XA_HEURHAZ:
1677:                            //usually throws an exception, but not for a couple of cases.
1678:                            gotHeuristic(resource, e.errorCode);
1679:                            //May not be correct for HEURCOM
1680:                            //Two phase commit is committed after prepare is logged.
1681:                            if (onePhase)
1682:                                status = Status.STATUS_MARKED_ROLLBACK;
1683:
1684:                            break;
1685:                        default:
1686:                            cause = e;
1687:                            if (onePhase) {
1688:                                status = Status.STATUS_MARKED_ROLLBACK;
1689:                                break;
1690:                            }
1691:                            //Not much we can do if there is an RMERR in the
1692:                            //commit phase of 2pc. I guess we try the other rms.
1693:                        }
1694:                    } catch (Throwable t) {
1695:                        if (trace)
1696:                            log.trace("unhandled throwable in commitResources "
1697:                                    + this , t);
1698:                    }
1699:                }
1700:
1701:                if (status == Status.STATUS_COMMITTING)
1702:                    status = Status.STATUS_COMMITTED;
1703:            }
1704:
1705:            /**
1706:             *  Rollback all enlisted resources.
1707:             *  This will release the lock while calling out.
1708:             */
1709:            private void rollbackResources() {
1710:                status = Status.STATUS_ROLLING_BACK;
1711:
1712:                for (int i = 0; i < resources.size(); ++i) {
1713:                    Resource resource = (Resource) resources.get(i);
1714:                    try {
1715:                        resource.rollback();
1716:                    } catch (XAException e) {
1717:                        logXAException(e);
1718:                        switch (e.errorCode) {
1719:                        case XAException.XA_HEURRB:
1720:                            // Heuristic rollback is not that bad when rolling back.
1721:                            gotHeuristic(resource, e.errorCode);
1722:                            continue;
1723:                        case XAException.XA_HEURCOM:
1724:                        case XAException.XA_HEURMIX:
1725:                        case XAException.XA_HEURHAZ:
1726:                            gotHeuristic(resource, e.errorCode);
1727:                            continue;
1728:                        default:
1729:                            cause = e;
1730:                            break;
1731:                        }
1732:                    } catch (Throwable t) {
1733:                        if (trace)
1734:                            log.trace(
1735:                                    "unhandled throwable in rollbackResources "
1736:                                            + this , t);
1737:                    }
1738:                }
1739:
1740:                status = Status.STATUS_ROLLEDBACK;
1741:            }
1742:
1743:            /**
1744:             *  Create an Xid representing a new branch of this transaction.
1745:             */
1746:            private Xid createXidBranch() {
1747:                long branchId = ++lastBranchId;
1748:
1749:                return xidFactory.newBranch(xid, branchId);
1750:            }
1751:
1752:            /**
1753:             * Determine the commit strategy
1754:             * 
1755:             * @return 0 for nothing to do, 1 for one phase and 2 for two phase
1756:             */
1757:            private int getCommitStrategy() {
1758:                int resourceCount = resources.size();
1759:
1760:                if (resourceCount == 0)
1761:                    return 0;
1762:
1763:                if (resourceCount == 1)
1764:                    return 1;
1765:
1766:                // first XAResource surely has -1, it's the first!
1767:                for (int i = 1; i < resourceCount; ++i) {
1768:                    Resource resource = (Resource) resources.get(i);
1769:                    if (resource.isResourceManager()) {
1770:                        // this one is not the same rm as previous ones,
1771:                        // there must be at least 2
1772:                        return 2;
1773:                    }
1774:
1775:                }
1776:                // all rms are the same one, one phase commit is ok.
1777:                return 1;
1778:            }
1779:
1780:            public long getTimeLeftBeforeTimeout(boolean errorRollback)
1781:                    throws RollbackException {
1782:                if (errorRollback && status != Status.STATUS_ACTIVE)
1783:                    throw new RollbackException("Transaction is not active: "
1784:                            + TxUtils.getStatusAsString(status));
1785:                return (start + timeoutPeriod) - System.currentTimeMillis();
1786:            }
1787:
1788:            Object getTransactionLocalValue(TransactionLocal tlocal) {
1789:                return transactionLocalMap.get(tlocal);
1790:            }
1791:
1792:            void putTransactionLocalValue(TransactionLocal tlocal, Object value) {
1793:                transactionLocalMap.put(tlocal, value);
1794:            }
1795:
1796:            boolean containsTransactionLocal(TransactionLocal tlocal) {
1797:                return transactionLocalMap.containsKey(tlocal);
1798:            }
1799:
1800:            /**
1801:             * Check we have no outstanding work
1802:             * 
1803:             * @throws IllegalStateException when there is still work
1804:             */
1805:            private void checkWork() {
1806:                if (work != null)
1807:                    throw new IllegalStateException("Work still outstanding "
1808:                            + work + " tx=" + this );
1809:            }
1810:
1811:            // Inner classes -------------------------------------------------
1812:
1813:            /**
1814:             * Represents a resource enlisted in the transaction
1815:             */
1816:            private class Resource {
1817:                /** The XAResource */
1818:                private XAResource xaResource;
1819:
1820:                /** The state of the resources */
1821:                private int resourceState;
1822:
1823:                /** The related xa resource from the same resource manager */
1824:                private Resource resourceSameRM;
1825:
1826:                /** The Xid of this resource */
1827:                private Xid resourceXid;
1828:
1829:                /**
1830:                 * Create a new resource
1831:                 */
1832:                public Resource(XAResource xaResource, Xid resourceXid,
1833:                        Resource resourceSameRM) {
1834:                    this .xaResource = xaResource;
1835:                    this .resourceXid = resourceXid;
1836:                    this .resourceSameRM = resourceSameRM;
1837:                    resourceState = RS_NEW;
1838:                }
1839:
1840:                /**
1841:                 * Get the XAResource for this resource
1842:                 */
1843:                public XAResource getXAResource() {
1844:                    return xaResource;
1845:                }
1846:
1847:                /**
1848:                 * Get the Xid for this resource
1849:                 */
1850:                public Xid getXid() {
1851:                    return resourceXid;
1852:                }
1853:
1854:                /**
1855:                 * Is the resource enlisted?
1856:                 */
1857:                public boolean isEnlisted() {
1858:                    return resourceState == RS_ENLISTED;
1859:                }
1860:
1861:                /**
1862:                 * Is this a resource manager
1863:                 */
1864:                public boolean isResourceManager() {
1865:                    return resourceSameRM == null;
1866:                }
1867:
1868:                /**
1869:                 * Is this the resource manager for the passed xa resource
1870:                 */
1871:                public boolean isResourceManager(XAResource xaRes)
1872:                        throws XAException {
1873:                    return resourceSameRM == null && xaRes.isSameRM(xaResource);
1874:                }
1875:
1876:                /**
1877:                 * Is the resource delisted and the XAResource always returns false
1878:                 * for isSameRM
1879:                 */
1880:                public boolean isDelisted(XAResource xaRes) throws XAException {
1881:                    return resourceState == RS_ENDED
1882:                            && xaResource.isSameRM(xaRes) == false;
1883:                }
1884:
1885:                /**
1886:                 * Call <code>start()</code> on a XAResource and update
1887:                 * internal state information.
1888:                 * This will release the lock while calling out.
1889:                 * 
1890:                 * @return when started, false otherwise 
1891:                 */
1892:                public boolean startResource() throws XAException {
1893:                    int flags = XAResource.TMJOIN;
1894:
1895:                    if (resourceSameRM == null) {
1896:                        switch (resourceState) {
1897:                        case RS_NEW:
1898:                            flags = XAResource.TMNOFLAGS;
1899:                            break;
1900:                        case RS_SUSPENDED:
1901:                            flags = XAResource.TMRESUME;
1902:                            break;
1903:
1904:                        default:
1905:                            if (trace)
1906:                                log
1907:                                        .trace("Unhandled resource state: "
1908:                                                + resourceState
1909:                                                + " (not RS_NEW or RS_SUSPENDED, using TMJOIN flags)");
1910:                        }
1911:                    }
1912:
1913:                    if (trace)
1914:                        log.trace("startResource("
1915:                                + xidFactory.toString(resourceXid)
1916:                                + ") entered: " + xaResource.toString()
1917:                                + " flags=" + flags);
1918:
1919:                    unlock();
1920:                    // OSH FIXME: resourceState could be incorrect during this callout.
1921:                    try {
1922:                        try {
1923:                            xaResource.start(resourceXid, flags);
1924:                        } catch (XAException e) {
1925:                            throw e;
1926:                        } catch (Throwable t) {
1927:                            if (trace)
1928:                                log
1929:                                        .trace(
1930:                                                "unhandled throwable error in startResource",
1931:                                                t);
1932:                            status = Status.STATUS_MARKED_ROLLBACK;
1933:                            return false;
1934:                        }
1935:
1936:                        // Now the XA resource is associated with a transaction.
1937:                        resourceState = RS_ENLISTED;
1938:                    } finally {
1939:                        lock();
1940:                        if (trace)
1941:                            log.trace("startResource("
1942:                                    + xidFactory.toString(resourceXid)
1943:                                    + ") leaving: " + xaResource.toString()
1944:                                    + " flags=" + flags);
1945:                    }
1946:                    return true;
1947:                }
1948:
1949:                /**
1950:                 * Delist the resource unless we already did it
1951:                 */
1952:                public boolean delistResource(XAResource xaRes, int flag)
1953:                        throws XAException {
1954:                    if (isDelisted(xaRes)) {
1955:                        // This RM always returns false on isSameRM.  Further,
1956:                        // the last resource has already been delisted.
1957:                        log.warn("Resource already delisted.  tx="
1958:                                + this .toString());
1959:                        return false;
1960:                    }
1961:                    endResource(flag);
1962:                    return true;
1963:                }
1964:
1965:                /**
1966:                 * End the resource
1967:                 */
1968:                public void endResource() throws XAException {
1969:                    if (resourceState == RS_ENLISTED
1970:                            || resourceState == RS_SUSPENDED) {
1971:                        if (trace)
1972:                            log.trace("endresources(" + xaResource
1973:                                    + "): state=" + resourceState);
1974:                        endResource(XAResource.TMSUCCESS);
1975:                    }
1976:                }
1977:
1978:                /**
1979:                 *  Call <code>end()</code> on the XAResource and update
1980:                 *  internal state information.
1981:                 *  This will release the lock while calling out.
1982:                 *
1983:                 *  @param flag The flag argument for the end() call.
1984:                 */
1985:                private void endResource(int flag) throws XAException {
1986:                    if (trace)
1987:                        log.trace("endResource("
1988:                                + xidFactory.toString(resourceXid)
1989:                                + ") entered: " + xaResource.toString()
1990:                                + " flag=" + flag);
1991:
1992:                    unlock();
1993:                    // OSH FIXME: resourceState could be incorrect during this callout.
1994:                    try {
1995:                        try {
1996:                            xaResource.end(resourceXid, flag);
1997:                        } catch (XAException e) {
1998:                            throw e;
1999:                        } catch (Throwable t) {
2000:                            if (trace)
2001:                                log
2002:                                        .trace(
2003:                                                "unhandled throwable error in endResource",
2004:                                                t);
2005:                            status = Status.STATUS_MARKED_ROLLBACK;
2006:                            // Resource may or may not be ended after illegal exception.
2007:                            // We just assume it ended.
2008:                            resourceState = RS_ENDED;
2009:                            return;
2010:                        }
2011:
2012:                        // Update our internal state information
2013:                        if (flag == XAResource.TMSUSPEND)
2014:                            resourceState = RS_SUSPENDED;
2015:                        else {
2016:                            if (flag == XAResource.TMFAIL)
2017:                                status = Status.STATUS_MARKED_ROLLBACK;
2018:                            resourceState = RS_ENDED;
2019:                        }
2020:                    } finally {
2021:                        lock();
2022:                        if (trace)
2023:                            log.trace("endResource("
2024:                                    + xidFactory.toString(resourceXid)
2025:                                    + ") leaving: " + xaResource.toString()
2026:                                    + " flag=" + flag);
2027:                    }
2028:                }
2029:
2030:                /**
2031:                 * Forget the resource
2032:                 */
2033:                public void forget() {
2034:                    unlock();
2035:                    try {
2036:                        xaResource.forget(resourceXid);
2037:                    } catch (XAException xae) {
2038:                        logXAException(xae);
2039:                        cause = xae;
2040:                    } finally {
2041:                        lock();
2042:                    }
2043:                    resourceState = RS_FORGOT;
2044:                }
2045:
2046:                /**
2047:                 * Prepare the resource
2048:                 */
2049:                public int prepare() throws XAException {
2050:                    int vote;
2051:                    unlock();
2052:                    try {
2053:                        vote = xaResource.prepare(resourceXid);
2054:                    } finally {
2055:                        lock();
2056:                    }
2057:
2058:                    if (vote == XAResource.XA_OK)
2059:                        resourceState = RS_VOTE_OK;
2060:                    else if (vote == XAResource.XA_RDONLY)
2061:                        resourceState = RS_VOTE_READONLY;
2062:
2063:                    return resourceState;
2064:                }
2065:
2066:                /**
2067:                 * Prepare the last resource
2068:                 */
2069:                public void prepareLastResource() throws XAException {
2070:                    resourceState = RS_VOTE_OK;
2071:                }
2072:
2073:                /**
2074:                 * Commit the resource
2075:                 */
2076:                public void commit(boolean onePhase) throws XAException {
2077:                    if (trace)
2078:                        log.trace("Committing resource " + xaResource
2079:                                + " state=" + resourceState);
2080:
2081:                    if (!onePhase && resourceState != RS_VOTE_OK)
2082:                        return; // Voted read-only at prepare phase.
2083:
2084:                    if (resourceSameRM != null)
2085:                        return; // This RM already committed.
2086:
2087:                    unlock();
2088:                    try {
2089:                        xaResource.commit(resourceXid, onePhase);
2090:                    } finally {
2091:                        lock();
2092:                    }
2093:                }
2094:
2095:                /**
2096:                 * Rollback the resource
2097:                 */
2098:                public void rollback() throws XAException {
2099:                    if (resourceState == RS_VOTE_READONLY)
2100:                        return;
2101:                    // Already forgotten
2102:                    if (resourceState == RS_FORGOT)
2103:                        return;
2104:                    if (resourceSameRM != null)
2105:                        return; // This RM already rolled back.
2106:
2107:                    unlock();
2108:                    try {
2109:                        xaResource.rollback(resourceXid);
2110:                    } finally {
2111:                        lock();
2112:                    }
2113:                }
2114:            }
2115:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.