001/* 002 * Copyright 2002-2012 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 java.util.List; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.springframework.aop.scope.ScopedObject; 025import org.springframework.core.InfrastructureProxy; 026import org.springframework.util.Assert; 027import org.springframework.util.ClassUtils; 028 029/** 030 * Utility methods for triggering specific {@link TransactionSynchronization} 031 * callback methods on all currently registered synchronizations. 032 * 033 * @author Juergen Hoeller 034 * @since 2.0 035 * @see TransactionSynchronization 036 * @see TransactionSynchronizationManager#getSynchronizations() 037 */ 038public abstract class TransactionSynchronizationUtils { 039 040 private static final Log logger = LogFactory.getLog(TransactionSynchronizationUtils.class); 041 042 private static final boolean aopAvailable = ClassUtils.isPresent( 043 "org.springframework.aop.scope.ScopedObject", TransactionSynchronizationUtils.class.getClassLoader()); 044 045 046 /** 047 * Check whether the given resource transaction managers refers to the given 048 * (underlying) resource factory. 049 * @see ResourceTransactionManager#getResourceFactory() 050 * @see org.springframework.core.InfrastructureProxy#getWrappedObject() 051 */ 052 public static boolean sameResourceFactory(ResourceTransactionManager tm, Object resourceFactory) { 053 return unwrapResourceIfNecessary(tm.getResourceFactory()).equals(unwrapResourceIfNecessary(resourceFactory)); 054 } 055 056 /** 057 * Unwrap the given resource handle if necessary; otherwise return 058 * the given handle as-is. 059 * @see org.springframework.core.InfrastructureProxy#getWrappedObject() 060 */ 061 static Object unwrapResourceIfNecessary(Object resource) { 062 Assert.notNull(resource, "Resource must not be null"); 063 Object resourceRef = resource; 064 // unwrap infrastructure proxy 065 if (resourceRef instanceof InfrastructureProxy) { 066 resourceRef = ((InfrastructureProxy) resourceRef).getWrappedObject(); 067 } 068 if (aopAvailable) { 069 // now unwrap scoped proxy 070 resourceRef = ScopedProxyUnwrapper.unwrapIfNecessary(resourceRef); 071 } 072 return resourceRef; 073 } 074 075 076 /** 077 * Trigger {@code flush} callbacks on all currently registered synchronizations. 078 * @throws RuntimeException if thrown by a {@code flush} callback 079 * @see TransactionSynchronization#flush() 080 */ 081 public static void triggerFlush() { 082 for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) { 083 synchronization.flush(); 084 } 085 } 086 087 /** 088 * Trigger {@code beforeCommit} callbacks on all currently registered synchronizations. 089 * @param readOnly whether the transaction is defined as read-only transaction 090 * @throws RuntimeException if thrown by a {@code beforeCommit} callback 091 * @see TransactionSynchronization#beforeCommit(boolean) 092 */ 093 public static void triggerBeforeCommit(boolean readOnly) { 094 for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) { 095 synchronization.beforeCommit(readOnly); 096 } 097 } 098 099 /** 100 * Trigger {@code beforeCompletion} callbacks on all currently registered synchronizations. 101 * @see TransactionSynchronization#beforeCompletion() 102 */ 103 public static void triggerBeforeCompletion() { 104 for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) { 105 try { 106 synchronization.beforeCompletion(); 107 } 108 catch (Throwable tsex) { 109 logger.error("TransactionSynchronization.beforeCompletion threw exception", tsex); 110 } 111 } 112 } 113 114 /** 115 * Trigger {@code afterCommit} callbacks on all currently registered synchronizations. 116 * @throws RuntimeException if thrown by a {@code afterCommit} callback 117 * @see TransactionSynchronizationManager#getSynchronizations() 118 * @see TransactionSynchronization#afterCommit() 119 */ 120 public static void triggerAfterCommit() { 121 invokeAfterCommit(TransactionSynchronizationManager.getSynchronizations()); 122 } 123 124 /** 125 * Actually invoke the {@code afterCommit} methods of the 126 * given Spring TransactionSynchronization objects. 127 * @param synchronizations List of TransactionSynchronization objects 128 * @see TransactionSynchronization#afterCommit() 129 */ 130 public static void invokeAfterCommit(List<TransactionSynchronization> synchronizations) { 131 if (synchronizations != null) { 132 for (TransactionSynchronization synchronization : synchronizations) { 133 synchronization.afterCommit(); 134 } 135 } 136 } 137 138 /** 139 * Trigger {@code afterCompletion} callbacks on all currently registered synchronizations. 140 * @see TransactionSynchronizationManager#getSynchronizations() 141 * @param completionStatus the completion status according to the 142 * constants in the TransactionSynchronization interface 143 * @see TransactionSynchronization#afterCompletion(int) 144 * @see TransactionSynchronization#STATUS_COMMITTED 145 * @see TransactionSynchronization#STATUS_ROLLED_BACK 146 * @see TransactionSynchronization#STATUS_UNKNOWN 147 */ 148 public static void triggerAfterCompletion(int completionStatus) { 149 List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations(); 150 invokeAfterCompletion(synchronizations, completionStatus); 151 } 152 153 /** 154 * Actually invoke the {@code afterCompletion} methods of the 155 * given Spring TransactionSynchronization objects. 156 * @param synchronizations List of TransactionSynchronization objects 157 * @param completionStatus the completion status according to the 158 * constants in the TransactionSynchronization interface 159 * @see TransactionSynchronization#afterCompletion(int) 160 * @see TransactionSynchronization#STATUS_COMMITTED 161 * @see TransactionSynchronization#STATUS_ROLLED_BACK 162 * @see TransactionSynchronization#STATUS_UNKNOWN 163 */ 164 public static void invokeAfterCompletion(List<TransactionSynchronization> synchronizations, int completionStatus) { 165 if (synchronizations != null) { 166 for (TransactionSynchronization synchronization : synchronizations) { 167 try { 168 synchronization.afterCompletion(completionStatus); 169 } 170 catch (Throwable tsex) { 171 logger.error("TransactionSynchronization.afterCompletion threw exception", tsex); 172 } 173 } 174 } 175 } 176 177 178 /** 179 * Inner class to avoid hard-coded dependency on AOP module. 180 */ 181 private static class ScopedProxyUnwrapper { 182 183 public static Object unwrapIfNecessary(Object resource) { 184 if (resource instanceof ScopedObject) { 185 return ((ScopedObject) resource).getTargetObject(); 186 } 187 else { 188 return resource; 189 } 190 } 191 } 192 193}