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.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.Field;
026    import java.lang.reflect.InvocationHandler;
027    import java.lang.reflect.Method;
028    
029    import java.util.ArrayList;
030    import java.util.Iterator;
031    import java.util.List;
032    
033    import org.aopalliance.intercept.MethodInterceptor;
034    
035    import org.springframework.aop.SpringProxy;
036    import org.springframework.aop.TargetSource;
037    import org.springframework.aop.framework.AdvisedSupport;
038    import org.springframework.aop.framework.AdvisorChainFactory;
039    import org.springframework.aop.framework.AopProxy;
040    import org.springframework.aop.framework.AopProxyUtils;
041    import org.springframework.util.ClassUtils;
042    
043    /**
044     * @author Shuyang Zhou
045     */
046    public class ServiceBeanAopProxy implements AopProxy, InvocationHandler {
047    
048            public static AdvisedSupport getAdvisedSupport(Object proxy)
049                    throws Exception {
050    
051                    InvocationHandler invocationHandler = ProxyUtil.getInvocationHandler(
052                            proxy);
053    
054                    Class<?> invocationHandlerClass = invocationHandler.getClass();
055    
056                    Field advisedSupportField = invocationHandlerClass.getDeclaredField(
057                            "_advisedSupport");
058    
059                    advisedSupportField.setAccessible(true);
060    
061                    return (AdvisedSupport)advisedSupportField.get(invocationHandler);
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 Object getProxy() {
137                    return getProxy(ClassUtils.getDefaultClassLoader());
138            }
139    
140            @Override
141            public Object getProxy(ClassLoader classLoader) {
142                    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
143                            _advisedSupport);
144    
145                    InvocationHandler invocationHandler = _pacl.getInvocationHandler(
146                            this, _advisedSupport);
147    
148                    return ProxyUtil.newProxyInstance(
149                            classLoader, proxiedInterfaces, invocationHandler);
150            }
151    
152            @Override
153            public Object invoke(Object proxy, Method method, Object[] arguments)
154                    throws Throwable {
155    
156                    TargetSource targetSource = _advisedSupport.getTargetSource();
157    
158                    Object target = null;
159    
160                    try {
161                            Class<?> targetClass = null;
162    
163                            target = targetSource.getTarget();
164    
165                            if (target != null) {
166                                    targetClass = target.getClass();
167                            }
168    
169                            ServiceBeanMethodInvocation serviceBeanMethodInvocation =
170                                    new ServiceBeanMethodInvocation(
171                                            target, targetClass, method, arguments);
172    
173                            _setMethodInterceptors(serviceBeanMethodInvocation);
174    
175                            return serviceBeanMethodInvocation.proceed();
176                    }
177                    finally {
178                            if ((target != null) && !targetSource.isStatic()) {
179                                    targetSource.releaseTarget(target);
180                            }
181                    }
182            }
183    
184            public static interface PACL {
185    
186                    public InvocationHandler getInvocationHandler(
187                            InvocationHandler invocationHandler, AdvisedSupport advisedSupport);
188    
189            }
190    
191            private List<MethodInterceptor> _getMethodInterceptors(
192                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
193    
194                    List<MethodInterceptor> methodInterceptors =
195                            new ArrayList<MethodInterceptor>(_fullMethodInterceptors);
196    
197                    if (!_mergeSpringMethodInterceptors) {
198                            return methodInterceptors;
199                    }
200    
201                    List<Object> list =
202                            _advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
203                                    _advisedSupport, serviceBeanMethodInvocation.getMethod(),
204                                    serviceBeanMethodInvocation.getTargetClass());
205    
206                    Iterator<Object> itr = list.iterator();
207    
208                    while (itr.hasNext()) {
209                            Object obj = itr.next();
210    
211                            if (obj instanceof MethodInterceptor) {
212                                    continue;
213                            }
214    
215                            if (_log.isWarnEnabled()) {
216                                    _log.warn(
217                                            "Skipping unsupported interceptor type " + obj.getClass());
218                            }
219    
220                            itr.remove();
221                    }
222    
223                    if (list.isEmpty()) {
224                            return methodInterceptors;
225                    }
226    
227                    for (Object object : list) {
228                            methodInterceptors.add((MethodInterceptor)object);
229                    }
230    
231                    return methodInterceptors;
232            }
233    
234            private void _setMethodInterceptors(
235                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
236    
237                    MethodInterceptorsBag methodInterceptorsBag =
238                            _serviceBeanAopCacheManager.getMethodInterceptorsBag(
239                                    serviceBeanMethodInvocation);
240    
241                    if (methodInterceptorsBag == null) {
242                            List<MethodInterceptor> methodInterceptors = _getMethodInterceptors(
243                                    serviceBeanMethodInvocation);
244    
245                            methodInterceptorsBag = new MethodInterceptorsBag(
246                                    _classLevelMethodInterceptors, methodInterceptors);
247    
248                            _serviceBeanAopCacheManager.putMethodInterceptorsBag(
249                                    serviceBeanMethodInvocation.toCacheKeyModel(),
250                                    methodInterceptorsBag);
251                    }
252    
253                    serviceBeanMethodInvocation.setMethodInterceptors(
254                            methodInterceptorsBag.getMergedMethodInterceptors());
255            }
256    
257            private static Log _log = LogFactoryUtil.getLog(ServiceBeanAopProxy.class);
258    
259            private static PACL _pacl = new NoPACL();
260    
261            private AdvisedSupport _advisedSupport;
262            private AdvisorChainFactory _advisorChainFactory;
263            private final List<MethodInterceptor> _classLevelMethodInterceptors;
264            private final List<MethodInterceptor> _fullMethodInterceptors;
265            private boolean _mergeSpringMethodInterceptors;
266            private 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    }