Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » transaction » interceptor » [javadoc | source]
    1   /*
    2    * Copyright 2002-2007 the original author or authors.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.springframework.transaction.interceptor;
   18   
   19   import java.io.IOException;
   20   import java.io.ObjectInputStream;
   21   import java.io.ObjectOutputStream;
   22   import java.io.Serializable;
   23   import java.util.Properties;
   24   
   25   import org.aopalliance.intercept.MethodInterceptor;
   26   import org.aopalliance.intercept.MethodInvocation;
   27   
   28   import org.springframework.transaction.PlatformTransactionManager;
   29   import org.springframework.transaction.TransactionStatus;
   30   import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
   31   import org.springframework.transaction.support.TransactionCallback;
   32   
   33   /**
   34    * AOP Alliance MethodInterceptor for declarative transaction
   35    * management using the common Spring transaction infrastructure
   36    * ({@link org.springframework.transaction.PlatformTransactionManager}).
   37    *
   38    * <p>Derives from the {@link TransactionAspectSupport} class which
   39    * contains the integration with Spring's underlying transaction API.
   40    * TransactionInterceptor simply calls the relevant superclass methods
   41    * such as {@link #createTransactionIfNecessary} in the correct order.
   42    *
   43    * <p>TransactionInterceptors are thread-safe.
   44    *
   45    * @author Rod Johnson
   46    * @author Juergen Hoeller
   47    * @see TransactionProxyFactoryBean
   48    * @see org.springframework.aop.framework.ProxyFactoryBean
   49    * @see org.springframework.aop.framework.ProxyFactory
   50    */
   51   public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
   52   
   53   	/**
   54   	 * Create a new TransactionInterceptor.
   55   	 * <p>Transaction manager and transaction attributes still need to be set.
   56   	 * @see #setTransactionManager
   57   	 * @see #setTransactionAttributes(java.util.Properties)
   58   	 * @see #setTransactionAttributeSource(TransactionAttributeSource)
   59   	 */
   60   	public TransactionInterceptor() {
   61   	}
   62   
   63   	/**
   64   	 * Create a new TransactionInterceptor.
   65   	 * @param ptm the transaction manager to perform the actual transaction management
   66   	 * @param attributes the transaction attributes in properties format
   67   	 * @see #setTransactionManager
   68   	 * @see #setTransactionAttributes(java.util.Properties)
   69   	 */
   70   	public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
   71   		setTransactionManager(ptm);
   72   		setTransactionAttributes(attributes);
   73   	}
   74   
   75   	/**
   76   	 * Create a new TransactionInterceptor.
   77   	 * @param ptm the transaction manager to perform the actual transaction management
   78   	 * @param tas the attribute source to be used to find transaction attributes
   79   	 * @see #setTransactionManager
   80   	 * @see #setTransactionAttributeSource(TransactionAttributeSource)
   81   	 */
   82   	public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
   83   		setTransactionManager(ptm);
   84   		setTransactionAttributeSource(tas);
   85   	}
   86   
   87   
   88   	public Object invoke(final MethodInvocation invocation) throws Throwable {
   89   		// Work out the target class: may be <code>null</code>.
   90   		// The TransactionAttributeSource should be passed the target class
   91   		// as well as the method, which may be from an interface.
   92   		Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);
   93   
   94   		// If the transaction attribute is null, the method is non-transactional.
   95   		final TransactionAttribute txAttr =
   96   				getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
   97   		final String joinpointIdentification = methodIdentification(invocation.getMethod());
   98   
   99   		if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
  100   			// Standard transaction demarcation with getTransaction and commit/rollback calls.
  101   			TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
  102   			Object retVal = null;
  103   			try {
  104   				// This is an around advice: Invoke the next interceptor in the chain.
  105   				// This will normally result in a target object being invoked.
  106   				retVal = invocation.proceed();
  107   			}
  108   			catch (Throwable ex) {
  109   				// target invocation exception
  110   				completeTransactionAfterThrowing(txInfo, ex);
  111   				throw ex;
  112   			}
  113   			finally {
  114   				cleanupTransactionInfo(txInfo);
  115   			}
  116   			commitTransactionAfterReturning(txInfo);
  117   			return retVal;
  118   		}
  119   
  120   		else {
  121   			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
  122   			try {
  123   				Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,
  124   						new TransactionCallback() {
  125   							public Object doInTransaction(TransactionStatus status) {
  126   								TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
  127   								try {
  128   									return invocation.proceed();
  129   								}
  130   								catch (Throwable ex) {
  131   									if (txAttr.rollbackOn(ex)) {
  132   										// A RuntimeException: will lead to a rollback.
  133   										if (ex instanceof RuntimeException) {
  134   											throw (RuntimeException) ex;
  135   										}
  136   										else {
  137   											throw new ThrowableHolderException(ex);
  138   										}
  139   									}
  140   									else {
  141   										// A normal return value: will lead to a commit.
  142   										return new ThrowableHolder(ex);
  143   									}
  144   								}
  145   								finally {
  146   									cleanupTransactionInfo(txInfo);
  147   								}
  148   							}
  149   						});
  150   
  151   				// Check result: It might indicate a Throwable to rethrow.
  152   				if (result instanceof ThrowableHolder) {
  153   					throw ((ThrowableHolder) result).getThrowable();
  154   				}
  155   				else {
  156   					return result;
  157   				}
  158   			}
  159   			catch (ThrowableHolderException ex) {
  160   				throw ex.getCause();
  161   			}
  162   		}
  163   	}
  164   
  165   
  166   	//---------------------------------------------------------------------
  167   	// Serialization support
  168   	//---------------------------------------------------------------------
  169   
  170   	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  171   		// Rely on default serialization, although this class itself doesn't carry state anyway...
  172   		ois.defaultReadObject();
  173   
  174   		// Serialize all relevant superclass fields.
  175   		// Superclass can't implement Serializable because it also serves as base class
  176   		// for AspectJ aspects (which are not allowed to implement Serializable)!
  177   		setTransactionManager((PlatformTransactionManager) ois.readObject());
  178   		setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
  179   	}
  180   
  181   	private void writeObject(ObjectOutputStream oos) throws IOException {
  182   		// Rely on default serialization, although this class itself doesn't carry state anyway...
  183   		oos.defaultWriteObject();
  184   
  185   		// Deserialize superclass fields.
  186   		oos.writeObject(getTransactionManager());
  187   		oos.writeObject(getTransactionAttributeSource());
  188   	}
  189   
  190   
  191   	/**
  192   	 * Internal holder class for a Throwable, used as a return value
  193   	 * from a TransactionCallback (to be subsequently unwrapped again).
  194   	 */
  195   	private static class ThrowableHolder {
  196   
  197   		private final Throwable throwable;
  198   
  199   		public ThrowableHolder(Throwable throwable) {
  200   			this.throwable = throwable;
  201   		}
  202   
  203   		public final Throwable getThrowable() {
  204   			return this.throwable;
  205   		}
  206   	}
  207   
  208   
  209   	/**
  210   	 * Internal holder class for a Throwable, used as a RuntimeException to be
  211   	 * thrown from a TransactionCallback (and subsequently unwrapped again).
  212   	 */
  213   	private static class ThrowableHolderException extends RuntimeException {
  214   
  215   		public ThrowableHolderException(Throwable throwable) {
  216   			super(throwable);
  217   		}
  218   
  219   		public String toString() {
  220   			return getCause().toString();
  221   		}
  222   	}
  223   
  224   }

Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » transaction » interceptor » [javadoc | source]