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