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;
021import org.springframework.transaction.TransactionException;
022import org.springframework.transaction.TransactionStatus;
023import org.springframework.transaction.TransactionUsageException;
024
025/**
026 * Abstract base implementation of the
027 * {@link org.springframework.transaction.TransactionStatus} interface.
028 *
029 * <p>Pre-implements the handling of local rollback-only and completed flags, and
030 * delegation to an underlying {@link org.springframework.transaction.SavepointManager}.
031 * Also offers the option of a holding a savepoint within the transaction.
032 *
033 * <p>Does not assume any specific internal transaction handling, such as an
034 * underlying transaction object, and no transaction synchronization mechanism.
035 *
036 * @author Juergen Hoeller
037 * @since 1.2.3
038 * @see #setRollbackOnly()
039 * @see #isRollbackOnly()
040 * @see #setCompleted()
041 * @see #isCompleted()
042 * @see #getSavepointManager()
043 * @see SimpleTransactionStatus
044 * @see DefaultTransactionStatus
045 */
046public abstract class AbstractTransactionStatus implements TransactionStatus {
047
048        private boolean rollbackOnly = false;
049
050        private boolean completed = false;
051
052        private Object savepoint;
053
054
055        //---------------------------------------------------------------------
056        // Handling of current transaction state
057        //---------------------------------------------------------------------
058
059        @Override
060        public void setRollbackOnly() {
061                this.rollbackOnly = true;
062        }
063
064        /**
065         * Determine the rollback-only flag via checking both the local rollback-only flag
066         * of this TransactionStatus and the global rollback-only flag of the underlying
067         * transaction, if any.
068         * @see #isLocalRollbackOnly()
069         * @see #isGlobalRollbackOnly()
070         */
071        @Override
072        public boolean isRollbackOnly() {
073                return (isLocalRollbackOnly() || isGlobalRollbackOnly());
074        }
075
076        /**
077         * Determine the rollback-only flag via checking this TransactionStatus.
078         * <p>Will only return "true" if the application called {@code setRollbackOnly}
079         * on this TransactionStatus object.
080         */
081        public boolean isLocalRollbackOnly() {
082                return this.rollbackOnly;
083        }
084
085        /**
086         * Template method for determining the global rollback-only flag of the
087         * underlying transaction, if any.
088         * <p>This implementation always returns {@code false}.
089         */
090        public boolean isGlobalRollbackOnly() {
091                return false;
092        }
093
094        /**
095         * This implementations is empty, considering flush as a no-op.
096         */
097        @Override
098        public void flush() {
099        }
100
101        /**
102         * Mark this transaction as completed, that is, committed or rolled back.
103         */
104        public void setCompleted() {
105                this.completed = true;
106        }
107
108        @Override
109        public boolean isCompleted() {
110                return this.completed;
111        }
112
113
114        //---------------------------------------------------------------------
115        // Handling of current savepoint state
116        //---------------------------------------------------------------------
117
118        /**
119         * Set a savepoint for this transaction. Useful for PROPAGATION_NESTED.
120         * @see org.springframework.transaction.TransactionDefinition#PROPAGATION_NESTED
121         */
122        protected void setSavepoint(Object savepoint) {
123                this.savepoint = savepoint;
124        }
125
126        /**
127         * Get the savepoint for this transaction, if any.
128         */
129        protected Object getSavepoint() {
130                return this.savepoint;
131        }
132
133        @Override
134        public boolean hasSavepoint() {
135                return (this.savepoint != null);
136        }
137
138        /**
139         * Create a savepoint and hold it for the transaction.
140         * @throws org.springframework.transaction.NestedTransactionNotSupportedException
141         * if the underlying transaction does not support savepoints
142         */
143        public void createAndHoldSavepoint() throws TransactionException {
144                setSavepoint(getSavepointManager().createSavepoint());
145        }
146
147        /**
148         * Roll back to the savepoint that is held for the transaction
149         * and release the savepoint right afterwards.
150         */
151        public void rollbackToHeldSavepoint() throws TransactionException {
152                if (!hasSavepoint()) {
153                        throw new TransactionUsageException(
154                                        "Cannot roll back to savepoint - no savepoint associated with current transaction");
155                }
156                getSavepointManager().rollbackToSavepoint(getSavepoint());
157                getSavepointManager().releaseSavepoint(getSavepoint());
158                setSavepoint(null);
159        }
160
161        /**
162         * Release the savepoint that is held for the transaction.
163         */
164        public void releaseHeldSavepoint() throws TransactionException {
165                if (!hasSavepoint()) {
166                        throw new TransactionUsageException(
167                                        "Cannot release savepoint - no savepoint associated with current transaction");
168                }
169                getSavepointManager().releaseSavepoint(getSavepoint());
170                setSavepoint(null);
171        }
172
173
174        //---------------------------------------------------------------------
175        // Implementation of SavepointManager
176        //---------------------------------------------------------------------
177
178        /**
179         * This implementation delegates to a SavepointManager for the
180         * underlying transaction, if possible.
181         * @see #getSavepointManager()
182         * @see SavepointManager#createSavepoint()
183         */
184        @Override
185        public Object createSavepoint() throws TransactionException {
186                return getSavepointManager().createSavepoint();
187        }
188
189        /**
190         * This implementation delegates to a SavepointManager for the
191         * underlying transaction, if possible.
192         * @see #getSavepointManager()
193         * @see SavepointManager#rollbackToSavepoint(Object)
194         */
195        @Override
196        public void rollbackToSavepoint(Object savepoint) throws TransactionException {
197                getSavepointManager().rollbackToSavepoint(savepoint);
198        }
199
200        /**
201         * This implementation delegates to a SavepointManager for the
202         * underlying transaction, if possible.
203         * @see #getSavepointManager()
204         * @see SavepointManager#releaseSavepoint(Object)
205         */
206        @Override
207        public void releaseSavepoint(Object savepoint) throws TransactionException {
208                getSavepointManager().releaseSavepoint(savepoint);
209        }
210
211        /**
212         * Return a SavepointManager for the underlying transaction, if possible.
213         * <p>Default implementation always throws a NestedTransactionNotSupportedException.
214         * @throws org.springframework.transaction.NestedTransactionNotSupportedException
215         * if the underlying transaction does not support savepoints
216         */
217        protected SavepointManager getSavepointManager() {
218                throw new NestedTransactionNotSupportedException("This transaction does not support savepoints");
219        }
220
221}