001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.transaction.annotation;
018:
019: import java.io.Serializable;
020: import java.lang.reflect.AnnotatedElement;
021: import java.lang.reflect.Method;
022: import java.util.Collections;
023: import java.util.LinkedHashSet;
024: import java.util.Set;
025:
026: import org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource;
027: import org.springframework.transaction.interceptor.TransactionAttribute;
028: import org.springframework.util.Assert;
029: import org.springframework.util.ClassUtils;
030:
031: /**
032: * Implementation of the
033: * {@link org.springframework.transaction.interceptor.TransactionAttributeSource}
034: * interface for working with transaction metadata in JDK 1.5+ annotation format.
035: *
036: * <p>This class reads Spring's JDK 1.5+ {@link Transactional} annotation and
037: * exposes corresponding transaction attributes to Spring's transaction infrastructure.
038: * Also supports EJB3's {@link javax.ejb.TransactionAttribute} annotation (if present).
039: * This class may also serve as base class for a custom TransactionAttributeSource,
040: * or get customized through {@link TransactionAnnotationParser} strategies.
041: *
042: * <p>This is a direct alternative to
043: * {@link org.springframework.transaction.interceptor.AttributesTransactionAttributeSource},
044: * which is able to read in source-level attributes via Commons Attributes.
045: *
046: * @author Colin Sampaleanu
047: * @author Juergen Hoeller
048: * @since 1.2
049: * @see Transactional
050: * @see TransactionAnnotationParser
051: * @see SpringTransactionAnnotationParser
052: * @see Ejb3TransactionAnnotationParser
053: * @see org.springframework.transaction.interceptor.TransactionInterceptor#setTransactionAttributeSource
054: * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean#setTransactionAttributeSource
055: */
056: public class AnnotationTransactionAttributeSource extends
057: AbstractFallbackTransactionAttributeSource implements
058: Serializable {
059:
060: private static final boolean ejb3Present = ClassUtils
061: .isPresent("javax.ejb.TransactionAttribute",
062: AnnotationTransactionAttributeSource.class
063: .getClassLoader());
064:
065: private final boolean publicMethodsOnly;
066:
067: private final Set<TransactionAnnotationParser> annotationParsers;
068:
069: /**
070: * Create a default AnnotationTransactionAttributeSource, supporting
071: * public methods that carry the <code>Transactional</code> annotation
072: * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
073: */
074: public AnnotationTransactionAttributeSource() {
075: this (true);
076: }
077:
078: /**
079: * Create a custom AnnotationTransactionAttributeSource, supporting
080: * public methods that carry the <code>Transactional</code> annotation
081: * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
082: * @param publicMethodsOnly whether to support public methods that carry
083: * the <code>Transactional</code> annotation only (typically for use
084: * with proxy-based AOP), or protected/private methods as well
085: * (typically used with AspectJ class weaving)
086: */
087: public AnnotationTransactionAttributeSource(
088: boolean publicMethodsOnly) {
089: this .publicMethodsOnly = publicMethodsOnly;
090: this .annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(
091: 2);
092: this .annotationParsers
093: .add(new SpringTransactionAnnotationParser());
094: if (ejb3Present) {
095: this .annotationParsers
096: .add(new Ejb3TransactionAnnotationParser());
097: }
098: }
099:
100: /**
101: * Create a custom AnnotationTransactionAttributeSource.
102: * @param annotationParser the TransactionAnnotationParser to use
103: */
104: public AnnotationTransactionAttributeSource(
105: TransactionAnnotationParser annotationParser) {
106: this .publicMethodsOnly = true;
107: Assert.notNull(annotationParser,
108: "TransactionAnnotationParser must not be null");
109: this .annotationParsers = Collections
110: .singleton(annotationParser);
111: }
112:
113: /**
114: * Create a custom AnnotationTransactionAttributeSource.
115: * @param annotationParsers the TransactionAnnotationParsers to use
116: */
117: public AnnotationTransactionAttributeSource(
118: Set<TransactionAnnotationParser> annotationParsers) {
119: this .publicMethodsOnly = true;
120: Assert
121: .notEmpty(annotationParsers,
122: "At least one TransactionAnnotationParser needs to be specified");
123: this .annotationParsers = annotationParsers;
124: }
125:
126: protected TransactionAttribute findTransactionAttribute(
127: Method method) {
128: return determineTransactionAttribute(method);
129: }
130:
131: protected TransactionAttribute findTransactionAttribute(Class clazz) {
132: return determineTransactionAttribute(clazz);
133: }
134:
135: /**
136: * Determine the transaction attribute for the given method or class.
137: * <p>This implementation delegates to configured
138: * {@link TransactionAnnotationParser TransactionAnnotationParsers}
139: * for parsing known annotations into Spring's metadata attribute class.
140: * Returns <code>null</code> if it's not transactional.
141: * <p>Can be overridden to support custom annotations that carry transaction metadata.
142: * @param ae the annotated method or class
143: * @return TransactionAttribute the configured transaction attribute,
144: * or <code>null</code> if none was found
145: */
146: protected TransactionAttribute determineTransactionAttribute(
147: AnnotatedElement ae) {
148: for (TransactionAnnotationParser annotationParser : this .annotationParsers) {
149: TransactionAttribute attr = annotationParser
150: .parseTransactionAnnotation(ae);
151: if (attr != null) {
152: return attr;
153: }
154: }
155: return null;
156: }
157:
158: /**
159: * By default, only public methods can be made transactional.
160: */
161: protected boolean allowPublicMethodsOnly() {
162: return this .publicMethodsOnly;
163: }
164:
165: public boolean equals(Object other) {
166: return (this == other || other instanceof AnnotationTransactionAttributeSource);
167: }
168:
169: public int hashCode() {
170: return AnnotationTransactionAttributeSource.class.hashCode();
171: }
172:
173: }
|