001: /*
002: * Copyright 2002-2006 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.Method;
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.Collection;
024:
025: import org.springframework.core.annotation.AnnotationUtils;
026: import org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource;
027: import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
028: import org.springframework.transaction.interceptor.RollbackRuleAttribute;
029: import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
030: import org.springframework.transaction.interceptor.TransactionAttribute;
031:
032: /**
033: * Implementation of the
034: * {@link org.springframework.transaction.interceptor.TransactionAttributeSource}
035: * interface for working with transaction metadata in JDK 1.5+ annotation format.
036: *
037: * <p>This class reads Spring's JDK 1.5+ {@link Transactional} annotation and
038: * exposes corresponding transaction attributes to Spring's transaction infrastructure.
039: * Can also be used as base class for a custom annotation-based TransactionAttributeSource.
040: *
041: * <p>This is a direct alternative to
042: * {@link org.springframework.transaction.interceptor.AttributesTransactionAttributeSource},
043: * which is able to read in source-level attributes via Commons Attributes.
044: *
045: * @author Colin Sampaleanu
046: * @author Juergen Hoeller
047: * @since 1.2
048: * @see Transactional
049: * @see #findTransactionAttribute
050: * @see org.springframework.transaction.interceptor.TransactionInterceptor#setTransactionAttributeSource
051: * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean#setTransactionAttributeSource
052: * @see org.springframework.transaction.interceptor.AttributesTransactionAttributeSource
053: * @see org.springframework.metadata.commons.CommonsAttributes
054: */
055: public class AnnotationTransactionAttributeSource extends
056: AbstractFallbackTransactionAttributeSource implements
057: Serializable {
058:
059: private final boolean publicMethodsOnly;
060:
061: /**
062: * Create a default AnnotationTransactionAttributeSource, supporting
063: * public methods that carry the <code>Transactional</code> annotation.
064: */
065: public AnnotationTransactionAttributeSource() {
066: this .publicMethodsOnly = true;
067: }
068:
069: /**
070: * Create a custom AnnotationTransactionAttributeSource.
071: * @param publicMethodsOnly whether to support public methods that carry
072: * the <code>Transactional</code> annotation only (typically for use
073: * with proxy-based AOP), or protected/private methods as well
074: * (typically used with AspectJ class weaving)
075: */
076: public AnnotationTransactionAttributeSource(
077: boolean publicMethodsOnly) {
078: this .publicMethodsOnly = publicMethodsOnly;
079: }
080:
081: /**
082: * Returns all JDK 1.5+ annotations found for the given method.
083: */
084: protected Collection findAllAttributes(Method method) {
085: return Arrays.asList(AnnotationUtils.getAnnotations(method));
086: }
087:
088: /**
089: * Returns all JDK 1.5+ annotations found for the given class.
090: */
091: protected Collection findAllAttributes(Class clazz) {
092: return Arrays.asList(clazz.getAnnotations());
093: }
094:
095: /**
096: * Return the transaction attribute, given this set of attributes
097: * attached to a method or class. Overrides method from parent class.
098: * <p>This implementation converts Spring's <code>Transactional</code> annotation
099: * to the Spring metadata classes. Returns <code>null</code> if it's not transactional.
100: * <p>Can be overridden to support custom annotations that carry transaction metadata.
101: * @param atts attributes attached to a method or class. May be <code>null</code>,
102: * in which case a <code>null</code> TransactionAttribute will be returned.
103: * @return TransactionAttribute the configured transaction attribute,
104: * or <code>null</code> if none was found
105: * @see Transactional
106: */
107: protected TransactionAttribute findTransactionAttribute(
108: Collection atts) {
109: if (atts == null) {
110: return null;
111: }
112:
113: // See if there is a transaction annotation.
114: for (Object att : atts) {
115: if (att instanceof Transactional) {
116: Transactional ruleBasedTx = (Transactional) att;
117:
118: RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
119: rbta.setPropagationBehavior(ruleBasedTx.propagation()
120: .value());
121: rbta.setIsolationLevel(ruleBasedTx.isolation().value());
122: rbta.setTimeout(ruleBasedTx.timeout());
123: rbta.setReadOnly(ruleBasedTx.readOnly());
124:
125: ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
126:
127: Class[] rbf = ruleBasedTx.rollbackFor();
128: for (int i = 0; i < rbf.length; ++i) {
129: RollbackRuleAttribute rule = new RollbackRuleAttribute(
130: rbf[i]);
131: rollBackRules.add(rule);
132: }
133:
134: String[] rbfc = ruleBasedTx.rollbackForClassName();
135: for (int i = 0; i < rbfc.length; ++i) {
136: RollbackRuleAttribute rule = new RollbackRuleAttribute(
137: rbfc[i]);
138: rollBackRules.add(rule);
139: }
140:
141: Class[] nrbf = ruleBasedTx.noRollbackFor();
142: for (int i = 0; i < nrbf.length; ++i) {
143: NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(
144: nrbf[i]);
145: rollBackRules.add(rule);
146: }
147:
148: String[] nrbfc = ruleBasedTx.noRollbackForClassName();
149: for (int i = 0; i < nrbfc.length; ++i) {
150: NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(
151: nrbfc[i]);
152: rollBackRules.add(rule);
153: }
154:
155: rbta.getRollbackRules().addAll(rollBackRules);
156:
157: return rbta;
158: }
159: }
160:
161: return null;
162: }
163:
164: /**
165: * By default, only public methods can be made transactional using
166: * {@link Transactional}.
167: */
168: protected boolean allowPublicMethodsOnly() {
169: return this .publicMethodsOnly;
170: }
171:
172: public boolean equals(Object other) {
173: return (this == other || other instanceof AnnotationTransactionAttributeSource);
174: }
175:
176: public int hashCode() {
177: return AnnotationTransactionAttributeSource.class.hashCode();
178: }
179:
180: }
|