001
014
015 package com.liferay.portal.spring.aop;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.spring.aop.Skip;
020 import com.liferay.portal.kernel.util.ArrayUtil;
021 import com.liferay.portal.kernel.util.ProxyUtil;
022
023 import java.lang.annotation.Annotation;
024 import java.lang.annotation.ElementType;
025 import java.lang.annotation.Target;
026 import java.lang.reflect.InvocationHandler;
027 import java.lang.reflect.Method;
028
029 import java.util.ArrayList;
030 import java.util.Collections;
031 import java.util.Iterator;
032 import java.util.List;
033 import java.util.Map;
034 import java.util.concurrent.ConcurrentHashMap;
035
036 import org.aopalliance.intercept.MethodInterceptor;
037 import org.aopalliance.intercept.MethodInvocation;
038
039 import org.springframework.aop.SpringProxy;
040 import org.springframework.aop.TargetSource;
041 import org.springframework.aop.framework.AdvisedSupport;
042 import org.springframework.aop.framework.AdvisorChainFactory;
043 import org.springframework.aop.framework.AopProxy;
044 import org.springframework.aop.framework.AopProxyUtils;
045 import org.springframework.util.ClassUtils;
046
047
050 public class ServiceBeanAopProxy implements AopProxy, InvocationHandler {
051
052 public static void clearMethodInterceptorCache() {
053 _methodInterceptorBags.clear();
054 }
055
056 public static void removeMethodInterceptor(
057 MethodInvocation methodInvocation,
058 MethodInterceptor methodInterceptor) {
059
060 if (!(methodInvocation instanceof ServiceBeanMethodInvocation)) {
061 return;
062 }
063
064 ServiceBeanMethodInvocation serviceBeanMethodInvocation =
065 (ServiceBeanMethodInvocation)methodInvocation;
066
067 MethodInterceptorsBag methodInterceptorsBag =
068 _methodInterceptorBags.get(serviceBeanMethodInvocation);
069
070 if (methodInterceptorsBag == null) {
071 return;
072 }
073
074 ArrayList<MethodInterceptor> methodInterceptors =
075 new ArrayList<MethodInterceptor>(
076 methodInterceptorsBag._mergedMethodInterceptors);
077
078 methodInterceptors.remove(methodInterceptor);
079
080 MethodInterceptorsBag newMethodInterceptorsBag = null;
081
082 if (methodInterceptors.equals(
083 methodInterceptorsBag._classLevelMethodInterceptors)) {
084
085 newMethodInterceptorsBag = new MethodInterceptorsBag(
086 methodInterceptorsBag._classLevelMethodInterceptors,
087 methodInterceptorsBag._classLevelMethodInterceptors);
088 }
089 else {
090 methodInterceptors.trimToSize();
091
092 newMethodInterceptorsBag = new MethodInterceptorsBag(
093 methodInterceptorsBag._classLevelMethodInterceptors,
094 methodInterceptors);
095 }
096
097 _methodInterceptorBags.put(
098 serviceBeanMethodInvocation.toCacheKeyModel(),
099 newMethodInterceptorsBag);
100 }
101
102 public ServiceBeanAopProxy(
103 AdvisedSupport advisedSupport, MethodInterceptor methodInterceptor) {
104
105 _advisedSupport = advisedSupport;
106 _advisorChainFactory = _advisedSupport.getAdvisorChainFactory();
107
108 Class<?>[] proxyInterfaces = _advisedSupport.getProxiedInterfaces();
109
110 _mergeSpringMethodInterceptors = !ArrayUtil.contains(
111 proxyInterfaces, SpringProxy.class);
112
113 ArrayList<MethodInterceptor> classLevelMethodInterceptors =
114 new ArrayList<MethodInterceptor>();
115 ArrayList<MethodInterceptor> fullMethodInterceptors =
116 new ArrayList<MethodInterceptor>();
117
118 while (true) {
119 if (!(methodInterceptor instanceof ChainableMethodAdvice)) {
120 classLevelMethodInterceptors.add(methodInterceptor);
121 fullMethodInterceptors.add(methodInterceptor);
122
123 break;
124 }
125
126 ChainableMethodAdvice chainableMethodAdvice =
127 (ChainableMethodAdvice)methodInterceptor;
128
129 if (methodInterceptor instanceof AnnotationChainableMethodAdvice) {
130 AnnotationChainableMethodAdvice<?>
131 annotationChainableMethodAdvice =
132 (AnnotationChainableMethodAdvice<?>)methodInterceptor;
133
134 Class<? extends Annotation> annotationClass =
135 annotationChainableMethodAdvice.getAnnotationClass();
136
137 Target target = annotationClass.getAnnotation(Target.class);
138
139 if (target == null) {
140 classLevelMethodInterceptors.add(methodInterceptor);
141 }
142 else {
143 for (ElementType elementType : target.value()) {
144 if (elementType == ElementType.TYPE) {
145 classLevelMethodInterceptors.add(methodInterceptor);
146
147 break;
148 }
149 }
150 }
151 }
152 else {
153 classLevelMethodInterceptors.add(methodInterceptor);
154 }
155
156 fullMethodInterceptors.add(methodInterceptor);
157
158 methodInterceptor = chainableMethodAdvice.nextMethodInterceptor;
159 }
160
161 classLevelMethodInterceptors.trimToSize();
162
163 _classLevelMethodInterceptors = classLevelMethodInterceptors;
164 _fullMethodInterceptors = fullMethodInterceptors;
165
166 AnnotationChainableMethodAdvice.registerAnnotationClass(Skip.class);
167 }
168
169 public Object getProxy() {
170 return getProxy(ClassUtils.getDefaultClassLoader());
171 }
172
173 public Object getProxy(ClassLoader classLoader) {
174 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
175 _advisedSupport);
176
177 return ProxyUtil.newProxyInstance(classLoader, proxiedInterfaces, this);
178 }
179
180 public Object invoke(Object proxy, Method method, Object[] arguments)
181 throws Throwable {
182
183 TargetSource targetSource = _advisedSupport.getTargetSource();
184
185 Object target = null;
186
187 try {
188 Class<?> targetClass = null;
189
190 target = targetSource.getTarget();
191
192 if (target != null) {
193 targetClass = target.getClass();
194 }
195
196 ServiceBeanMethodInvocation serviceBeanMethodInvocation =
197 new ServiceBeanMethodInvocation(
198 target, targetClass, method, arguments);
199
200 Skip skip = ServiceMethodAnnotationCache.get(
201 serviceBeanMethodInvocation, Skip.class, null);
202
203 if (skip != null) {
204 serviceBeanMethodInvocation.setMethodInterceptors(
205 Collections.<MethodInterceptor>emptyList());
206 }
207 else {
208 _setMethodInterceptors(serviceBeanMethodInvocation);
209 }
210
211 return serviceBeanMethodInvocation.proceed();
212 }
213 finally {
214 if ((target != null) && !targetSource.isStatic()) {
215 targetSource.releaseTarget(target);
216 }
217 }
218 }
219
220 private List<MethodInterceptor> _getMethodInterceptors(
221 ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
222
223 List<MethodInterceptor> methodInterceptors =
224 new ArrayList<MethodInterceptor>(_fullMethodInterceptors);
225
226 if (!_mergeSpringMethodInterceptors) {
227 return methodInterceptors;
228 }
229
230 List<Object> list =
231 _advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
232 _advisedSupport, serviceBeanMethodInvocation.getMethod(),
233 serviceBeanMethodInvocation.getTargetClass());
234
235 Iterator<Object> itr = list.iterator();
236
237 while (itr.hasNext()) {
238 Object obj = itr.next();
239
240 if (obj instanceof MethodInterceptor) {
241 continue;
242 }
243
244 if (_log.isWarnEnabled()) {
245 _log.warn(
246 "Skipping unsupported interceptor type " + obj.getClass());
247 }
248
249 itr.remove();
250 }
251
252 if (list.isEmpty()) {
253 return methodInterceptors;
254 }
255
256 for (Object object : list) {
257 methodInterceptors.add((MethodInterceptor)object);
258 }
259
260 return methodInterceptors;
261 }
262
263 private void _setMethodInterceptors(
264 ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
265
266 MethodInterceptorsBag methodInterceptorsBag =
267 _methodInterceptorBags.get(serviceBeanMethodInvocation);
268
269 if (methodInterceptorsBag == null) {
270 List<MethodInterceptor> methodInterceptors = _getMethodInterceptors(
271 serviceBeanMethodInvocation);
272
273 methodInterceptorsBag = new MethodInterceptorsBag(
274 _classLevelMethodInterceptors, methodInterceptors);
275
276 _methodInterceptorBags.put(
277 serviceBeanMethodInvocation.toCacheKeyModel(),
278 methodInterceptorsBag);
279 }
280
281 serviceBeanMethodInvocation.setMethodInterceptors(
282 methodInterceptorsBag._mergedMethodInterceptors);
283 }
284
285 private static Log _log = LogFactoryUtil.getLog(ServiceBeanAopProxy.class);
286
287 private static Map <ServiceBeanMethodInvocation, MethodInterceptorsBag>
288 _methodInterceptorBags = new ConcurrentHashMap
289 <ServiceBeanMethodInvocation, MethodInterceptorsBag>();
290
291 private AdvisedSupport _advisedSupport;
292 private AdvisorChainFactory _advisorChainFactory;
293 private final List<MethodInterceptor> _classLevelMethodInterceptors;
294 private final List<MethodInterceptor> _fullMethodInterceptors;
295 private boolean _mergeSpringMethodInterceptors;
296
297 private static class MethodInterceptorsBag {
298
299 public MethodInterceptorsBag(
300 List<MethodInterceptor> classLevelMethodInterceptors,
301 List<MethodInterceptor> mergedMethodInterceptors) {
302
303 _classLevelMethodInterceptors = classLevelMethodInterceptors;
304 _mergedMethodInterceptors = mergedMethodInterceptors;
305 }
306
307 private List<MethodInterceptor> _classLevelMethodInterceptors;
308 private List<MethodInterceptor> _mergedMethodInterceptors;
309
310 }
311
312 }