001    /**
002     * Copyright (c) 2000-2012 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                    return ProxyUtil.newProxyInstance(classLoader, proxiedInterfaces, this);
129            }
130    
131            public Object invoke(Object proxy, Method method, Object[] arguments)
132                    throws Throwable {
133    
134                    TargetSource targetSource = _advisedSupport.getTargetSource();
135    
136                    Object target = null;
137    
138                    try {
139                            Class<?> targetClass = null;
140    
141                            target = targetSource.getTarget();
142    
143                            if (target != null) {
144                                    targetClass = target.getClass();
145                            }
146    
147                            ServiceBeanMethodInvocation serviceBeanMethodInvocation =
148                                    new ServiceBeanMethodInvocation(
149                                            target, targetClass, method, arguments);
150    
151                            Skip skip = ServiceBeanAopCacheManager.getAnnotation(
152                                    serviceBeanMethodInvocation, Skip.class, null);
153    
154                            if (skip != null) {
155                                    serviceBeanMethodInvocation.setMethodInterceptors(
156                                            Collections.<MethodInterceptor>emptyList());
157                            }
158                            else {
159                                    _setMethodInterceptors(serviceBeanMethodInvocation);
160                            }
161    
162                            return serviceBeanMethodInvocation.proceed();
163                    }
164                    finally {
165                            if ((target != null) && !targetSource.isStatic()) {
166                                    targetSource.releaseTarget(target);
167                            }
168                    }
169            }
170    
171            private List<MethodInterceptor> _getMethodInterceptors(
172                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
173    
174                    List<MethodInterceptor> methodInterceptors =
175                            new ArrayList<MethodInterceptor>(_fullMethodInterceptors);
176    
177                    if (!_mergeSpringMethodInterceptors) {
178                            return methodInterceptors;
179                    }
180    
181                    List<Object> list =
182                            _advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
183                                    _advisedSupport, serviceBeanMethodInvocation.getMethod(),
184                                    serviceBeanMethodInvocation.getTargetClass());
185    
186                    Iterator<Object> itr = list.iterator();
187    
188                    while (itr.hasNext()) {
189                            Object obj = itr.next();
190    
191                            if (obj instanceof MethodInterceptor) {
192                                    continue;
193                            }
194    
195                            if (_log.isWarnEnabled()) {
196                                    _log.warn(
197                                            "Skipping unsupported interceptor type " + obj.getClass());
198                            }
199    
200                            itr.remove();
201                    }
202    
203                    if (list.isEmpty()) {
204                            return methodInterceptors;
205                    }
206    
207                    for (Object object : list) {
208                            methodInterceptors.add((MethodInterceptor)object);
209                    }
210    
211                    return methodInterceptors;
212            }
213    
214            private void _setMethodInterceptors(
215                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
216    
217                    MethodInterceptorsBag methodInterceptorsBag =
218                            _serviceBeanAopCacheManager.getMethodInterceptorsBag(
219                                    serviceBeanMethodInvocation);
220    
221                    if (methodInterceptorsBag == null) {
222                            List<MethodInterceptor> methodInterceptors = _getMethodInterceptors(
223                                    serviceBeanMethodInvocation);
224    
225                            methodInterceptorsBag = new MethodInterceptorsBag(
226                                    _classLevelMethodInterceptors, methodInterceptors);
227    
228                            _serviceBeanAopCacheManager.putMethodInterceptorsBag(
229                                    serviceBeanMethodInvocation.toCacheKeyModel(),
230                                    methodInterceptorsBag);
231                    }
232    
233                    serviceBeanMethodInvocation.setMethodInterceptors(
234                            methodInterceptorsBag.getMergedMethodInterceptors());
235            }
236    
237            private static Log _log = LogFactoryUtil.getLog(ServiceBeanAopProxy.class);
238    
239            private AdvisedSupport _advisedSupport;
240            private AdvisorChainFactory _advisorChainFactory;
241            private final List<MethodInterceptor> _classLevelMethodInterceptors;
242            private final List<MethodInterceptor> _fullMethodInterceptors;
243            private boolean _mergeSpringMethodInterceptors;
244            private ServiceBeanAopCacheManager _serviceBeanAopCacheManager;
245    
246    }