001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.transaction.support;
018
019import org.springframework.transaction.NestedTransactionNotSupportedException;
020import org.springframework.transaction.SavepointManager;
021
022/**
023 * Default implementation of the {@link org.springframework.transaction.TransactionStatus}
024 * interface, used by {@link AbstractPlatformTransactionManager}. Based on the concept
025 * of an underlying "transaction object".
026 *
027 * <p>Holds all status information that {@link AbstractPlatformTransactionManager}
028 * needs internally, including a generic transaction object determined by the
029 * concrete transaction manager implementation.
030 *
031 * <p>Supports delegating savepoint-related methods to a transaction object
032 * that implements the {@link SavepointManager} interface.
033 *
034 * <p><b>NOTE:</b> This is <i>not</i> intended for use with other PlatformTransactionManager
035 * implementations, in particular not for mock transaction managers in testing environments.
036 * Use the alternative {@link SimpleTransactionStatus} class or a mock for the plain
037 * {@link org.springframework.transaction.TransactionStatus} interface instead.
038 *
039 * @author Juergen Hoeller
040 * @since 19.01.2004
041 * @see AbstractPlatformTransactionManager
042 * @see org.springframework.transaction.SavepointManager
043 * @see #getTransaction
044 * @see #createSavepoint
045 * @see #rollbackToSavepoint
046 * @see #releaseSavepoint
047 * @see SimpleTransactionStatus
048 */
049public class DefaultTransactionStatus extends AbstractTransactionStatus {
050
051        private final Object transaction;
052
053        private final boolean newTransaction;
054
055        private final boolean newSynchronization;
056
057        private final boolean readOnly;
058
059        private final boolean debug;
060
061        private final Object suspendedResources;
062
063
064        /**
065         * Create a new {@code DefaultTransactionStatus} instance.
066         * @param transaction underlying transaction object that can hold state
067         * for the internal transaction implementation
068         * @param newTransaction if the transaction is new, otherwise participating
069         * in an existing transaction
070         * @param newSynchronization if a new transaction synchronization has been
071         * opened for the given transaction
072         * @param readOnly whether the transaction is marked as read-only
073         * @param debug should debug logging be enabled for the handling of this transaction?
074         * Caching it in here can prevent repeated calls to ask the logging system whether
075         * debug logging should be enabled.
076         * @param suspendedResources a holder for resources that have been suspended
077         * for this transaction, if any
078         */
079        public DefaultTransactionStatus(
080                        Object transaction, boolean newTransaction, boolean newSynchronization,
081                        boolean readOnly, boolean debug, Object suspendedResources) {
082
083                this.transaction = transaction;
084                this.newTransaction = newTransaction;
085                this.newSynchronization = newSynchronization;
086                this.readOnly = readOnly;
087                this.debug = debug;
088                this.suspendedResources = suspendedResources;
089        }
090
091
092        /**
093         * Return the underlying transaction object.
094         */
095        public Object getTransaction() {
096                return this.transaction;
097        }
098
099        /**
100         * Return whether there is an actual transaction active.
101         */
102        public boolean hasTransaction() {
103                return (this.transaction != null);
104        }
105
106        @Override
107        public boolean isNewTransaction() {
108                return (hasTransaction() && this.newTransaction);
109        }
110
111        /**
112         * Return if a new transaction synchronization has been opened
113         * for this transaction.
114         */
115        public boolean isNewSynchronization() {
116                return this.newSynchronization;
117        }
118
119        /**
120         * Return if this transaction is defined as read-only transaction.
121         */
122        public boolean isReadOnly() {
123                return this.readOnly;
124        }
125
126        /**
127         * Return whether the progress of this transaction is debugged. This is used by
128         * {@link AbstractPlatformTransactionManager} as an optimization, to prevent repeated
129         * calls to {@code logger.isDebugEnabled()}. Not really intended for client code.
130         */
131        public boolean isDebug() {
132                return this.debug;
133        }
134
135        /**
136         * Return the holder for resources that have been suspended for this transaction,
137         * if any.
138         */
139        public Object getSuspendedResources() {
140                return this.suspendedResources;
141        }
142
143
144        //---------------------------------------------------------------------
145        // Enable functionality through underlying transaction object
146        //---------------------------------------------------------------------
147
148        /**
149         * Determine the rollback-only flag via checking the transaction object, provided
150         * that the latter implements the {@link SmartTransactionObject} interface.
151         * <p>Will return {@code true} if the global transaction itself has been marked
152         * rollback-only by the transaction coordinator, for example in case of a timeout.
153         * @see SmartTransactionObject#isRollbackOnly()
154         */
155        @Override
156        public boolean isGlobalRollbackOnly() {
157                return ((this.transaction instanceof SmartTransactionObject) &&
158                                ((SmartTransactionObject) this.transaction).isRollbackOnly());
159        }
160
161        /**
162         * Delegate the flushing to the transaction object, provided that the latter
163         * implements the {@link SmartTransactionObject} interface.
164         * @see SmartTransactionObject#flush()
165         */
166        @Override
167        public void flush() {
168                if (this.transaction instanceof SmartTransactionObject) {
169                        ((SmartTransactionObject) this.transaction).flush();
170                }
171        }
172
173        /**
174         * This implementation exposes the {@link SavepointManager} interface
175         * of the underlying transaction object, if any.
176         * @throws NestedTransactionNotSupportedException if savepoints are not supported
177         * @see #isTransactionSavepointManager()
178         */
179        @Override
180        protected SavepointManager getSavepointManager() {
181                if (!isTransactionSavepointManager()) {
182                        throw new NestedTransactionNotSupportedException(
183                                        "Transaction object [" + this.transaction + "] does not support savepoints");
184                }
185                return (SavepointManager) getTransaction();
186        }
187
188        /**
189         * Return whether the underlying transaction implements the {@link SavepointManager}
190         * interface and therefore supports savepoints.
191         * @see #getTransaction()
192         * @see #getSavepointManager()
193         */
194        public boolean isTransactionSavepointManager() {
195                return (getTransaction() instanceof SavepointManager);
196        }
197
198}