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<MethodInterceptor>();
078                    ArrayList<MethodInterceptor> fullMethodInterceptors =
079                            new ArrayList<MethodInterceptor>();
080    
081                    while (true) {
082                            if (!(methodInterceptor instanceof ChainableMethodAdvice)) {
083                                    classLevelMethodInterceptors.add(methodInterceptor);
084                                    fullMethodInterceptors.add(methodInterceptor);
085    
086                                    break;
087                            }
088    
089                            ChainableMethodAdvice chainableMethodAdvice =
090                                    (ChainableMethodAdvice)methodInterceptor;
091    
092                            chainableMethodAdvice.setServiceBeanAopCacheManager(
093                                    serviceBeanAopCacheManager);
094    
095                            if (methodInterceptor instanceof AnnotationChainableMethodAdvice) {
096                                    AnnotationChainableMethodAdvice<?>
097                                            annotationChainableMethodAdvice =
098                                                    (AnnotationChainableMethodAdvice<?>)methodInterceptor;
099    
100                                    Class<? extends Annotation> annotationClass =
101                                            annotationChainableMethodAdvice.getAnnotationClass();
102    
103                                    Target target = annotationClass.getAnnotation(Target.class);
104    
105                                    if (target == null) {
106                                            classLevelMethodInterceptors.add(methodInterceptor);
107                                    }
108                                    else {
109                                            for (ElementType elementType : target.value()) {
110                                                    if (elementType == ElementType.TYPE) {
111                                                            classLevelMethodInterceptors.add(methodInterceptor);
112    
113                                                            break;
114                                                    }
115                                            }
116                                    }
117                            }
118                            else {
119                                    classLevelMethodInterceptors.add(methodInterceptor);
120                            }
121    
122                            fullMethodInterceptors.add(methodInterceptor);
123    
124                            methodInterceptor = chainableMethodAdvice.nextMethodInterceptor;
125                    }
126    
127                    classLevelMethodInterceptors.trimToSize();
128    
129                    _classLevelMethodInterceptors = classLevelMethodInterceptors;
130                    _fullMethodInterceptors = fullMethodInterceptors;
131    
132                    _serviceBeanAopCacheManager = serviceBeanAopCacheManager;
133            }
134    
135            @Override
136            public AdvisedSupport getAdvisedSupport() {
137                    return _advisedSupport;
138            }
139    
140            @Override
141            public Object getProxy() {
142                    return getProxy(ClassUtils.getDefaultClassLoader());
143            }
144    
145            @Override
146            public Object getProxy(ClassLoader classLoader) {
147                    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
148                            _advisedSupport);
149    
150                    InvocationHandler invocationHandler = _pacl.getInvocationHandler(
151                            this, _advisedSupport);
152    
153                    return ProxyUtil.newProxyInstance(
154                            classLoader, proxiedInterfaces, invocationHandler);
155            }
156    
157            @Override
158            public Object invoke(Object proxy, Method method, Object[] arguments)
159                    throws Throwable {
160    
161                    TargetSource targetSource = _advisedSupport.getTargetSource();
162    
163                    Object target = null;
164    
165                    try {
166                            target = targetSource.getTarget();
167    
168                            ServiceBeanMethodInvocation serviceBeanMethodInvocation =
169                                    new ServiceBeanMethodInvocation(
170                                            target, targetSource.getTargetClass(), method, arguments);
171    
172                            _setMethodInterceptors(serviceBeanMethodInvocation);
173    
174                            return serviceBeanMethodInvocation.proceed();
175                    }
176                    finally {
177                            if ((target != null) && !targetSource.isStatic()) {
178                                    targetSource.releaseTarget(target);
179                            }
180                    }
181            }
182    
183            public interface PACL {
184    
185                    public InvocationHandler getInvocationHandler(
186                            InvocationHandler invocationHandler, AdvisedSupport advisedSupport);
187    
188            }
189    
190            private List<MethodInterceptor> _getMethodInterceptors(
191                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
192    
193                    List<MethodInterceptor> methodInterceptors =
194                            new ArrayList<MethodInterceptor>(_fullMethodInterceptors);
195    
196                    if (!_mergeSpringMethodInterceptors) {
197                            return methodInterceptors;
198                    }
199    
200                    List<Object> list =
201                            _advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
202                                    _advisedSupport, serviceBeanMethodInvocation.getMethod(),
203                                    serviceBeanMethodInvocation.getTargetClass());
204    
205                    Iterator<Object> itr = list.iterator();
206    
207                    while (itr.hasNext()) {
208                            Object obj = itr.next();
209    
210                            if (obj instanceof MethodInterceptor) {
211                                    continue;
212                            }
213    
214                            if (_log.isWarnEnabled()) {
215                                    _log.warn(
216                                            "Skipping unsupported interceptor type " + obj.getClass());
217                            }
218    
219                            itr.remove();
220                    }
221    
222                    if (list.isEmpty()) {
223                            return methodInterceptors;
224                    }
225    
226                    for (Object object : list) {
227                            methodInterceptors.add((MethodInterceptor)object);
228                    }
229    
230                    return methodInterceptors;
231            }
232    
233            private void _setMethodInterceptors(
234                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
235    
236                    MethodInterceptorsBag methodInterceptorsBag =
237                            _serviceBeanAopCacheManager.getMethodInterceptorsBag(
238                                    serviceBeanMethodInvocation);
239    
240                    if (methodInterceptorsBag == null) {
241                            List<MethodInterceptor> methodInterceptors = _getMethodInterceptors(
242                                    serviceBeanMethodInvocation);
243    
244                            methodInterceptorsBag = new MethodInterceptorsBag(
245                                    _classLevelMethodInterceptors, methodInterceptors);
246    
247                            _serviceBeanAopCacheManager.putMethodInterceptorsBag(
248                                    serviceBeanMethodInvocation.toCacheKeyModel(),
249                                    methodInterceptorsBag);
250                    }
251    
252                    serviceBeanMethodInvocation.setMethodInterceptors(
253                            methodInterceptorsBag.getMergedMethodInterceptors());
254            }
255    
256            private static final Log _log = LogFactoryUtil.getLog(
257                    ServiceBeanAopProxy.class);
258    
259            private static final PACL _pacl = new NoPACL();
260    
261            private final AdvisedSupport _advisedSupport;
262            private final AdvisorChainFactory _advisorChainFactory;
263            private final List<MethodInterceptor> _classLevelMethodInterceptors;
264            private final List<MethodInterceptor> _fullMethodInterceptors;
265            private final boolean _mergeSpringMethodInterceptors;
266            private final ServiceBeanAopCacheManager _serviceBeanAopCacheManager;
267    
268            private static class NoPACL implements PACL {
269    
270                    @Override
271                    public InvocationHandler getInvocationHandler(
272                            InvocationHandler invocationHandler,
273                            AdvisedSupport advisedSupport) {
274    
275                            return invocationHandler;
276                    }
277    
278            }
279    
280    }