001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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    
034    import org.aopalliance.intercept.MethodInterceptor;
035    
036    import org.springframework.aop.SpringProxy;
037    import org.springframework.aop.TargetSource;
038    import org.springframework.aop.framework.AdvisedSupport;
039    import org.springframework.aop.framework.AdvisorChainFactory;
040    import org.springframework.aop.framework.AopProxy;
041    import org.springframework.aop.framework.AopProxyUtils;
042    import org.springframework.util.ClassUtils;
043    
044    /**
045     * @author Shuyang Zhou
046     */
047    public class ServiceBeanAopProxy implements AopProxy, InvocationHandler {
048    
049            public ServiceBeanAopProxy(
050                    AdvisedSupport advisedSupport, MethodInterceptor methodInterceptor,
051                    ServiceBeanAopCacheManager serviceBeanAopCacheManager) {
052    
053                    _advisedSupport = advisedSupport;
054                    _advisorChainFactory = _advisedSupport.getAdvisorChainFactory();
055    
056                    Class<?>[] proxyInterfaces = _advisedSupport.getProxiedInterfaces();
057    
058                    _mergeSpringMethodInterceptors = !ArrayUtil.contains(
059                            proxyInterfaces, SpringProxy.class);
060    
061                    ArrayList<MethodInterceptor> classLevelMethodInterceptors =
062                            new ArrayList<MethodInterceptor>();
063                    ArrayList<MethodInterceptor> fullMethodInterceptors =
064                            new ArrayList<MethodInterceptor>();
065    
066                    while (true) {
067                            if (!(methodInterceptor instanceof ChainableMethodAdvice)) {
068                                    classLevelMethodInterceptors.add(methodInterceptor);
069                                    fullMethodInterceptors.add(methodInterceptor);
070    
071                                    break;
072                            }
073    
074                            ChainableMethodAdvice chainableMethodAdvice =
075                                    (ChainableMethodAdvice)methodInterceptor;
076    
077                            chainableMethodAdvice.setServiceBeanAopCacheManager(
078                                    serviceBeanAopCacheManager);
079    
080                            if (methodInterceptor instanceof AnnotationChainableMethodAdvice) {
081                                    AnnotationChainableMethodAdvice<?>
082                                            annotationChainableMethodAdvice =
083                                                    (AnnotationChainableMethodAdvice<?>)methodInterceptor;
084    
085                                    Class<? extends Annotation> annotationClass =
086                                            annotationChainableMethodAdvice.getAnnotationClass();
087    
088                                    Target target = annotationClass.getAnnotation(Target.class);
089    
090                                    if (target == null) {
091                                            classLevelMethodInterceptors.add(methodInterceptor);
092                                    }
093                                    else {
094                                            for (ElementType elementType : target.value()) {
095                                                    if (elementType == ElementType.TYPE) {
096                                                            classLevelMethodInterceptors.add(methodInterceptor);
097    
098                                                            break;
099                                                    }
100                                            }
101                                    }
102                            }
103                            else {
104                                    classLevelMethodInterceptors.add(methodInterceptor);
105                            }
106    
107                            fullMethodInterceptors.add(methodInterceptor);
108    
109                            methodInterceptor = chainableMethodAdvice.nextMethodInterceptor;
110                    }
111    
112                    classLevelMethodInterceptors.trimToSize();
113    
114                    _classLevelMethodInterceptors = classLevelMethodInterceptors;
115                    _fullMethodInterceptors = fullMethodInterceptors;
116    
117                    _serviceBeanAopCacheManager = serviceBeanAopCacheManager;
118            }
119    
120            public Object getProxy() {
121                    return getProxy(ClassUtils.getDefaultClassLoader());
122            }
123    
124            public Object getProxy(ClassLoader classLoader) {
125                    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
126                            _advisedSupport);
127    
128                    InvocationHandler invocationHandler = _pacl.getInvocationHandler(
129                            this, _advisedSupport);
130    
131                    return ProxyUtil.newProxyInstance(
132                            classLoader, proxiedInterfaces, invocationHandler);
133            }
134    
135            public Object invoke(Object proxy, Method method, Object[] arguments)
136                    throws Throwable {
137    
138                    TargetSource targetSource = _advisedSupport.getTargetSource();
139    
140                    Object target = null;
141    
142                    try {
143                            Class<?> targetClass = null;
144    
145                            target = targetSource.getTarget();
146    
147                            if (target != null) {
148                                    targetClass = target.getClass();
149                            }
150    
151                            ServiceBeanMethodInvocation serviceBeanMethodInvocation =
152                                    new ServiceBeanMethodInvocation(
153                                            target, targetClass, method, arguments);
154    
155                            Skip skip = ServiceBeanAopCacheManager.getAnnotation(
156                                    serviceBeanMethodInvocation, Skip.class, null);
157    
158                            if (skip != null) {
159                                    serviceBeanMethodInvocation.setMethodInterceptors(
160                                            Collections.<MethodInterceptor>emptyList());
161                            }
162                            else {
163                                    _setMethodInterceptors(serviceBeanMethodInvocation);
164                            }
165    
166                            return serviceBeanMethodInvocation.proceed();
167                    }
168                    finally {
169                            if ((target != null) && !targetSource.isStatic()) {
170                                    targetSource.releaseTarget(target);
171                            }
172                    }
173            }
174    
175            private List<MethodInterceptor> _getMethodInterceptors(
176                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
177    
178                    List<MethodInterceptor> methodInterceptors =
179                            new ArrayList<MethodInterceptor>(_fullMethodInterceptors);
180    
181                    if (!_mergeSpringMethodInterceptors) {
182                            return methodInterceptors;
183                    }
184    
185                    List<Object> list =
186                            _advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
187                                    _advisedSupport, serviceBeanMethodInvocation.getMethod(),
188                                    serviceBeanMethodInvocation.getTargetClass());
189    
190                    Iterator<Object> itr = list.iterator();
191    
192                    while (itr.hasNext()) {
193                            Object obj = itr.next();
194    
195                            if (obj instanceof MethodInterceptor) {
196                                    continue;
197                            }
198    
199                            if (_log.isWarnEnabled()) {
200                                    _log.warn(
201                                            "Skipping unsupported interceptor type " + obj.getClass());
202                            }
203    
204                            itr.remove();
205                    }
206    
207                    if (list.isEmpty()) {
208                            return methodInterceptors;
209                    }
210    
211                    for (Object object : list) {
212                            methodInterceptors.add((MethodInterceptor)object);
213                    }
214    
215                    return methodInterceptors;
216            }
217    
218            private void _setMethodInterceptors(
219                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
220    
221                    MethodInterceptorsBag methodInterceptorsBag =
222                            _serviceBeanAopCacheManager.getMethodInterceptorsBag(
223                                    serviceBeanMethodInvocation);
224    
225                    if (methodInterceptorsBag == null) {
226                            List<MethodInterceptor> methodInterceptors = _getMethodInterceptors(
227                                    serviceBeanMethodInvocation);
228    
229                            methodInterceptorsBag = new MethodInterceptorsBag(
230                                    _classLevelMethodInterceptors, methodInterceptors);
231    
232                            _serviceBeanAopCacheManager.putMethodInterceptorsBag(
233                                    serviceBeanMethodInvocation.toCacheKeyModel(),
234                                    methodInterceptorsBag);
235                    }
236    
237                    serviceBeanMethodInvocation.setMethodInterceptors(
238                            methodInterceptorsBag.getMergedMethodInterceptors());
239            }
240    
241            private static Log _log = LogFactoryUtil.getLog(ServiceBeanAopProxy.class);
242    
243            private static PACL _pacl = new NoPACL();
244    
245            private AdvisedSupport _advisedSupport;
246            private AdvisorChainFactory _advisorChainFactory;
247            private final List<MethodInterceptor> _classLevelMethodInterceptors;
248            private final List<MethodInterceptor> _fullMethodInterceptors;
249            private boolean _mergeSpringMethodInterceptors;
250            private ServiceBeanAopCacheManager _serviceBeanAopCacheManager;
251    
252            private static class NoPACL implements PACL {
253    
254                    public InvocationHandler getInvocationHandler(
255                            InvocationHandler invocationHandler,
256                            AdvisedSupport advisedSupport) {
257    
258                            return invocationHandler;
259                    }
260    
261            }
262    
263            public static interface PACL {
264    
265                    public InvocationHandler getInvocationHandler(
266                            InvocationHandler invocationHandler, AdvisedSupport advisedSupport);
267    
268            }
269    
270    }