Source Code Cross Referenced for AbstractPlatformTransactionManager.java in  » J2EE » spring-framework-2.0.6 » org » springframework » transaction » support » 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 » J2EE » spring framework 2.0.6 » org.springframework.transaction.support 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2002-2007 the original author or authors.
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:
0017:        package org.springframework.transaction.support;
0018:
0019:        import java.io.IOException;
0020:        import java.io.ObjectInputStream;
0021:        import java.io.Serializable;
0022:        import java.util.Iterator;
0023:        import java.util.List;
0024:
0025:        import org.apache.commons.logging.Log;
0026:        import org.apache.commons.logging.LogFactory;
0027:
0028:        import org.springframework.core.Constants;
0029:        import org.springframework.transaction.IllegalTransactionStateException;
0030:        import org.springframework.transaction.InvalidTimeoutException;
0031:        import org.springframework.transaction.NestedTransactionNotSupportedException;
0032:        import org.springframework.transaction.PlatformTransactionManager;
0033:        import org.springframework.transaction.TransactionDefinition;
0034:        import org.springframework.transaction.TransactionException;
0035:        import org.springframework.transaction.TransactionStatus;
0036:        import org.springframework.transaction.TransactionSuspensionNotSupportedException;
0037:        import org.springframework.transaction.UnexpectedRollbackException;
0038:
0039:        /**
0040:         * Abstract base class that implements Spring's standard transaction workflow,
0041:         * serving as basis for concrete platform transaction managers like
0042:         * {@link org.springframework.transaction.jta.JtaTransactionManager} and
0043:         * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}.
0044:         *
0045:         * <p>This base class provides the following workflow handling:
0046:         * <ul>
0047:         * <li>determines if there is an existing transaction;
0048:         * <li>applies the appropriate propagation behavior;
0049:         * <li>suspends and resumes transactions if necessary;
0050:         * <li>checks the rollback-only flag on commit;
0051:         * <li>applies the appropriate modification on rollback
0052:         * (actual rollback or setting rollback-only);
0053:         * <li>triggers registered synchronization callbacks
0054:         * (if transaction synchronization is active).
0055:         * </ul>
0056:         *
0057:         * <p>Subclasses have to implement specific template methods for specific
0058:         * states of a transaction, e.g.: begin, suspend, resume, commit, rollback.
0059:         * The most important of them are abstract and must be provided by a concrete
0060:         * implementation; for the rest, defaults are provided, so overriding is optional.
0061:         *
0062:         * <p>Transaction synchronization is a generic mechanism for registering callbacks
0063:         * that get invoked at transaction completion time. This is mainly used internally
0064:         * by the data access support classes for JDBC, Hibernate, JDO, etc when running
0065:         * within a JTA transaction: They register resources that are opened within the
0066:         * transaction for closing at transaction completion time, allowing e.g. for reuse
0067:         * of the same Hibernate Session within the transaction. The same mechanism can
0068:         * also be leveraged for custom synchronization needs in an application.
0069:         * 
0070:         * <p>The state of this class is serializable, to allow for serializing the
0071:         * transaction strategy along with proxies that carry a transaction interceptor.
0072:         * It is up to subclasses if they wish to make their state to be serializable too.
0073:         * They should implement the <code>java.io.Serializable</code> marker interface in
0074:         * that case, and potentially a private <code>readObject()</code> method (according
0075:         * to Java serialization rules) if they need to restore any transient state.
0076:         *
0077:         * @author Juergen Hoeller
0078:         * @since 28.03.2003
0079:         * @see #setTransactionSynchronization
0080:         * @see TransactionSynchronizationManager
0081:         * @see org.springframework.transaction.jta.JtaTransactionManager
0082:         * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
0083:         * @see org.springframework.orm.hibernate.HibernateTransactionManager
0084:         */
0085:        public abstract class AbstractPlatformTransactionManager implements 
0086:                PlatformTransactionManager, Serializable {
0087:
0088:            /**
0089:             * Always activate transaction synchronization, even for "empty" transactions
0090:             * that result from PROPAGATION_SUPPORTS with no existing backend transaction.
0091:             * @see org.springframework.transaction.TransactionDefinition#PROPAGATION_SUPPORTS
0092:             * @see org.springframework.transaction.TransactionDefinition#PROPAGATION_NOT_SUPPORTED
0093:             * @see org.springframework.transaction.TransactionDefinition#PROPAGATION_NEVER
0094:             */
0095:            public static final int SYNCHRONIZATION_ALWAYS = 0;
0096:
0097:            /**
0098:             * Activate transaction synchronization only for actual transactions,
0099:             * that is, not for empty ones that result from PROPAGATION_SUPPORTS with
0100:             * no existing backend transaction.
0101:             * @see org.springframework.transaction.TransactionDefinition#PROPAGATION_REQUIRED
0102:             * @see org.springframework.transaction.TransactionDefinition#PROPAGATION_MANDATORY
0103:             * @see org.springframework.transaction.TransactionDefinition#PROPAGATION_REQUIRES_NEW
0104:             */
0105:            public static final int SYNCHRONIZATION_ON_ACTUAL_TRANSACTION = 1;
0106:
0107:            /**
0108:             * Never active transaction synchronization, not even for actual transactions.
0109:             */
0110:            public static final int SYNCHRONIZATION_NEVER = 2;
0111:
0112:            /** Constants instance for AbstractPlatformTransactionManager */
0113:            private static final Constants constants = new Constants(
0114:                    AbstractPlatformTransactionManager.class);
0115:
0116:            /** Transient to optimize serialization */
0117:            protected transient Log logger = LogFactory.getLog(getClass());
0118:
0119:            private int transactionSynchronization = SYNCHRONIZATION_ALWAYS;
0120:
0121:            private int defaultTimeout = TransactionDefinition.TIMEOUT_DEFAULT;
0122:
0123:            private boolean nestedTransactionAllowed = false;
0124:
0125:            private boolean globalRollbackOnParticipationFailure = true;
0126:
0127:            private boolean failEarlyOnGlobalRollbackOnly = false;
0128:
0129:            private boolean rollbackOnCommitFailure = false;
0130:
0131:            /**
0132:             * Set the transaction synchronization by the name of the corresponding constant
0133:             * in this class, e.g. "SYNCHRONIZATION_ALWAYS".
0134:             * @param constantName name of the constant
0135:             * @see #SYNCHRONIZATION_ALWAYS
0136:             */
0137:            public final void setTransactionSynchronizationName(
0138:                    String constantName) {
0139:                setTransactionSynchronization(constants.asNumber(constantName)
0140:                        .intValue());
0141:            }
0142:
0143:            /**
0144:             * Set when this transaction manager should activate the thread-bound
0145:             * transaction synchronization support. Default is "always".
0146:             * <p>Note that transaction synchronization isn't supported for
0147:             * multiple concurrent transactions by different transaction managers.
0148:             * Only one transaction manager is allowed to activate it at any time.
0149:             * @see #SYNCHRONIZATION_ALWAYS
0150:             * @see #SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
0151:             * @see #SYNCHRONIZATION_NEVER
0152:             * @see TransactionSynchronizationManager
0153:             * @see TransactionSynchronization
0154:             */
0155:            public final void setTransactionSynchronization(
0156:                    int transactionSynchronization) {
0157:                this .transactionSynchronization = transactionSynchronization;
0158:            }
0159:
0160:            /**
0161:             * Return if this transaction manager should activate the thread-bound
0162:             * transaction synchronization support.
0163:             */
0164:            public final int getTransactionSynchronization() {
0165:                return this .transactionSynchronization;
0166:            }
0167:
0168:            /**
0169:             * Specify the default timeout that this transaction manager should apply
0170:             * if there is no timeout specified at the transaction level, in seconds.
0171:             * <p>Default is the underlying transaction infrastructure's default timeout,
0172:             * e.g. typically 30 seconds in case of a JTA provider, indicated by the
0173:             * <code>TransactionDefinition.TIMEOUT_DEFAULT</code> value.
0174:             * @see org.springframework.transaction.TransactionDefinition#TIMEOUT_DEFAULT
0175:             */
0176:            public final void setDefaultTimeout(int defaultTimeout) {
0177:                if (defaultTimeout < TransactionDefinition.TIMEOUT_DEFAULT) {
0178:                    throw new InvalidTimeoutException(
0179:                            "Invalid default timeout", defaultTimeout);
0180:                }
0181:                this .defaultTimeout = defaultTimeout;
0182:            }
0183:
0184:            /**
0185:             * Return the default timeout that this transaction manager should apply
0186:             * if there is no timeout specified at the transaction level, in seconds.
0187:             * <p>Returns <code>TransactionDefinition.TIMEOUT_DEFAULT</code> to indicate
0188:             * the underlying transaction infrastructure's default timeout.
0189:             */
0190:            public final int getDefaultTimeout() {
0191:                return this .defaultTimeout;
0192:            }
0193:
0194:            /**
0195:             * Set whether nested transactions are allowed. Default is "false".
0196:             * <p>Typically initialized with an appropriate default by the
0197:             * concrete transaction manager subclass.
0198:             */
0199:            public final void setNestedTransactionAllowed(
0200:                    boolean nestedTransactionAllowed) {
0201:                this .nestedTransactionAllowed = nestedTransactionAllowed;
0202:            }
0203:
0204:            /**
0205:             * Return whether nested transactions are allowed.
0206:             */
0207:            public final boolean isNestedTransactionAllowed() {
0208:                return this .nestedTransactionAllowed;
0209:            }
0210:
0211:            /**
0212:             * Set whether to globally mark an existing transaction as rollback-only
0213:             * after a participating transaction failed.
0214:             * <p>Default is "true": If a participating transaction (e.g. with
0215:             * PROPAGATION_REQUIRES or PROPAGATION_SUPPORTS encountering an existing
0216:             * transaction) fails, the transaction will be globally marked as rollback-only.
0217:             * The only possible outcome of such a transaction is a rollback: The
0218:             * transaction originator <i>cannot</i> make the transaction commit anymore.
0219:             * <p>Switch this to "false" to let the transaction originator make the rollback
0220:             * decision. If a participating transaction fails with an exception, the caller
0221:             * can still decide to continue with a different path within the transaction.
0222:             * However, note that this will only work as long as all participating resources
0223:             * are capable of continuing towards a transaction commit even after a data access
0224:             * failure: This is generally not the case for a Hibernate Session, for example;
0225:             * neither is it for a sequence of JDBC insert/update/delete operations.
0226:             * <p><b>Note:</b>This flag only applies to an explicit rollback attempt for a
0227:             * subtransaction, typically caused by an exception thrown by a data access operation
0228:             * (where TransactionInterceptor will trigger a <code>PlatformTransactionManager.rollback()</code>
0229:             * call according to a rollback rule). If the flag is off, the caller can handle the exception
0230:             * and decide on a rollback, independent of the rollback rules of the subtransaction.
0231:             * This flag does, however, <i>not</i> apply to explicit <code>setRollbackOnly</code>
0232:             * calls on a <code>TransactionStatus</code>, which will always cause an eventual
0233:             * global rollback (as it might not throw an exception after the rollback-only call).
0234:             * <p>The recommended solution for handling failure of a subtransaction
0235:             * is a "nested transaction", where the global transaction can be rolled
0236:             * back to a savepoint taken at the beginning of the subtransaction.
0237:             * PROPAGATION_NESTED provides exactly those semantics; however, it will
0238:             * only work when nested transaction support is available. This is the case
0239:             * with DataSourceTransactionManager, but not with JtaTransactionManager.
0240:             * @see #setNestedTransactionAllowed
0241:             * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
0242:             * @see org.springframework.transaction.jta.JtaTransactionManager
0243:             */
0244:            public final void setGlobalRollbackOnParticipationFailure(
0245:                    boolean globalRollbackOnParticipationFailure) {
0246:                this .globalRollbackOnParticipationFailure = globalRollbackOnParticipationFailure;
0247:            }
0248:
0249:            /**
0250:             * Return whether to globally mark an existing transaction as rollback-only
0251:             * after a participating transaction failed.
0252:             */
0253:            public final boolean isGlobalRollbackOnParticipationFailure() {
0254:                return this .globalRollbackOnParticipationFailure;
0255:            }
0256:
0257:            /**
0258:             * Set whether to fail early in case of the transaction being globally marked
0259:             * as rollback-only.
0260:             * <p>Default is "false", only causing an UnexpectedRollbackException at the
0261:             * outermost transaction boundary. Switch this flag on to cause an
0262:             * UnexpectedRollbackException as early as the global rollback-only marker
0263:             * has been first detected, even from within an inner transaction boundary.
0264:             * <p>Note that, as of Spring 2.0, the fail-early behavior for global
0265:             * rollback-only markers has been unified: All transaction managers will by
0266:             * default only cause UnexpectedRollbackException at the outermost transaction
0267:             * boundary. This allows, for example, to continue unit tests even after an
0268:             * operation failed and the transaction will never be completed. All transaction
0269:             * managers will only fail earlier if this flag has explicitly been set to "true".
0270:             * @see org.springframework.transaction.UnexpectedRollbackException
0271:             */
0272:            public final void setFailEarlyOnGlobalRollbackOnly(
0273:                    boolean failEarlyOnGlobalRollbackOnly) {
0274:                this .failEarlyOnGlobalRollbackOnly = failEarlyOnGlobalRollbackOnly;
0275:            }
0276:
0277:            /**
0278:             * Return whether to fail early in case of the transaction being globally marked
0279:             * as rollback-only.
0280:             */
0281:            public final boolean isFailEarlyOnGlobalRollbackOnly() {
0282:                return this .failEarlyOnGlobalRollbackOnly;
0283:            }
0284:
0285:            /**
0286:             * Set whether <code>doRollback</code> should be performed on failure of the
0287:             * <code>doCommit</code> call. Typically not necessary and thus to be avoided,
0288:             * as it can potentially override the commit exception with a subsequent
0289:             * rollback exception.
0290:             * <p>Default is "false".
0291:             * @see #doCommit
0292:             * @see #doRollback
0293:             */
0294:            public final void setRollbackOnCommitFailure(
0295:                    boolean rollbackOnCommitFailure) {
0296:                this .rollbackOnCommitFailure = rollbackOnCommitFailure;
0297:            }
0298:
0299:            /**
0300:             * Return whether <code>doRollback</code> should be performed on failure of the
0301:             * <code>doCommit</code> call.
0302:             */
0303:            public final boolean isRollbackOnCommitFailure() {
0304:                return this .rollbackOnCommitFailure;
0305:            }
0306:
0307:            //---------------------------------------------------------------------
0308:            // Implementation of PlatformTransactionManager
0309:            //---------------------------------------------------------------------
0310:
0311:            /**
0312:             * This implementation handles propagation behavior. Delegates to
0313:             * <code>doGetTransaction</code>, <code>isExistingTransaction</code>
0314:             * and <code>doBegin</code>.
0315:             * @see #doGetTransaction
0316:             * @see #isExistingTransaction
0317:             * @see #doBegin
0318:             */
0319:            public final TransactionStatus getTransaction(
0320:                    TransactionDefinition definition)
0321:                    throws TransactionException {
0322:                Object transaction = doGetTransaction();
0323:
0324:                // Cache debug flag to avoid repeated checks.
0325:                boolean debugEnabled = logger.isDebugEnabled();
0326:                if (debugEnabled) {
0327:                    logger.debug("Using transaction object [" + transaction
0328:                            + "]");
0329:                }
0330:
0331:                if (definition == null) {
0332:                    // Use defaults if no transaction definition given.
0333:                    definition = new DefaultTransactionDefinition();
0334:                }
0335:
0336:                if (isExistingTransaction(transaction)) {
0337:                    // Existing transaction found -> check propagation behavior to find out how to behave.
0338:                    return handleExistingTransaction(definition, transaction,
0339:                            debugEnabled);
0340:                }
0341:
0342:                // Check definition settings for new transaction.
0343:                if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
0344:                    throw new InvalidTimeoutException(
0345:                            "Invalid transaction timeout", definition
0346:                                    .getTimeout());
0347:                }
0348:
0349:                // No existing transaction found -> check propagation behavior to find out how to proceed.
0350:                if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
0351:                    throw new IllegalTransactionStateException(
0352:                            "No existing transaction found for transaction marked with propagation 'mandatory'");
0353:                } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED
0354:                        || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW
0355:                        || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
0356:                    SuspendedResourcesHolder suspendedResources = suspend(null);
0357:                    if (debugEnabled) {
0358:                        logger.debug("Creating new transaction with name ["
0359:                                + definition.getName() + "]: " + definition);
0360:                    }
0361:                    try {
0362:                        doBegin(transaction, definition);
0363:                    } catch (TransactionException ex) {
0364:                        resume(null, suspendedResources);
0365:                        throw ex;
0366:                    }
0367:                    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
0368:                    return newTransactionStatus(definition, transaction, true,
0369:                            newSynchronization, debugEnabled,
0370:                            suspendedResources);
0371:                } else {
0372:                    // Create "empty" transaction: no actual transaction, but potentially synchronization.
0373:                    boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
0374:                    return newTransactionStatus(definition, null, true,
0375:                            newSynchronization, debugEnabled, null);
0376:                }
0377:            }
0378:
0379:            /**
0380:             * Create a TransactionStatus for an existing transaction.
0381:             */
0382:            private TransactionStatus handleExistingTransaction(
0383:                    TransactionDefinition definition, Object transaction,
0384:                    boolean debugEnabled) throws TransactionException {
0385:
0386:                if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
0387:                    throw new IllegalTransactionStateException(
0388:                            "Existing transaction found for transaction marked with propagation 'never'");
0389:                }
0390:
0391:                if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
0392:                    if (debugEnabled) {
0393:                        logger.debug("Suspending current transaction");
0394:                    }
0395:                    Object suspendedResources = suspend(transaction);
0396:                    boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
0397:                    return newTransactionStatus(definition, null, false,
0398:                            newSynchronization, debugEnabled,
0399:                            suspendedResources);
0400:                }
0401:
0402:                if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
0403:                    if (debugEnabled) {
0404:                        logger
0405:                                .debug("Suspending current transaction, creating new transaction with name ["
0406:                                        + definition.getName() + "]");
0407:                    }
0408:                    SuspendedResourcesHolder suspendedResources = suspend(transaction);
0409:                    try {
0410:                        doBegin(transaction, definition);
0411:                    } catch (TransactionException beginEx) {
0412:                        try {
0413:                            resume(transaction, suspendedResources);
0414:                        } catch (TransactionException resumeEx) {
0415:                            logger
0416:                                    .error(
0417:                                            "Inner transaction begin exception overridden by outer transaction resume exception",
0418:                                            beginEx);
0419:                            throw resumeEx;
0420:                        }
0421:                        throw beginEx;
0422:                    }
0423:                    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
0424:                    return newTransactionStatus(definition, transaction, true,
0425:                            newSynchronization, debugEnabled,
0426:                            suspendedResources);
0427:                }
0428:
0429:                if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
0430:                    if (!isNestedTransactionAllowed()) {
0431:                        throw new NestedTransactionNotSupportedException(
0432:                                "Transaction manager does not allow nested transactions by default - "
0433:                                        + "specify 'nestedTransactionAllowed' property with value 'true'");
0434:                    }
0435:                    if (debugEnabled) {
0436:                        logger.debug("Creating nested transaction with name ["
0437:                                + definition.getName() + "]");
0438:                    }
0439:                    if (useSavepointForNestedTransaction()) {
0440:                        // Create savepoint within existing Spring-managed transaction,
0441:                        // through the SavepointManager API implemented by TransactionStatus.
0442:                        // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
0443:                        DefaultTransactionStatus status = newTransactionStatus(
0444:                                definition, transaction, false, false,
0445:                                debugEnabled, null);
0446:                        status.createAndHoldSavepoint();
0447:                        return status;
0448:                    } else {
0449:                        // Nested transaction through nested begin and commit/rollback calls.
0450:                        // Usually only for JTA: Spring synchronization might get activated here
0451:                        // in case of a pre-existing JTA transaction.
0452:                        doBegin(transaction, definition);
0453:                        boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
0454:                        return newTransactionStatus(definition, transaction,
0455:                                true, newSynchronization, debugEnabled, null);
0456:                    }
0457:                }
0458:
0459:                // Assumably PROPAGATION_SUPPORTS.
0460:                if (debugEnabled) {
0461:                    logger.debug("Participating in existing transaction");
0462:                }
0463:                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
0464:                return newTransactionStatus(definition, transaction, false,
0465:                        newSynchronization, debugEnabled, null);
0466:            }
0467:
0468:            /**
0469:             * Create a new TransactionStatus for the given arguments,
0470:             * initializing transaction synchronization as appropriate.
0471:             */
0472:            protected DefaultTransactionStatus newTransactionStatus(
0473:                    TransactionDefinition definition, Object transaction,
0474:                    boolean newTransaction, boolean newSynchronization,
0475:                    boolean debug, Object suspendedResources) {
0476:
0477:                boolean actualNewSynchronization = newSynchronization
0478:                        && !TransactionSynchronizationManager
0479:                                .isSynchronizationActive();
0480:                if (actualNewSynchronization) {
0481:                    TransactionSynchronizationManager
0482:                            .setActualTransactionActive(transaction != null);
0483:                    TransactionSynchronizationManager
0484:                            .setCurrentTransactionIsolationLevel((definition
0485:                                    .getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) ? new Integer(
0486:                                    definition.getIsolationLevel())
0487:                                    : null);
0488:                    TransactionSynchronizationManager
0489:                            .setCurrentTransactionReadOnly(definition
0490:                                    .isReadOnly());
0491:                    TransactionSynchronizationManager
0492:                            .setCurrentTransactionName(definition.getName());
0493:                    TransactionSynchronizationManager.initSynchronization();
0494:                }
0495:                return new DefaultTransactionStatus(transaction,
0496:                        newTransaction, actualNewSynchronization, definition
0497:                                .isReadOnly(), debug, suspendedResources);
0498:            }
0499:
0500:            /**
0501:             * Determine the actual timeout to use for the given definition.
0502:             * Will fall back to this manager's default timeout if the
0503:             * transaction definition doesn't specify a non-default value.
0504:             * @param definition the transaction definition
0505:             * @return the actual timeout to use
0506:             * @see org.springframework.transaction.TransactionDefinition#getTimeout()
0507:             * @see #setDefaultTimeout
0508:             */
0509:            protected int determineTimeout(TransactionDefinition definition) {
0510:                if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
0511:                    return definition.getTimeout();
0512:                }
0513:                return this .defaultTimeout;
0514:            }
0515:
0516:            /**
0517:             * Suspend the given transaction. Suspends transaction synchronization first,
0518:             * then delegates to the <code>doSuspend</code> template method.
0519:             * @param transaction the current transaction object
0520:             * (or <code>null</code> to just suspend active synchronizations, if any)
0521:             * @return an object that holds suspended resources
0522:             * (or <code>null</code> if neither transaction nor synchronization active)
0523:             * @see #doSuspend
0524:             * @see #resume
0525:             */
0526:            protected final SuspendedResourcesHolder suspend(Object transaction)
0527:                    throws TransactionException {
0528:                if (TransactionSynchronizationManager.isSynchronizationActive()) {
0529:                    List suspendedSynchronizations = doSuspendSynchronization();
0530:                    try {
0531:                        Object suspendedResources = null;
0532:                        if (transaction != null) {
0533:                            suspendedResources = doSuspend(transaction);
0534:                        }
0535:                        String name = TransactionSynchronizationManager
0536:                                .getCurrentTransactionName();
0537:                        TransactionSynchronizationManager
0538:                                .setCurrentTransactionName(null);
0539:                        boolean readOnly = TransactionSynchronizationManager
0540:                                .isCurrentTransactionReadOnly();
0541:                        TransactionSynchronizationManager
0542:                                .setCurrentTransactionReadOnly(false);
0543:                        Integer isolationLevel = TransactionSynchronizationManager
0544:                                .getCurrentTransactionIsolationLevel();
0545:                        TransactionSynchronizationManager
0546:                                .setCurrentTransactionIsolationLevel(null);
0547:                        boolean wasActive = TransactionSynchronizationManager
0548:                                .isActualTransactionActive();
0549:                        TransactionSynchronizationManager
0550:                                .setActualTransactionActive(false);
0551:                        return new SuspendedResourcesHolder(suspendedResources,
0552:                                suspendedSynchronizations, name, readOnly,
0553:                                isolationLevel, wasActive);
0554:                    } catch (TransactionException ex) {
0555:                        // doSuspend failed - original transaction is still active...
0556:                        doResumeSynchronization(suspendedSynchronizations);
0557:                        throw ex;
0558:                    }
0559:                } else if (transaction != null) {
0560:                    // Transaction active but no synchronization active.
0561:                    Object suspendedResources = doSuspend(transaction);
0562:                    return new SuspendedResourcesHolder(suspendedResources);
0563:                } else {
0564:                    // Neither transaction nor synchronization active.
0565:                    return null;
0566:                }
0567:            }
0568:
0569:            /**
0570:             * Resume the given transaction. Delegates to the <code>doResume</code>
0571:             * template method first, then resuming transaction synchronization.
0572:             * @param transaction the current transaction object
0573:             * @param resourcesHolder the object that holds suspended resources,
0574:             * as returned by <code>suspend</code> (or <code>null</code> to just
0575:             * resume synchronizations, if any)
0576:             * @see #doResume
0577:             * @see #suspend
0578:             */
0579:            protected final void resume(Object transaction,
0580:                    SuspendedResourcesHolder resourcesHolder)
0581:                    throws TransactionException {
0582:
0583:                if (resourcesHolder != null) {
0584:                    Object suspendedResources = resourcesHolder.suspendedResources;
0585:                    if (suspendedResources != null) {
0586:                        doResume(transaction, suspendedResources);
0587:                    }
0588:                    List suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
0589:                    if (suspendedSynchronizations != null) {
0590:                        TransactionSynchronizationManager
0591:                                .setActualTransactionActive(resourcesHolder.wasActive);
0592:                        TransactionSynchronizationManager
0593:                                .setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
0594:                        TransactionSynchronizationManager
0595:                                .setCurrentTransactionReadOnly(resourcesHolder.readOnly);
0596:                        TransactionSynchronizationManager
0597:                                .setCurrentTransactionName(resourcesHolder.name);
0598:                        doResumeSynchronization(suspendedSynchronizations);
0599:                    }
0600:                }
0601:            }
0602:
0603:            /**
0604:             * Suspend all current synchronizations and deactivate transaction
0605:             * synchronization for the current thread.
0606:             * @return the List of suspended TransactionSynchronization objects
0607:             */
0608:            private List doSuspendSynchronization() {
0609:                List suspendedSynchronizations = TransactionSynchronizationManager
0610:                        .getSynchronizations();
0611:                for (Iterator it = suspendedSynchronizations.iterator(); it
0612:                        .hasNext();) {
0613:                    ((TransactionSynchronization) it.next()).suspend();
0614:                }
0615:                TransactionSynchronizationManager.clearSynchronization();
0616:                return suspendedSynchronizations;
0617:            }
0618:
0619:            /**
0620:             * Reactivate transaction synchronization for the current thread
0621:             * and resume all given synchronizations.
0622:             * @param suspendedSynchronizations List of TransactionSynchronization objects
0623:             */
0624:            private void doResumeSynchronization(List suspendedSynchronizations) {
0625:                TransactionSynchronizationManager.initSynchronization();
0626:                for (Iterator it = suspendedSynchronizations.iterator(); it
0627:                        .hasNext();) {
0628:                    TransactionSynchronization synchronization = (TransactionSynchronization) it
0629:                            .next();
0630:                    synchronization.resume();
0631:                    TransactionSynchronizationManager
0632:                            .registerSynchronization(synchronization);
0633:                }
0634:            }
0635:
0636:            /**
0637:             * This implementation of commit handles participating in existing
0638:             * transactions and programmatic rollback requests.
0639:             * Delegates to <code>isRollbackOnly</code>, <code>doCommit</code>
0640:             * and <code>rollback</code>.
0641:             * @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
0642:             * @see #doCommit
0643:             * @see #rollback
0644:             */
0645:            public final void commit(TransactionStatus status)
0646:                    throws TransactionException {
0647:                if (status.isCompleted()) {
0648:                    throw new IllegalTransactionStateException(
0649:                            "Transaction is already completed - do not call commit or rollback more than once per transaction");
0650:                }
0651:
0652:                DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
0653:                if (defStatus.isLocalRollbackOnly()) {
0654:                    if (defStatus.isDebug()) {
0655:                        logger
0656:                                .debug("Transactional code has requested rollback");
0657:                    }
0658:                    processRollback(defStatus);
0659:                    return;
0660:                }
0661:                if (!shouldCommitOnGlobalRollbackOnly()
0662:                        && defStatus.isGlobalRollbackOnly()) {
0663:                    if (defStatus.isDebug()) {
0664:                        logger
0665:                                .debug("Global transaction is marked as rollback-only but transactional code requested commit");
0666:                    }
0667:                    processRollback(defStatus);
0668:                    // Throw UnexpectedRollbackException only at outermost transaction boundary
0669:                    // or if explicitly asked to.
0670:                    if (status.isNewTransaction()
0671:                            || isFailEarlyOnGlobalRollbackOnly()) {
0672:                        throw new UnexpectedRollbackException(
0673:                                "Transaction rolled back because it has been marked as rollback-only");
0674:                    }
0675:                    return;
0676:                }
0677:
0678:                processCommit(defStatus);
0679:            }
0680:
0681:            /**
0682:             * Process an actual commit.
0683:             * Rollback-only flags have already been checked and applied.
0684:             * @param status object representing the transaction
0685:             * @throws TransactionException in case of commit failure
0686:             */
0687:            private void processCommit(DefaultTransactionStatus status)
0688:                    throws TransactionException {
0689:                try {
0690:                    boolean beforeCompletionInvoked = false;
0691:                    try {
0692:                        triggerBeforeCommit(status);
0693:                        triggerBeforeCompletion(status);
0694:                        beforeCompletionInvoked = true;
0695:                        boolean globalRollbackOnly = false;
0696:                        if (status.isNewTransaction()
0697:                                || isFailEarlyOnGlobalRollbackOnly()) {
0698:                            globalRollbackOnly = status.isGlobalRollbackOnly();
0699:                        }
0700:                        if (status.hasSavepoint()) {
0701:                            if (status.isDebug()) {
0702:                                logger.debug("Releasing transaction savepoint");
0703:                            }
0704:                            status.releaseHeldSavepoint();
0705:                        } else if (status.isNewTransaction()) {
0706:                            if (status.isDebug()) {
0707:                                logger.debug("Initiating transaction commit");
0708:                            }
0709:                            doCommit(status);
0710:                        }
0711:                        // Throw UnexpectedRollbackException if we have a global rollback-only
0712:                        // marker but still didn't get a corresponding exception from commit.
0713:                        if (globalRollbackOnly) {
0714:                            throw new UnexpectedRollbackException(
0715:                                    "Transaction silently rolled back because it has been marked as rollback-only");
0716:                        }
0717:                    } catch (UnexpectedRollbackException ex) {
0718:                        // can only be caused by doCommit
0719:                        triggerAfterCompletion(status,
0720:                                TransactionSynchronization.STATUS_ROLLED_BACK);
0721:                        throw ex;
0722:                    } catch (TransactionException ex) {
0723:                        // can only be caused by doCommit
0724:                        if (isRollbackOnCommitFailure()) {
0725:                            doRollbackOnCommitException(status, ex);
0726:                        } else {
0727:                            triggerAfterCompletion(status,
0728:                                    TransactionSynchronization.STATUS_UNKNOWN);
0729:                        }
0730:                        throw ex;
0731:                    } catch (RuntimeException ex) {
0732:                        if (!beforeCompletionInvoked) {
0733:                            triggerBeforeCompletion(status);
0734:                        }
0735:                        doRollbackOnCommitException(status, ex);
0736:                        throw ex;
0737:                    } catch (Error err) {
0738:                        if (!beforeCompletionInvoked) {
0739:                            triggerBeforeCompletion(status);
0740:                        }
0741:                        doRollbackOnCommitException(status, err);
0742:                        throw err;
0743:                    }
0744:
0745:                    // Trigger afterCommit callbacks, with an exception thrown there
0746:                    // propagated to callers but the transaction still considered as committed.
0747:                    try {
0748:                        triggerAfterCommit(status);
0749:                    } finally {
0750:                        triggerAfterCompletion(status,
0751:                                TransactionSynchronization.STATUS_COMMITTED);
0752:                    }
0753:
0754:                } finally {
0755:                    cleanupAfterCompletion(status);
0756:                }
0757:            }
0758:
0759:            /**
0760:             * This implementation of rollback handles participating in existing
0761:             * transactions. Delegates to <code>doRollback</code> and
0762:             * <code>doSetRollbackOnly</code>.
0763:             * @see #doRollback
0764:             * @see #doSetRollbackOnly
0765:             */
0766:            public final void rollback(TransactionStatus status)
0767:                    throws TransactionException {
0768:                if (status.isCompleted()) {
0769:                    throw new IllegalTransactionStateException(
0770:                            "Transaction is already completed - do not call commit or rollback more than once per transaction");
0771:                }
0772:
0773:                DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
0774:                processRollback(defStatus);
0775:            }
0776:
0777:            /**
0778:             * Process an actual rollback.
0779:             * The completed flag has already been checked.
0780:             * @param status object representing the transaction
0781:             * @throws TransactionException in case of rollback failure
0782:             */
0783:            private void processRollback(DefaultTransactionStatus status) {
0784:                try {
0785:                    try {
0786:                        triggerBeforeCompletion(status);
0787:                        if (status.hasSavepoint()) {
0788:                            if (status.isDebug()) {
0789:                                logger
0790:                                        .debug("Rolling back transaction to savepoint");
0791:                            }
0792:                            status.rollbackToHeldSavepoint();
0793:                        } else if (status.isNewTransaction()) {
0794:                            if (status.isDebug()) {
0795:                                logger.debug("Initiating transaction rollback");
0796:                            }
0797:                            doRollback(status);
0798:                        } else if (status.hasTransaction()) {
0799:                            if (status.isLocalRollbackOnly()
0800:                                    || isGlobalRollbackOnParticipationFailure()) {
0801:                                if (status.isDebug()) {
0802:                                    logger
0803:                                            .debug("Participating transaction failed - marking existing transaction as rollback-only");
0804:                                }
0805:                                doSetRollbackOnly(status);
0806:                            } else {
0807:                                if (status.isDebug()) {
0808:                                    logger
0809:                                            .debug("Participating transaction failed - letting transaction originator decide on rollback");
0810:                                }
0811:                            }
0812:                        } else {
0813:                            logger
0814:                                    .debug("Should roll back transaction but cannot - no transaction available");
0815:                        }
0816:                    } catch (RuntimeException ex) {
0817:                        triggerAfterCompletion(status,
0818:                                TransactionSynchronization.STATUS_UNKNOWN);
0819:                        throw ex;
0820:                    } catch (Error err) {
0821:                        triggerAfterCompletion(status,
0822:                                TransactionSynchronization.STATUS_UNKNOWN);
0823:                        throw err;
0824:                    }
0825:                    triggerAfterCompletion(status,
0826:                            TransactionSynchronization.STATUS_ROLLED_BACK);
0827:                } finally {
0828:                    cleanupAfterCompletion(status);
0829:                }
0830:            }
0831:
0832:            /**
0833:             * Invoke <code>doRollback</code>, handling rollback exceptions properly.
0834:             * @param status object representing the transaction
0835:             * @param ex the thrown application exception or error
0836:             * @throws TransactionException in case of rollback failure
0837:             * @see #doRollback
0838:             */
0839:            private void doRollbackOnCommitException(
0840:                    DefaultTransactionStatus status, Throwable ex)
0841:                    throws TransactionException {
0842:                try {
0843:                    if (status.isNewTransaction()) {
0844:                        if (status.isDebug()) {
0845:                            logger
0846:                                    .debug(
0847:                                            "Initiating transaction rollback after commit exception",
0848:                                            ex);
0849:                        }
0850:                        doRollback(status);
0851:                    } else if (status.hasTransaction()
0852:                            && isGlobalRollbackOnParticipationFailure()) {
0853:                        if (status.isDebug()) {
0854:                            logger
0855:                                    .debug(
0856:                                            "Marking existing transaction as rollback-only after commit exception",
0857:                                            ex);
0858:                        }
0859:                        doSetRollbackOnly(status);
0860:                    }
0861:                } catch (RuntimeException rbex) {
0862:                    logger
0863:                            .error(
0864:                                    "Commit exception overridden by rollback exception",
0865:                                    ex);
0866:                    triggerAfterCompletion(status,
0867:                            TransactionSynchronization.STATUS_UNKNOWN);
0868:                    throw rbex;
0869:                } catch (Error rberr) {
0870:                    logger
0871:                            .error(
0872:                                    "Commit exception overridden by rollback exception",
0873:                                    ex);
0874:                    triggerAfterCompletion(status,
0875:                            TransactionSynchronization.STATUS_UNKNOWN);
0876:                    throw rberr;
0877:                }
0878:                triggerAfterCompletion(status,
0879:                        TransactionSynchronization.STATUS_ROLLED_BACK);
0880:            }
0881:
0882:            /**
0883:             * Trigger <code>beforeCommit</code> callbacks.
0884:             * @param status object representing the transaction
0885:             */
0886:            protected final void triggerBeforeCommit(
0887:                    DefaultTransactionStatus status) {
0888:                if (status.isNewSynchronization()) {
0889:                    if (status.isDebug()) {
0890:                        logger.debug("Triggering beforeCommit synchronization");
0891:                    }
0892:                    TransactionSynchronizationUtils.triggerBeforeCommit(status
0893:                            .isReadOnly());
0894:                }
0895:            }
0896:
0897:            /**
0898:             * Trigger <code>beforeCompletion</code> callbacks.
0899:             * @param status object representing the transaction
0900:             */
0901:            protected final void triggerBeforeCompletion(
0902:                    DefaultTransactionStatus status) {
0903:                if (status.isNewSynchronization()) {
0904:                    if (status.isDebug()) {
0905:                        logger
0906:                                .debug("Triggering beforeCompletion synchronization");
0907:                    }
0908:                    TransactionSynchronizationUtils.triggerBeforeCompletion();
0909:                }
0910:            }
0911:
0912:            /**
0913:             * Trigger <code>afterCommit</code> callbacks.
0914:             * @param status object representing the transaction
0915:             */
0916:            private void triggerAfterCommit(DefaultTransactionStatus status) {
0917:                if (status.isNewSynchronization()) {
0918:                    if (status.isDebug()) {
0919:                        logger.debug("Triggering afterCommit synchronization");
0920:                    }
0921:                    TransactionSynchronizationUtils.triggerAfterCommit();
0922:                }
0923:            }
0924:
0925:            /**
0926:             * Trigger <code>afterCompletion</code> callbacks.
0927:             * @param status object representing the transaction
0928:             * @param completionStatus completion status according to TransactionSynchronization constants
0929:             */
0930:            private void triggerAfterCompletion(
0931:                    DefaultTransactionStatus status, int completionStatus) {
0932:                if (status.isNewSynchronization()) {
0933:                    List synchronizations = TransactionSynchronizationManager
0934:                            .getSynchronizations();
0935:                    if (!status.hasTransaction() || status.isNewTransaction()) {
0936:                        if (status.isDebug()) {
0937:                            logger
0938:                                    .debug("Triggering afterCompletion synchronization");
0939:                        }
0940:                        // No transaction or new transaction for the current scope ->
0941:                        // invoke the afterCompletion callbacks immediately
0942:                        invokeAfterCompletion(synchronizations,
0943:                                completionStatus);
0944:                    } else {
0945:                        // Existing transaction that we participate in, controlled outside
0946:                        // of the scope of this Spring transaction manager -> try to register
0947:                        // an afterCompletion callback with the existing (JTA) transaction.
0948:                        registerAfterCompletionWithExistingTransaction(status
0949:                                .getTransaction(), synchronizations);
0950:                    }
0951:                }
0952:            }
0953:
0954:            /**
0955:             * Actually invoke the <code>afterCompletion</code> methods of the
0956:             * given Spring TransactionSynchronization objects.
0957:             * <p>To be called by this abstract manager itself, or by special implementations
0958:             * of the <code>registerAfterCompletionWithExistingTransaction</code> callback.
0959:             * @param synchronizations List of TransactionSynchronization objects
0960:             * @param completionStatus the completion status according to the
0961:             * constants in the TransactionSynchronization interface
0962:             * @see #registerAfterCompletionWithExistingTransaction(Object, java.util.List)
0963:             * @see TransactionSynchronization#STATUS_COMMITTED
0964:             * @see TransactionSynchronization#STATUS_ROLLED_BACK
0965:             * @see TransactionSynchronization#STATUS_UNKNOWN
0966:             */
0967:            protected final void invokeAfterCompletion(List synchronizations,
0968:                    int completionStatus) {
0969:                TransactionSynchronizationUtils.invokeAfterCompletion(
0970:                        synchronizations, completionStatus);
0971:            }
0972:
0973:            /**
0974:             * Clean up after completion, clearing synchronization if necessary,
0975:             * and invoking doCleanupAfterCompletion.
0976:             * @param status object representing the transaction
0977:             * @see #doCleanupAfterCompletion
0978:             */
0979:            private void cleanupAfterCompletion(DefaultTransactionStatus status) {
0980:                status.setCompleted();
0981:                if (status.isNewSynchronization()) {
0982:                    TransactionSynchronizationManager.clear();
0983:                }
0984:                if (status.isNewTransaction()) {
0985:                    doCleanupAfterCompletion(status.getTransaction());
0986:                }
0987:                if (status.getSuspendedResources() != null) {
0988:                    if (status.isDebug()) {
0989:                        logger.debug("Resuming suspended transaction");
0990:                    }
0991:                    resume(status.getTransaction(),
0992:                            (SuspendedResourcesHolder) status
0993:                                    .getSuspendedResources());
0994:                }
0995:            }
0996:
0997:            //---------------------------------------------------------------------
0998:            // Template methods to be implemented in subclasses
0999:            //---------------------------------------------------------------------
1000:
1001:            /**
1002:             * Return a transaction object for the current transaction state.
1003:             * <p>The returned object will usually be specific to the concrete transaction
1004:             * manager implementation, carrying corresponding transaction state in a
1005:             * modifiable fashion. This object will be passed into the other template
1006:             * methods (e.g. doBegin and doCommit), either directly or as part of a
1007:             * DefaultTransactionStatus instance.
1008:             * <p>The returned object should contain information about any existing
1009:             * transaction, that is, a transaction that has already started before the
1010:             * current <code>getTransaction</code> call on the transaction manager.
1011:             * Consequently, a <code>doGetTransaction</code> implementation will usually
1012:             * look for an existing transaction and store corresponding state in the
1013:             * returned transaction object.
1014:             * @return the current transaction object
1015:             * @throws org.springframework.transaction.CannotCreateTransactionException
1016:             * if transaction support is not available
1017:             * @throws TransactionException in case of lookup or system errors
1018:             * @see #doBegin
1019:             * @see #doCommit
1020:             * @see #doRollback
1021:             * @see DefaultTransactionStatus#getTransaction
1022:             */
1023:            protected abstract Object doGetTransaction()
1024:                    throws TransactionException;
1025:
1026:            /**
1027:             * Check if the given transaction object indicates an existing transaction
1028:             * (that is, a transaction which has already started).
1029:             * <p>The result will be evaluated according to the specified propagation
1030:             * behavior for the new transaction. An existing transaction might get
1031:             * suspended (in case of PROPAGATION_REQUIRES_NEW), or the new transaction
1032:             * might participate in the existing one (in case of PROPAGATION_REQUIRED).
1033:             * <p>The default implementation returns <code>false</code>, assuming that
1034:             * participating in existing transactions is generally not supported.
1035:             * Subclasses are of course encouraged to provide such support.
1036:             * @param transaction transaction object returned by doGetTransaction
1037:             * @return if there is an existing transaction
1038:             * @throws TransactionException in case of system errors
1039:             * @see #doGetTransaction
1040:             */
1041:            protected boolean isExistingTransaction(Object transaction)
1042:                    throws TransactionException {
1043:                return false;
1044:            }
1045:
1046:            /**
1047:             * Return whether to use a savepoint for a nested transaction.
1048:             * <p>Default is <code>true</code>, which causes delegation to DefaultTransactionStatus
1049:             * for creating and holding a savepoint. If the transaction object does not implement
1050:             * the SavepointManager interface, a NestedTransactionNotSupportedException will be
1051:             * thrown. Else, the SavepointManager will be asked to create a new savepoint to
1052:             * demarcate the start of the nested transaction.
1053:             * <p>Subclasses can override this to return <code>false</code>, causing a further
1054:             * call to <code>doBegin</code> - within the context of an already existing transaction.
1055:             * The <code>doBegin</code> implementation needs to handle this accordingly in such
1056:             * a scenario. This is appropriate for JTA, for example.
1057:             * @see DefaultTransactionStatus#createAndHoldSavepoint
1058:             * @see DefaultTransactionStatus#rollbackToHeldSavepoint
1059:             * @see DefaultTransactionStatus#releaseHeldSavepoint
1060:             * @see #doBegin
1061:             */
1062:            protected boolean useSavepointForNestedTransaction() {
1063:                return true;
1064:            }
1065:
1066:            /**
1067:             * Begin a new transaction with semantics according to the given transaction
1068:             * definition. Does not have to care about applying the propagation behavior,
1069:             * as this has already been handled by this abstract manager.
1070:             * <p>This method gets called when the transaction manager has decided to actually
1071:             * start a new transaction. Either there wasn't any transaction before, or the
1072:             * previous transaction has been suspended.
1073:             * <p>A special scenario is a nested transaction without savepoint: If
1074:             * <code>useSavepointForNestedTransaction()</code> returns "false", this method
1075:             * will be called to start a nested transaction when necessary. In such a context,
1076:             * there will be an active transaction: The implementation of this method has
1077:             * to detect this and start an appropriate nested transaction.
1078:             * @param transaction transaction object returned by <code>doGetTransaction</code>
1079:             * @param definition TransactionDefinition instance, describing propagation
1080:             * behavior, isolation level, read-only flag, timeout, and transaction name
1081:             * @throws TransactionException in case of creation or system errors
1082:             */
1083:            protected abstract void doBegin(Object transaction,
1084:                    TransactionDefinition definition)
1085:                    throws TransactionException;
1086:
1087:            /**
1088:             * Suspend the resources of the current transaction.
1089:             * Transaction synchronization will already have been suspended.
1090:             * <p>The default implementation throws a TransactionSuspensionNotSupportedException,
1091:             * assuming that transaction suspension is generally not supported.
1092:             * @param transaction transaction object returned by <code>doGetTransaction</code>
1093:             * @return an object that holds suspended resources
1094:             * (will be kept unexamined for passing it into doResume)
1095:             * @throws org.springframework.transaction.TransactionSuspensionNotSupportedException
1096:             * if suspending is not supported by the transaction manager implementation
1097:             * @throws TransactionException in case of system errors
1098:             * @see #doResume
1099:             */
1100:            protected Object doSuspend(Object transaction)
1101:                    throws TransactionException {
1102:                throw new TransactionSuspensionNotSupportedException(
1103:                        "Transaction manager [" + getClass().getName()
1104:                                + "] does not support transaction suspension");
1105:            }
1106:
1107:            /**
1108:             * Resume the resources of the current transaction.
1109:             * Transaction synchronization will be resumed afterwards.
1110:             * <p>The default implementation throws a TransactionSuspensionNotSupportedException,
1111:             * assuming that transaction suspension is generally not supported.
1112:             * @param transaction transaction object returned by <code>doGetTransaction</code>
1113:             * @param suspendedResources the object that holds suspended resources,
1114:             * as returned by doSuspend
1115:             * @throws org.springframework.transaction.TransactionSuspensionNotSupportedException
1116:             * if resuming is not supported by the transaction manager implementation
1117:             * @throws TransactionException in case of system errors
1118:             * @see #doSuspend
1119:             */
1120:            protected void doResume(Object transaction,
1121:                    Object suspendedResources) throws TransactionException {
1122:                throw new TransactionSuspensionNotSupportedException(
1123:                        "Transaction manager [" + getClass().getName()
1124:                                + "] does not support transaction suspension");
1125:            }
1126:
1127:            /**
1128:             * Return whether to call <code>doCommit</code> on a transaction that has been
1129:             * marked as rollback-only in a global fashion.
1130:             * <p>Does not apply if an application locally sets the transaction to rollback-only
1131:             * via the TransactionStatus, but only to the transaction itself being marked as
1132:             * rollback-only by the transaction coordinator.
1133:             * <p>Default is "false": Local transaction strategies usually don't hold the rollback-only
1134:             * marker in the transaction itself, therefore they can't handle rollback-only transactions
1135:             * as part of transaction commit. Hence, AbstractPlatformTransactionManager will trigger
1136:             * a rollback in that case, throwing an UnexpectedRollbackException afterwards.
1137:             * <p>Override this to return "true" if the concrete transaction manager expects a
1138:             * <code>doCommit</code> call even for a rollback-only transaction, allowing for
1139:             * special handling there. This will, for example, be the case for JTA, where
1140:             * <code>UserTransaction.commit</code> will check the read-only flag itself and
1141:             * throw a corresponding RollbackException, which might include the specific reason
1142:             * (such as a transaction timeout).
1143:             * <p>If this method returns "true" but the <code>doCommit</code> implementation does not
1144:             * throw an exception, this transaction manager will throw an UnexpectedRollbackException
1145:             * itself. This should not be the typical case; it is mainly checked to cover misbehaving
1146:             * JTA providers that silently roll back even when the rollback has not been requested
1147:             * by the calling code.
1148:             * @see #doCommit
1149:             * @see DefaultTransactionStatus#isGlobalRollbackOnly()
1150:             * @see DefaultTransactionStatus#isLocalRollbackOnly()
1151:             * @see org.springframework.transaction.TransactionStatus#setRollbackOnly()
1152:             * @see org.springframework.transaction.UnexpectedRollbackException
1153:             * @see javax.transaction.UserTransaction#commit()
1154:             * @see javax.transaction.RollbackException
1155:             */
1156:            protected boolean shouldCommitOnGlobalRollbackOnly() {
1157:                return false;
1158:            }
1159:
1160:            /**
1161:             * Perform an actual commit of the given transaction.
1162:             * <p>An implementation does not need to check the "new transaction" flag
1163:             * or the rollback-only flag; this will already have been handled before.
1164:             * Usually, a straight commit will be performed on the transaction object
1165:             * contained in the passed-in status.
1166:             * @param status the status representation of the transaction
1167:             * @throws TransactionException in case of commit or system errors
1168:             * @see DefaultTransactionStatus#getTransaction
1169:             */
1170:            protected abstract void doCommit(DefaultTransactionStatus status)
1171:                    throws TransactionException;
1172:
1173:            /**
1174:             * Perform an actual rollback of the given transaction.
1175:             * <p>An implementation does not need to check the "new transaction" flag;
1176:             * this will already have been handled before. Usually, a straight rollback
1177:             * will be performed on the transaction object contained in the passed-in status.
1178:             * @param status the status representation of the transaction
1179:             * @throws TransactionException in case of system errors
1180:             * @see DefaultTransactionStatus#getTransaction
1181:             */
1182:            protected abstract void doRollback(DefaultTransactionStatus status)
1183:                    throws TransactionException;
1184:
1185:            /**
1186:             * Set the given transaction rollback-only. Only called on rollback
1187:             * if the current transaction participates in an existing one.
1188:             * <p>The default implementation throws an IllegalTransactionStateException,
1189:             * assuming that participating in existing transactions is generally not
1190:             * supported. Subclasses are of course encouraged to provide such support.
1191:             * @param status the status representation of the transaction
1192:             * @throws TransactionException in case of system errors
1193:             */
1194:            protected void doSetRollbackOnly(DefaultTransactionStatus status)
1195:                    throws TransactionException {
1196:                throw new IllegalTransactionStateException(
1197:                        "Participating in existing transactions is not supported - when 'isExistingTransaction' "
1198:                                + "returns true, appropriate 'doSetRollbackOnly' behavior must be provided");
1199:            }
1200:
1201:            /**
1202:             * Register the given list of transaction synchronizations with the existing transaction.
1203:             * <p>Invoked when the control of the Spring transaction manager and thus all Spring
1204:             * transaction synchronizations end, without the transaction being completed yet. This
1205:             * is for example the case when participating in an existing JTA or EJB CMT transaction.
1206:             * <p>The default implementation simply invokes the <code>afterCompletion</code> methods
1207:             * immediately, passing in "STATUS_UNKNOWN". This is the best we can do if there's no
1208:             * chance to determine the actual outcome of the outer transaction.
1209:             * @param transaction transaction object returned by <code>doGetTransaction</code>
1210:             * @param synchronizations List of TransactionSynchronization objects
1211:             * @throws TransactionException in case of system errors
1212:             * @see #invokeAfterCompletion(java.util.List, int)
1213:             * @see TransactionSynchronization#afterCompletion(int)
1214:             * @see TransactionSynchronization#STATUS_UNKNOWN
1215:             */
1216:            protected void registerAfterCompletionWithExistingTransaction(
1217:                    Object transaction, List synchronizations)
1218:                    throws TransactionException {
1219:
1220:                logger
1221:                        .debug("Cannot register Spring after-completion synchronization with existing transaction - "
1222:                                + "processing Spring after-completion callbacks immediately, with outcome status 'unknown'");
1223:                invokeAfterCompletion(synchronizations,
1224:                        TransactionSynchronization.STATUS_UNKNOWN);
1225:            }
1226:
1227:            /**
1228:             * Cleanup resources after transaction completion.
1229:             * <p>Called after <code>doCommit</code> and <code>doRollback</code> execution,
1230:             * on any outcome. The default implementation does nothing.
1231:             * <p>Should not throw any exceptions but just issue warnings on errors.
1232:             * @param transaction transaction object returned by <code>doGetTransaction</code>
1233:             */
1234:            protected void doCleanupAfterCompletion(Object transaction) {
1235:            }
1236:
1237:            //---------------------------------------------------------------------
1238:            // Serialization support
1239:            //---------------------------------------------------------------------
1240:
1241:            private void readObject(ObjectInputStream ois) throws IOException,
1242:                    ClassNotFoundException {
1243:                // Rely on default serialization; just initialize state after deserialization.
1244:                ois.defaultReadObject();
1245:
1246:                // Initialize transient fields.
1247:                this .logger = LogFactory.getLog(getClass());
1248:            }
1249:
1250:            /**
1251:             * Holder for suspended resources.
1252:             * Used internally by <code>suspend</code> and <code>resume</code>.
1253:             */
1254:            protected static class SuspendedResourcesHolder {
1255:
1256:                private final Object suspendedResources;
1257:                private List suspendedSynchronizations;
1258:                private String name;
1259:                private boolean readOnly;
1260:                private Integer isolationLevel;
1261:                private boolean wasActive;
1262:
1263:                private SuspendedResourcesHolder(Object suspendedResources) {
1264:                    this .suspendedResources = suspendedResources;
1265:                }
1266:
1267:                private SuspendedResourcesHolder(Object suspendedResources,
1268:                        List suspendedSynchronizations, String name,
1269:                        boolean readOnly, Integer isolationLevel,
1270:                        boolean wasActive) {
1271:                    this.suspendedResources = suspendedResources;
1272:                    this.suspendedSynchronizations = suspendedSynchronizations;
1273:                    this.name = name;
1274:                    this.readOnly = readOnly;
1275:                    this.isolationLevel = isolationLevel;
1276:                    this.wasActive = wasActive;
1277:                }
1278:            }
1279:
1280:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.