1 16 17 package org.springframework.transaction.interceptor; 18 19 import java.lang.reflect.Method ; 20 import java.util.Properties ; 21 22 import org.apache.commons.logging.Log; 23 import org.apache.commons.logging.LogFactory; 24 25 import org.springframework.beans.factory.InitializingBean; 26 import org.springframework.transaction.NoTransactionException; 27 import org.springframework.transaction.PlatformTransactionManager; 28 import org.springframework.transaction.TransactionStatus; 29 import org.springframework.util.ClassUtils; 30 31 62 public abstract class TransactionAspectSupport implements InitializingBean { 63 64 67 73 private static final ThreadLocal transactionInfoHolder = new ThreadLocal (); 74 75 76 93 protected static TransactionInfo currentTransactionInfo() throws NoTransactionException { 94 return (TransactionInfo) transactionInfoHolder.get(); 95 } 96 103 public static TransactionStatus currentTransactionStatus() throws NoTransactionException { 104 TransactionInfo info = currentTransactionInfo(); 105 if (info == null) { 106 throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope"); 107 } 108 return currentTransactionInfo().transactionStatus; 109 } 110 111 112 protected final Log logger = LogFactory.getLog(getClass()); 113 114 115 private PlatformTransactionManager transactionManager; 116 117 118 private TransactionAttributeSource transactionAttributeSource; 119 120 121 125 public void setTransactionManager(PlatformTransactionManager transactionManager) { 126 this.transactionManager = transactionManager; 127 } 128 129 132 public PlatformTransactionManager getTransactionManager() { 133 return transactionManager; 134 } 135 136 148 public void setTransactionAttributes(Properties transactionAttributes) { 149 NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource(); 150 tas.setProperties(transactionAttributes); 151 this.transactionAttributeSource = tas; 152 } 153 154 163 public void setTransactionAttributeSources(TransactionAttributeSource[] transactionAttributeSources) { 164 this.transactionAttributeSource = new CompositeTransactionAttributeSource(transactionAttributeSources); 165 } 166 167 177 public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { 178 this.transactionAttributeSource = transactionAttributeSource; 179 } 180 181 184 public TransactionAttributeSource getTransactionAttributeSource() { 185 return transactionAttributeSource; 186 } 187 188 189 192 public void afterPropertiesSet() { 193 if (getTransactionManager() == null) { 194 throw new IllegalArgumentException ("transactionManager is required"); 195 } 196 if (getTransactionAttributeSource() == null) { 197 throw new IllegalArgumentException ( 198 "Either 'transactionAttributeSource' or 'transactionAttributes' is required: " + 199 "If there are no transactional methods, don't use a TransactionInterceptor " + 200 "or TransactionProxyFactoryBean."); 201 } 202 } 203 204 205 215 protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) { 216 TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); 218 return createTransactionIfNecessary(txAttr, methodIdentification(method)); 219 } 220 221 229 protected String methodIdentification(Method method) { 230 return ClassUtils.getQualifiedMethodName(method); 231 } 232 233 245 protected TransactionInfo createTransactionIfNecessary( 246 TransactionAttribute txAttr, final String joinpointIdentification) { 247 248 if (txAttr != null && txAttr.getName() == null) { 250 txAttr = new DelegatingTransactionAttribute(txAttr) { 251 public String getName() { 252 return joinpointIdentification; 253 } 254 }; 255 } 256 257 TransactionStatus status = null; 258 if (txAttr != null) { 259 status = getTransactionManager().getTransaction(txAttr); 260 } 261 return prepareTransactionInfo(txAttr, joinpointIdentification, status); 262 } 263 264 272 protected TransactionInfo prepareTransactionInfo( 273 TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) { 274 275 TransactionInfo txInfo = new TransactionInfo(txAttr, joinpointIdentification); 276 if (txAttr != null) { 277 if (logger.isDebugEnabled()) { 279 logger.debug("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]"); 280 } 281 282 txInfo.newTransactionStatus(status); 284 } 285 else { 286 if (logger.isDebugEnabled()) 290 logger.debug("Don't need to create transaction for [" + joinpointIdentification + 291 "]: This method isn't transactional."); 292 } 293 294 txInfo.bindToThread(); 298 return txInfo; 299 } 300 301 306 protected void commitTransactionAfterReturning(TransactionInfo txInfo) { 307 if (txInfo != null && txInfo.hasTransaction()) { 308 if (logger.isDebugEnabled()) { 309 logger.debug("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]"); 310 } 311 this.transactionManager.commit(txInfo.getTransactionStatus()); 312 } 313 } 314 315 321 protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) { 322 if (txInfo != null && txInfo.hasTransaction()) { 323 if (logger.isDebugEnabled()) { 324 logger.debug("Completing transaction for [" + txInfo.getJoinpointIdentification() + 325 "] after exception: " + ex); 326 } 327 if (txInfo.transactionAttribute.rollbackOn(ex)) { 328 try { 329 this.transactionManager.rollback(txInfo.getTransactionStatus()); 330 } 331 catch (RuntimeException ex2) { 332 logger.error("Application exception overridden by rollback exception", ex); 333 throw ex2; 334 } 335 catch (Error err) { 336 logger.error("Application exception overridden by rollback error", ex); 337 throw err; 338 } 339 } 340 else { 341 try { 344 this.transactionManager.commit(txInfo.getTransactionStatus()); 345 } 346 catch (RuntimeException ex2) { 347 logger.error("Application exception overridden by commit exception", ex); 348 throw ex2; 349 } 350 catch (Error err) { 351 logger.error("Application exception overridden by commit error", ex); 352 throw err; 353 } 354 } 355 } 356 } 357 358 363 protected void cleanupTransactionInfo(TransactionInfo txInfo) { 364 if (txInfo != null) { 365 txInfo.restoreThreadLocalStatus(); 366 } 367 } 368 369 370 374 protected class TransactionInfo { 375 376 private final TransactionAttribute transactionAttribute; 377 378 private final String joinpointIdentification; 379 380 private TransactionStatus transactionStatus; 381 382 private TransactionInfo oldTransactionInfo; 383 384 public TransactionInfo(TransactionAttribute transactionAttribute, String joinpointIdentification) { 385 this.transactionAttribute = transactionAttribute; 386 this.joinpointIdentification = joinpointIdentification; 387 } 388 389 public TransactionAttribute getTransactionAttribute() { 390 return this.transactionAttribute; 391 } 392 393 397 public String getJoinpointIdentification() { 398 return this.joinpointIdentification; 399 } 400 401 public void newTransactionStatus(TransactionStatus status) { 402 this.transactionStatus = status; 403 } 404 405 public TransactionStatus getTransactionStatus() { 406 return this.transactionStatus; 407 } 408 409 413 public boolean hasTransaction() { 414 return (this.transactionStatus != null); 415 } 416 417 private void bindToThread() { 418 this.oldTransactionInfo = (TransactionInfo) transactionInfoHolder.get(); 421 transactionInfoHolder.set(this); 422 } 423 424 private void restoreThreadLocalStatus() { 425 transactionInfoHolder.set(this.oldTransactionInfo); 428 } 429 } 430 431 } 432 | Popular Tags |