1
14
15 package com.liferay.portal.spring.transaction;
16
17 import com.liferay.portal.kernel.annotation.TransactionDefinition;
18 import com.liferay.portal.kernel.annotation.Transactional;
19 import com.liferay.portal.kernel.util.MethodTargetClassKey;
20 import com.liferay.portal.util.PropsValues;
21
22 import java.lang.reflect.Method;
23
24 import java.util.ArrayList;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Queue;
29 import java.util.concurrent.ConcurrentHashMap;
30
31 import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
32 import org.springframework.transaction.interceptor.NoRollbackRuleAttribute;
33 import org.springframework.transaction.interceptor.RollbackRuleAttribute;
34 import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
35 import org.springframework.transaction.interceptor.TransactionAttribute;
36 import org.springframework.transaction.interceptor.TransactionAttributeSource;
37
38
44 public class AnnotationTransactionAttributeSource
45 implements TransactionAttributeSource {
46
47 @SuppressWarnings("rawtypes")
48 public TransactionAttribute getTransactionAttribute(
49 Method method, Class targetClass) {
50
51 MethodTargetClassKey methodTargetClassKey = new MethodTargetClassKey(
52 method, targetClass);
53
54 TransactionAttribute transactionAttribute = _transactionAttributes.get(
55 methodTargetClassKey);
56
57 if (transactionAttribute != null) {
58 if (transactionAttribute == _nullTransactionAttribute) {
59 return null;
60 }
61 else {
62 return transactionAttribute;
63 }
64 }
65
66 Queue<Class<?>> candidateQueue = new LinkedList<Class<?>>();
67
68 if (targetClass == null) {
69 candidateQueue.offer(method.getDeclaringClass());
70 }
71 else {
72 candidateQueue.offer(targetClass);
73 }
74
75 Transactional transactional = _findTransactionAnnotation(
76 method, candidateQueue);
77
78 transactionAttribute = _parseTransactionAnnotation(transactional);
79
80 if (transactionAttribute == null) {
81 _transactionAttributes.put(
82 methodTargetClassKey, _nullTransactionAttribute);
83 }
84 else {
85 _transactionAttributes.put(
86 methodTargetClassKey, transactionAttribute);
87 }
88
89 return transactionAttribute;
90 }
91
92 private Transactional _findTransactionAnnotation(
93 Method method, Queue<Class<?>> candidateQueue) {
94
95 if (candidateQueue.isEmpty()) {
96 return null;
97 }
98
99 Transactional transactional = null;
100
101 Class<?> clazz = candidateQueue.poll();
102
103 try {
104 Method specificMethod = clazz.getDeclaredMethod(
105 method.getName(), method.getParameterTypes());
106
107 transactional = specificMethod.getAnnotation(Transactional.class);
108
109 if (transactional != null) {
110 return transactional;
111 }
112 }
113 catch (Exception e) {
114 }
115
116 transactional = clazz.getAnnotation(Transactional.class);
117
118 if (transactional != null) {
119 return transactional;
120 }
121
122 _queueSuperTypes(clazz, candidateQueue);
123
124 return _findTransactionAnnotation(method, candidateQueue);
125 }
126
127 private TransactionAttribute _parseTransactionAnnotation(
128 Transactional transactional) {
129
130 if (transactional == null || !transactional.enabled()) {
131 return null;
132 }
133
134 RuleBasedTransactionAttribute ruleBasedTransactionAttribute =
135 new RuleBasedTransactionAttribute();
136
137 int isolationLevel = transactional.isolation().value();
138
139 if (isolationLevel == TransactionDefinition.ISOLATION_PORTAL) {
140 ruleBasedTransactionAttribute.setIsolationLevel(
141 PropsValues.TRANSACTION_ISOLATION_PORTAL);
142 }
143 else {
144 ruleBasedTransactionAttribute.setIsolationLevel(isolationLevel);
145 }
146
147 ruleBasedTransactionAttribute.setPropagationBehavior(
148 transactional.propagation().value());
149 ruleBasedTransactionAttribute.setReadOnly(transactional.readOnly());
150 ruleBasedTransactionAttribute.setTimeout(transactional.timeout());
151
152 List<RollbackRuleAttribute> rollBackAttributes =
153 new ArrayList<RollbackRuleAttribute>();
154
155 Class<?>[] rollbackFor = transactional.rollbackFor();
156
157 for (int i = 0; i < rollbackFor.length; i++) {
158 RollbackRuleAttribute rollbackRuleAttribute =
159 new RollbackRuleAttribute(rollbackFor[i]);
160
161 rollBackAttributes.add(rollbackRuleAttribute);
162 }
163
164 String[] rollbackForClassName = transactional.rollbackForClassName();
165
166 for (int i = 0; i < rollbackForClassName.length; i++) {
167 RollbackRuleAttribute rollbackRuleAttribute =
168 new RollbackRuleAttribute(rollbackForClassName[i]);
169
170 rollBackAttributes.add(rollbackRuleAttribute);
171 }
172
173 Class<?>[] noRollbackFor = transactional.noRollbackFor();
174
175 for (int i = 0; i < noRollbackFor.length; ++i) {
176 NoRollbackRuleAttribute noRollbackRuleAttribute =
177 new NoRollbackRuleAttribute(noRollbackFor[i]);
178
179 rollBackAttributes.add(noRollbackRuleAttribute);
180 }
181
182 String[] noRollbackForClassName =
183 transactional.noRollbackForClassName();
184
185 for (int i = 0; i < noRollbackForClassName.length; ++i) {
186 NoRollbackRuleAttribute noRollbackRuleAttribute =
187 new NoRollbackRuleAttribute(noRollbackForClassName[i]);
188
189 rollBackAttributes.add(noRollbackRuleAttribute);
190 }
191
192 ruleBasedTransactionAttribute.getRollbackRules().addAll(
193 rollBackAttributes);
194
195 return ruleBasedTransactionAttribute;
196 }
197
198 private void _queueSuperTypes(
199 Class<?> clazz, Queue<Class<?>> candidateQueue) {
200
201 Class<?> supperClass = clazz.getSuperclass();
202
203 if ((supperClass != null) && (supperClass != Object.class)) {
204 candidateQueue.offer(supperClass);
205 }
206
207 Class<?>[] interfaces = clazz.getInterfaces();
208
209 for (Class<?> inter : interfaces) {
210 candidateQueue.offer(inter);
211 }
212 }
213
214 private static TransactionAttribute _nullTransactionAttribute =
215 new DefaultTransactionAttribute();
216 private Map<MethodTargetClassKey, TransactionAttribute>
217 _transactionAttributes =
218 new ConcurrentHashMap<MethodTargetClassKey, TransactionAttribute>();
219
220 }