Open Source Repository

Home /spring/spring-transaction-3.0.5 | Repository Home


org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java
/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.transaction.annotation;

import java.io.Serializable;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
 * Implementation of the
 {@link org.springframework.transaction.interceptor.TransactionAttributeSource}
 * interface for working with transaction metadata in JDK 1.5+ annotation format.
 *
 <p>This class reads Spring's JDK 1.5+ {@link Transactional} annotation and
 * exposes corresponding transaction attributes to Spring's transaction infrastructure.
 * Also supports EJB3's {@link javax.ejb.TransactionAttribute} annotation (if present).
 * This class may also serve as base class for a custom TransactionAttributeSource,
 * or get customized through {@link TransactionAnnotationParser} strategies.
 *
 @author Colin Sampaleanu
 @author Juergen Hoeller
 @since 1.2
 @see Transactional
 @see TransactionAnnotationParser
 @see SpringTransactionAnnotationParser
 @see Ejb3TransactionAnnotationParser
 @see org.springframework.transaction.interceptor.TransactionInterceptor#setTransactionAttributeSource
 @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean#setTransactionAttributeSource
 */
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
    implements Serializable {

  private static final boolean ejb3Present = ClassUtils.isPresent(
      "javax.ejb.TransactionAttribute", AnnotationTransactionAttributeSource.class.getClassLoader());

  private final boolean publicMethodsOnly;

  private final Set<TransactionAnnotationParser> annotationParsers;


  /**
   * Create a default AnnotationTransactionAttributeSource, supporting
   * public methods that carry the <code>Transactional</code> annotation
   * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
   */
  public AnnotationTransactionAttributeSource() {
    this(true);
  }

  /**
   * Create a custom AnnotationTransactionAttributeSource, supporting
   * public methods that carry the <code>Transactional</code> annotation
   * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
   @param publicMethodsOnly whether to support public methods that carry
   * the <code>Transactional</code> annotation only (typically for use
   * with proxy-based AOP), or protected/private methods as well
   * (typically used with AspectJ class weaving)
   */
  public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
    this.publicMethodsOnly = publicMethodsOnly;
    this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
    this.annotationParsers.add(new SpringTransactionAnnotationParser());
    if (ejb3Present) {
      this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
    }
  }

  /**
   * Create a custom AnnotationTransactionAttributeSource.
   @param annotationParser the TransactionAnnotationParser to use
   */
  public AnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) {
    this.publicMethodsOnly = true;
    Assert.notNull(annotationParser, "TransactionAnnotationParser must not be null");
    this.annotationParsers = Collections.singleton(annotationParser);
  }

  /**
   * Create a custom AnnotationTransactionAttributeSource.
   @param annotationParsers the TransactionAnnotationParsers to use
   */
  public AnnotationTransactionAttributeSource(Set<TransactionAnnotationParser> annotationParsers) {
    this.publicMethodsOnly = true;
    Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
    this.annotationParsers = annotationParsers;
  }


  @Override
  protected TransactionAttribute findTransactionAttribute(Method method) {
    return determineTransactionAttribute(method);
  }

  @Override
  protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
    return determineTransactionAttribute(clazz);
  }

  /**
   * Determine the transaction attribute for the given method or class.
   <p>This implementation delegates to configured
   {@link TransactionAnnotationParser TransactionAnnotationParsers}
   * for parsing known annotations into Spring's metadata attribute class.
   * Returns <code>null</code> if it's not transactional.
   <p>Can be overridden to support custom annotations that carry transaction metadata.
   @param ae the annotated method or class
   @return TransactionAttribute the configured transaction attribute,
   * or <code>null</code> if none was found
   */
  protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
    for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
      TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
      if (attr != null) {
        return attr;
      }
    }
    return null;
  }

  /**
   * By default, only public methods can be made transactional.
   */
  @Override
  protected boolean allowPublicMethodsOnly() {
    return this.publicMethodsOnly;
  }

}