001
014
015 package com.liferay.portal.spring.transaction;
016
017 import com.liferay.portal.kernel.annotation.TransactionDefinition;
018 import com.liferay.portal.kernel.annotation.Transactional;
019 import com.liferay.portal.kernel.util.MethodTargetClassKey;
020 import com.liferay.portal.util.PropsValues;
021
022 import java.lang.reflect.Method;
023
024 import java.util.ArrayList;
025 import java.util.LinkedList;
026 import java.util.List;
027 import java.util.Map;
028 import java.util.Queue;
029 import java.util.concurrent.ConcurrentHashMap;
030
031 import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
032 import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
033 import org.springframework.transaction.interceptor.RollbackRuleAttribute;
034 import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
035 import org.springframework.transaction.interceptor.TransactionAttribute;
036 import org.springframework.transaction.interceptor.TransactionAttributeSource;
037
038
041 public class AnnotationTransactionAttributeSource
042 implements TransactionAttributeSource {
043
044 @SuppressWarnings("rawtypes")
045 public TransactionAttribute getTransactionAttribute(
046 Method method, Class targetClass) {
047
048 MethodTargetClassKey methodTargetClassKey = new MethodTargetClassKey(
049 method, targetClass);
050
051 TransactionAttribute transactionAttribute = _transactionAttributes.get(
052 methodTargetClassKey);
053
054 if (transactionAttribute != null) {
055 if (transactionAttribute == _nullTransactionAttribute) {
056 return null;
057 }
058 else {
059 return transactionAttribute;
060 }
061 }
062
063 Queue<Class<?>> candidateQueue = new LinkedList<Class<?>>();
064
065 if (targetClass == null) {
066 candidateQueue.offer(method.getDeclaringClass());
067 }
068 else {
069 candidateQueue.offer(targetClass);
070 }
071
072 Transactional transactional = _findTransactionAnnotation(
073 method, candidateQueue);
074
075 transactionAttribute = _parseTransactionAnnotation(transactional);
076
077 if (transactionAttribute == null) {
078 _transactionAttributes.put(
079 methodTargetClassKey, _nullTransactionAttribute);
080 }
081 else {
082 _transactionAttributes.put(
083 methodTargetClassKey, transactionAttribute);
084 }
085
086 return transactionAttribute;
087 }
088
089 private Transactional _findTransactionAnnotation(
090 Method method, Queue<Class<?>> candidateQueue) {
091
092 if (candidateQueue.isEmpty()) {
093 return null;
094 }
095
096 Transactional transactional = null;
097
098 Class<?> clazz = candidateQueue.poll();
099
100 try {
101 Method specificMethod = clazz.getDeclaredMethod(
102 method.getName(), method.getParameterTypes());
103
104 transactional = specificMethod.getAnnotation(Transactional.class);
105
106 if (transactional != null) {
107 return transactional;
108 }
109 }
110 catch (Exception e) {
111 }
112
113 transactional = clazz.getAnnotation(Transactional.class);
114
115 if (transactional != null) {
116 return transactional;
117 }
118
119 _queueSuperTypes(clazz, candidateQueue);
120
121 return _findTransactionAnnotation(method, candidateQueue);
122 }
123
124 private TransactionAttribute _parseTransactionAnnotation(
125 Transactional transactional) {
126
127 if (transactional == null) {
128 return null;
129 }
130
131 RuleBasedTransactionAttribute ruleBasedTransactionAttribute =
132 new RuleBasedTransactionAttribute();
133
134 int isolationLevel = transactional.isolation().value();
135
136 if (isolationLevel == TransactionDefinition.ISOLATION_PORTAL) {
137 ruleBasedTransactionAttribute.setIsolationLevel(
138 PropsValues.TRANSACTION_ISOLATION_PORTAL);
139 }
140 else {
141 ruleBasedTransactionAttribute.setIsolationLevel(isolationLevel);
142 }
143
144 ruleBasedTransactionAttribute.setPropagationBehavior(
145 transactional.propagation().value());
146 ruleBasedTransactionAttribute.setReadOnly(transactional.readOnly());
147 ruleBasedTransactionAttribute.setTimeout(transactional.timeout());
148
149 List<RollbackRuleAttribute> rollBackAttributes =
150 new ArrayList<RollbackRuleAttribute>();
151
152 Class<?>[] rollbackFor = transactional.rollbackFor();
153
154 for (int i = 0; i < rollbackFor.length; i++) {
155 RollbackRuleAttribute rollbackRuleAttribute =
156 new RollbackRuleAttribute(rollbackFor[i]);
157
158 rollBackAttributes.add(rollbackRuleAttribute);
159 }
160
161 String[] rollbackForClassName = transactional.rollbackForClassName();
162
163 for (int i = 0; i < rollbackForClassName.length; i++) {
164 RollbackRuleAttribute rollbackRuleAttribute =
165 new RollbackRuleAttribute(rollbackForClassName[i]);
166
167 rollBackAttributes.add(rollbackRuleAttribute);
168 }
169
170 Class<?>[] noRollbackFor = transactional.noRollbackFor();
171
172 for (int i = 0; i < noRollbackFor.length; ++i) {
173 NoRollbackRuleAttribute noRollbackRuleAttribute =
174 new NoRollbackRuleAttribute(noRollbackFor[i]);
175
176 rollBackAttributes.add(noRollbackRuleAttribute);
177 }
178
179 String[] noRollbackForClassName =
180 transactional.noRollbackForClassName();
181
182 for (int i = 0; i < noRollbackForClassName.length; ++i) {
183 NoRollbackRuleAttribute noRollbackRuleAttribute =
184 new NoRollbackRuleAttribute(noRollbackForClassName[i]);
185
186 rollBackAttributes.add(noRollbackRuleAttribute);
187 }
188
189 ruleBasedTransactionAttribute.getRollbackRules().addAll(
190 rollBackAttributes);
191
192 return ruleBasedTransactionAttribute;
193 }
194
195 private void _queueSuperTypes(
196 Class<?> clazz, Queue<Class<?>> candidateQueue) {
197
198 Class<?> supperClass = clazz.getSuperclass();
199
200 if ((supperClass != null) && (supperClass != Object.class)) {
201 candidateQueue.offer(supperClass);
202 }
203
204 Class<?>[] interfaces = clazz.getInterfaces();
205
206 for (Class<?> inter : interfaces) {
207 candidateQueue.offer(inter);
208 }
209 }
210
211 private static TransactionAttribute _nullTransactionAttribute =
212 new DefaultTransactionAttribute();
213 private Map<MethodTargetClassKey, TransactionAttribute>
214 _transactionAttributes =
215 new ConcurrentHashMap<MethodTargetClassKey, TransactionAttribute>();
216
217 }