1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
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  /**
39   * <a href="AnnotationTransactionAttributeSource.java.html"><b><i>View Source
40   * </i></b></a>
41   *
42   * @author Shuyang Zhou
43   */
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 }