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 || !transactional.enabled()) {
128 return null;
129 }
130
131 RuleBasedTransactionAttribute ruleBasedTransactionAttribute =
132 new RuleBasedTransactionAttribute();
133
134 int isolationLevel = transactional.isolation().value();
135
136 if (isolationLevel == TransactionDefinition.ISOLATION_COUNTER) {
137 ruleBasedTransactionAttribute.setIsolationLevel(
138 PropsValues.TRANSACTION_ISOLATION_COUNTER);
139 }
140 else if (isolationLevel == TransactionDefinition.ISOLATION_PORTAL) {
141 ruleBasedTransactionAttribute.setIsolationLevel(
142 PropsValues.TRANSACTION_ISOLATION_PORTAL);
143 }
144 else {
145 ruleBasedTransactionAttribute.setIsolationLevel(isolationLevel);
146 }
147
148 ruleBasedTransactionAttribute.setPropagationBehavior(
149 transactional.propagation().value());
150 ruleBasedTransactionAttribute.setReadOnly(transactional.readOnly());
151 ruleBasedTransactionAttribute.setTimeout(transactional.timeout());
152
153 List<RollbackRuleAttribute> rollBackAttributes =
154 new ArrayList<RollbackRuleAttribute>();
155
156 Class<?>[] rollbackFor = transactional.rollbackFor();
157
158 for (int i = 0; i < rollbackFor.length; i++) {
159 RollbackRuleAttribute rollbackRuleAttribute =
160 new RollbackRuleAttribute(rollbackFor[i]);
161
162 rollBackAttributes.add(rollbackRuleAttribute);
163 }
164
165 String[] rollbackForClassName = transactional.rollbackForClassName();
166
167 for (int i = 0; i < rollbackForClassName.length; i++) {
168 RollbackRuleAttribute rollbackRuleAttribute =
169 new RollbackRuleAttribute(rollbackForClassName[i]);
170
171 rollBackAttributes.add(rollbackRuleAttribute);
172 }
173
174 Class<?>[] noRollbackFor = transactional.noRollbackFor();
175
176 for (int i = 0; i < noRollbackFor.length; ++i) {
177 NoRollbackRuleAttribute noRollbackRuleAttribute =
178 new NoRollbackRuleAttribute(noRollbackFor[i]);
179
180 rollBackAttributes.add(noRollbackRuleAttribute);
181 }
182
183 String[] noRollbackForClassName =
184 transactional.noRollbackForClassName();
185
186 for (int i = 0; i < noRollbackForClassName.length; ++i) {
187 NoRollbackRuleAttribute noRollbackRuleAttribute =
188 new NoRollbackRuleAttribute(noRollbackForClassName[i]);
189
190 rollBackAttributes.add(noRollbackRuleAttribute);
191 }
192
193 ruleBasedTransactionAttribute.getRollbackRules().addAll(
194 rollBackAttributes);
195
196 return ruleBasedTransactionAttribute;
197 }
198
199 private void _queueSuperTypes(
200 Class<?> clazz, Queue<Class<?>> candidateQueue) {
201
202 Class<?> supperClass = clazz.getSuperclass();
203
204 if ((supperClass != null) && (supperClass != Object.class)) {
205 candidateQueue.offer(supperClass);
206 }
207
208 Class<?>[] interfaces = clazz.getInterfaces();
209
210 for (Class<?> inter : interfaces) {
211 candidateQueue.offer(inter);
212 }
213 }
214
215 private static TransactionAttribute _nullTransactionAttribute =
216 new DefaultTransactionAttribute();
217 private Map<MethodTargetClassKey, TransactionAttribute>
218 _transactionAttributes =
219 new ConcurrentHashMap<MethodTargetClassKey, TransactionAttribute>();
220
221 }