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}