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 @Override
170 public Object getProxy() {
171 return getProxy(ClassUtils.getDefaultClassLoader());
172 }
173
174 @Override
175 public Object getProxy(ClassLoader classLoader) {
176 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
177 _advisedSupport);
178
179 InvocationHandler invocationHandler = _pacl.getInvocationHandler(
180 this, _advisedSupport);
181
182 return ProxyUtil.newProxyInstance(
183 classLoader, proxiedInterfaces, invocationHandler);
184 }
185
186 @Override
187 public Object invoke(Object proxy, Method method, Object[] arguments)
188 throws Throwable {
189
190 TargetSource targetSource = _advisedSupport.getTargetSource();
191
192 Object target = null;
193
194 try {
195 Class<?> targetClass = null;
196
197 target = targetSource.getTarget();
198
199 if (target != null) {
200 targetClass = target.getClass();
201 }
202
203 ServiceBeanMethodInvocation serviceBeanMethodInvocation =
204 new ServiceBeanMethodInvocation(
205 target, targetClass, method, arguments);
206
207 Skip skip = ServiceMethodAnnotationCache.get(
208 serviceBeanMethodInvocation, Skip.class, null);
209
210 if (skip != null) {
211 serviceBeanMethodInvocation.setMethodInterceptors(
212 Collections.<MethodInterceptor>emptyList());
213 }
214 else {
215 _setMethodInterceptors(serviceBeanMethodInvocation);
216 }
217
218 return serviceBeanMethodInvocation.proceed();
219 }
220 finally {
221 if ((target != null) && !targetSource.isStatic()) {
222 targetSource.releaseTarget(target);
223 }
224 }
225 }
226
227 private List<MethodInterceptor> _getMethodInterceptors(
228 ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
229
230 List<MethodInterceptor> methodInterceptors =
231 new ArrayList<MethodInterceptor>(_fullMethodInterceptors);
232
233 if (!_mergeSpringMethodInterceptors) {
234 return methodInterceptors;
235 }
236
237 List<Object> list =
238 _advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
239 _advisedSupport, serviceBeanMethodInvocation.getMethod(),
240 serviceBeanMethodInvocation.getTargetClass());
241
242 Iterator<Object> itr = list.iterator();
243
244 while (itr.hasNext()) {
245 Object obj = itr.next();
246
247 if (obj instanceof MethodInterceptor) {
248 continue;
249 }
250
251 if (_log.isWarnEnabled()) {
252 _log.warn(
253 "Skipping unsupported interceptor type " + obj.getClass());
254 }
255
256 itr.remove();
257 }
258
259 if (list.isEmpty()) {
260 return methodInterceptors;
261 }
262
263 for (Object object : list) {
264 methodInterceptors.add((MethodInterceptor)object);
265 }
266
267 return methodInterceptors;
268 }
269
270 private void _setMethodInterceptors(
271 ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
272
273 MethodInterceptorsBag methodInterceptorsBag =
274 _methodInterceptorBags.get(serviceBeanMethodInvocation);
275
276 if (methodInterceptorsBag == null) {
277 List<MethodInterceptor> methodInterceptors = _getMethodInterceptors(
278 serviceBeanMethodInvocation);
279
280 methodInterceptorsBag = new MethodInterceptorsBag(
281 _classLevelMethodInterceptors, methodInterceptors);
282
283 _methodInterceptorBags.put(
284 serviceBeanMethodInvocation.toCacheKeyModel(),
285 methodInterceptorsBag);
286 }
287
288 serviceBeanMethodInvocation.setMethodInterceptors(
289 methodInterceptorsBag._mergedMethodInterceptors);
290 }
291
292 private static Log _log = LogFactoryUtil.getLog(ServiceBeanAopProxy.class);
293
294 private static Map <ServiceBeanMethodInvocation, MethodInterceptorsBag>
295 _methodInterceptorBags = new ConcurrentHashMap
296 <ServiceBeanMethodInvocation, MethodInterceptorsBag>();
297 private static PACL _pacl = new NoPACL();
298
299 private AdvisedSupport _advisedSupport;
300 private AdvisorChainFactory _advisorChainFactory;
301 private final List<MethodInterceptor> _classLevelMethodInterceptors;
302 private final List<MethodInterceptor> _fullMethodInterceptors;
303 private boolean _mergeSpringMethodInterceptors;
304
305 private static class MethodInterceptorsBag {
306
307 public MethodInterceptorsBag(
308 List<MethodInterceptor> classLevelMethodInterceptors,
309 List<MethodInterceptor> mergedMethodInterceptors) {
310
311 _classLevelMethodInterceptors = classLevelMethodInterceptors;
312 _mergedMethodInterceptors = mergedMethodInterceptors;
313 }
314
315 private List<MethodInterceptor> _classLevelMethodInterceptors;
316 private List<MethodInterceptor> _mergedMethodInterceptors;
317
318 }
319
320 private static class NoPACL implements PACL {
321
322 @Override
323 public InvocationHandler getInvocationHandler(
324 InvocationHandler invocationHandler,
325 AdvisedSupport advisedSupport) {
326
327 return invocationHandler;
328 }
329
330 }
331
332 public static interface PACL {
333
334 public InvocationHandler getInvocationHandler(
335 InvocationHandler invocationHandler, AdvisedSupport advisedSupport);
336
337 }
338
339 }