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