1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.spring.annotation;
16  
17  import com.liferay.portal.kernel.annotation.TransactionDefinition;
18  import com.liferay.portal.kernel.annotation.Transactional;
19  import com.liferay.portal.util.PropsValues;
20  
21  import java.io.Serializable;
22  
23  import java.lang.reflect.AnnotatedElement;
24  import java.lang.reflect.Method;
25  
26  import java.util.ArrayList;
27  import java.util.LinkedList;
28  import java.util.List;
29  import java.util.Queue;
30  
31  import org.springframework.transaction.annotation.TransactionAnnotationParser;
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  
37  /**
38   * <a href="PortalTransactionAnnotationParser.java.html"><b><i>View Source</i>
39   * </b></a>
40   *
41   * @author Michael Young
42   * @author Shuyang Zhou
43   */
44  public class PortalTransactionAnnotationParser
45      implements TransactionAnnotationParser, Serializable {
46  
47      public TransactionAttribute parseTransactionAnnotation(
48          AnnotatedElement annotatedElement) {
49  
50          //Transactional annotation = annotatedElement.getAnnotation(
51          //  Transactional.class);
52  
53          Transactional annotation = null;
54  
55          Queue<Class<?>> candidateQueue = new LinkedList<Class<?>>();
56  
57          if (annotatedElement instanceof Method) {
58              Method method = (Method)annotatedElement;
59  
60              candidateQueue.offer(method.getDeclaringClass());
61  
62              annotation = _deepSearchMethods(method, candidateQueue);
63          }
64          else {
65              candidateQueue.offer((Class<?>)annotatedElement);
66  
67              annotation = _deepSearchTypes(candidateQueue);
68          }
69  
70          if (annotation == null) {
71              return null;
72          }
73  
74          RuleBasedTransactionAttribute ruleBasedTransactionAttribute =
75              new RuleBasedTransactionAttribute();
76  
77          int isolationLevel = annotation.isolation().value();
78  
79          if (isolationLevel == TransactionDefinition.ISOLATION_PORTAL) {
80              ruleBasedTransactionAttribute.setIsolationLevel(
81                  PropsValues.TRANSACTION_ISOLATION_PORTAL);
82          }
83          else {
84              ruleBasedTransactionAttribute.setIsolationLevel(isolationLevel);
85          }
86  
87          ruleBasedTransactionAttribute.setPropagationBehavior(
88              annotation.propagation().value());
89          ruleBasedTransactionAttribute.setReadOnly(annotation.readOnly());
90          ruleBasedTransactionAttribute.setTimeout(annotation.timeout());
91  
92          List<RollbackRuleAttribute> rollBackAttributes =
93              new ArrayList<RollbackRuleAttribute>();
94  
95          Class<?>[] rollbackFor = annotation.rollbackFor();
96  
97          for (int i = 0; i < rollbackFor.length; i++) {
98              RollbackRuleAttribute rollbackRuleAttribute =
99                  new RollbackRuleAttribute(rollbackFor[i]);
100 
101             rollBackAttributes.add(rollbackRuleAttribute);
102         }
103 
104         String[] rollbackForClassName = annotation.rollbackForClassName();
105 
106         for (int i = 0; i < rollbackForClassName.length; i++) {
107             RollbackRuleAttribute rollbackRuleAttribute =
108                 new RollbackRuleAttribute(rollbackForClassName[i]);
109 
110             rollBackAttributes.add(rollbackRuleAttribute);
111         }
112 
113         Class<?>[] noRollbackFor = annotation.noRollbackFor();
114 
115         for (int i = 0; i < noRollbackFor.length; ++i) {
116             NoRollbackRuleAttribute noRollbackRuleAttribute =
117                 new NoRollbackRuleAttribute(noRollbackFor[i]);
118 
119             rollBackAttributes.add(noRollbackRuleAttribute);
120         }
121 
122         String[] noRollbackForClassName = annotation.noRollbackForClassName();
123 
124         for (int i = 0; i < noRollbackForClassName.length; ++i) {
125             NoRollbackRuleAttribute noRollbackRuleAttribute =
126                 new NoRollbackRuleAttribute(noRollbackForClassName[i]);
127 
128             rollBackAttributes.add(noRollbackRuleAttribute);
129         }
130 
131         ruleBasedTransactionAttribute.getRollbackRules().addAll(
132             rollBackAttributes);
133 
134         return ruleBasedTransactionAttribute;
135     }
136 
137     private Transactional _deepSearchMethods(
138         Method method, Queue<Class<?>> candidateQueue) {
139 
140         Transactional annotation = method.getAnnotation(Transactional.class);
141 
142         if (annotation != null) {
143             return annotation;
144         }
145 
146         if (candidateQueue.isEmpty()) {
147             return null;
148         }
149 
150         Class<?> clazz = candidateQueue.poll();
151 
152         if (method.getDeclaringClass() != clazz) {
153             try {
154                 Method specificMethod = clazz.getDeclaredMethod(
155                     method.getName(), method.getParameterTypes());
156 
157                 annotation = specificMethod.getAnnotation(Transactional.class);
158 
159                 if (annotation != null) {
160                     return annotation;
161                 }
162             }
163             catch (Exception e) {
164             }
165         }
166 
167         annotation = clazz.getAnnotation(Transactional.class);
168 
169         if (annotation == null) {
170             _queueSuperTypes(clazz, candidateQueue);
171 
172             return _deepSearchMethods(method, candidateQueue);
173         }
174         else {
175             return annotation;
176         }
177     }
178 
179     private Transactional _deepSearchTypes(Queue<Class<?>> candidateQueue) {
180         if (candidateQueue.isEmpty()) {
181             return null;
182         }
183 
184         Class<?> clazz = candidateQueue.poll();
185 
186         Transactional annotation = clazz.getAnnotation(Transactional.class);
187 
188         if (annotation == null) {
189             _queueSuperTypes(clazz, candidateQueue);
190 
191             return _deepSearchTypes(candidateQueue);
192         }
193         else {
194             return annotation;
195         }
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 }