001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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    import java.util.Map;
034    import java.util.concurrent.ConcurrentHashMap;
035    
036    import org.aopalliance.intercept.MethodInterceptor;
037    import org.aopalliance.intercept.MethodInvocation;
038    
039    import org.springframework.aop.SpringProxy;
040    import org.springframework.aop.TargetSource;
041    import org.springframework.aop.framework.AdvisedSupport;
042    import org.springframework.aop.framework.AdvisorChainFactory;
043    import org.springframework.aop.framework.AopProxy;
044    import org.springframework.aop.framework.AopProxyUtils;
045    import org.springframework.util.ClassUtils;
046    
047    /**
048     * @author Shuyang Zhou
049     */
050    public class ServiceBeanAopProxy implements AopProxy, InvocationHandler {
051    
052            public static void clearMethodInterceptorCache() {
053                    _methodInterceptorBags.clear();
054            }
055    
056            public static void removeMethodInterceptor(
057                    MethodInvocation methodInvocation,
058                    MethodInterceptor methodInterceptor) {
059    
060                    if (!(methodInvocation instanceof ServiceBeanMethodInvocation)) {
061                            return;
062                    }
063    
064                    ServiceBeanMethodInvocation serviceBeanMethodInvocation =
065                            (ServiceBeanMethodInvocation)methodInvocation;
066    
067                    MethodInterceptorsBag methodInterceptorsBag =
068                            _methodInterceptorBags.get(serviceBeanMethodInvocation);
069    
070                    if (methodInterceptorsBag == null) {
071                            return;
072                    }
073    
074                    ArrayList<MethodInterceptor> methodInterceptors =
075                            new ArrayList<MethodInterceptor>(
076                                    methodInterceptorsBag._mergedMethodInterceptors);
077    
078                    methodInterceptors.remove(methodInterceptor);
079    
080                    MethodInterceptorsBag newMethodInterceptorsBag = null;
081    
082                    if (methodInterceptors.equals(
083                                    methodInterceptorsBag._classLevelMethodInterceptors)) {
084    
085                            newMethodInterceptorsBag = new MethodInterceptorsBag(
086                                    methodInterceptorsBag._classLevelMethodInterceptors,
087                                    methodInterceptorsBag._classLevelMethodInterceptors);
088                    }
089                    else {
090                            methodInterceptors.trimToSize();
091    
092                            newMethodInterceptorsBag = new MethodInterceptorsBag(
093                                    methodInterceptorsBag._classLevelMethodInterceptors,
094                                    methodInterceptors);
095                    }
096    
097                    _methodInterceptorBags.put(
098                            serviceBeanMethodInvocation.toCacheKeyModel(),
099                            newMethodInterceptorsBag);
100            }
101    
102            public ServiceBeanAopProxy(
103                    AdvisedSupport advisedSupport, MethodInterceptor methodInterceptor) {
104    
105                    _advisedSupport = advisedSupport;
106                    _advisorChainFactory = _advisedSupport.getAdvisorChainFactory();
107    
108                    Class<?>[] proxyInterfaces = _advisedSupport.getProxiedInterfaces();
109    
110                    _mergeSpringMethodInterceptors = !ArrayUtil.contains(
111                            proxyInterfaces, SpringProxy.class);
112    
113                    ArrayList<MethodInterceptor> classLevelMethodInterceptors =
114                            new ArrayList<MethodInterceptor>();
115                    ArrayList<MethodInterceptor> fullMethodInterceptors =
116                            new ArrayList<MethodInterceptor>();
117    
118                    while (true) {
119                            if (!(methodInterceptor instanceof ChainableMethodAdvice)) {
120                                    classLevelMethodInterceptors.add(methodInterceptor);
121                                    fullMethodInterceptors.add(methodInterceptor);
122    
123                                    break;
124                            }
125    
126                            ChainableMethodAdvice chainableMethodAdvice =
127                                    (ChainableMethodAdvice)methodInterceptor;
128    
129                            if (methodInterceptor instanceof AnnotationChainableMethodAdvice) {
130                                    AnnotationChainableMethodAdvice<?>
131                                            annotationChainableMethodAdvice =
132                                                    (AnnotationChainableMethodAdvice<?>)methodInterceptor;
133    
134                                    Class<? extends Annotation> annotationClass =
135                                            annotationChainableMethodAdvice.getAnnotationClass();
136    
137                                    Target target = annotationClass.getAnnotation(Target.class);
138    
139                                    if (target == null) {
140                                            classLevelMethodInterceptors.add(methodInterceptor);
141                                    }
142                                    else {
143                                            for (ElementType elementType : target.value()) {
144                                                    if (elementType == ElementType.TYPE) {
145                                                            classLevelMethodInterceptors.add(methodInterceptor);
146    
147                                                            break;
148                                                    }
149                                            }
150                                    }
151                            }
152                            else {
153                                    classLevelMethodInterceptors.add(methodInterceptor);
154                            }
155    
156                            fullMethodInterceptors.add(methodInterceptor);
157    
158                            methodInterceptor = chainableMethodAdvice.nextMethodInterceptor;
159                    }
160    
161                    classLevelMethodInterceptors.trimToSize();
162    
163                    _classLevelMethodInterceptors = classLevelMethodInterceptors;
164                    _fullMethodInterceptors = fullMethodInterceptors;
165    
166                    AnnotationChainableMethodAdvice.registerAnnotationClass(Skip.class);
167            }
168    
169            public Object getProxy() {
170                    return getProxy(ClassUtils.getDefaultClassLoader());
171            }
172    
173            public Object getProxy(ClassLoader classLoader) {
174                    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
175                            _advisedSupport);
176    
177                    return ProxyUtil.newProxyInstance(classLoader, proxiedInterfaces, this);
178            }
179    
180            public Object invoke(Object proxy, Method method, Object[] arguments)
181                    throws Throwable {
182    
183                    TargetSource targetSource = _advisedSupport.getTargetSource();
184    
185                    Object target = null;
186    
187                    try {
188                            Class<?> targetClass = null;
189    
190                            target = targetSource.getTarget();
191    
192                            if (target != null) {
193                                    targetClass = target.getClass();
194                            }
195    
196                            ServiceBeanMethodInvocation serviceBeanMethodInvocation =
197                                    new ServiceBeanMethodInvocation(
198                                            target, targetClass, method, arguments);
199    
200                            Skip skip = ServiceMethodAnnotationCache.get(
201                                    serviceBeanMethodInvocation, Skip.class, null);
202    
203                            if (skip != null) {
204                                    serviceBeanMethodInvocation.setMethodInterceptors(
205                                            Collections.<MethodInterceptor>emptyList());
206                            }
207                            else {
208                                    _setMethodInterceptors(serviceBeanMethodInvocation);
209                            }
210    
211                            return serviceBeanMethodInvocation.proceed();
212                    }
213                    finally {
214                            if ((target != null) && !targetSource.isStatic()) {
215                                    targetSource.releaseTarget(target);
216                            }
217                    }
218            }
219    
220            private List<MethodInterceptor> _getMethodInterceptors(
221                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
222    
223                    List<MethodInterceptor> methodInterceptors =
224                            new ArrayList<MethodInterceptor>(_fullMethodInterceptors);
225    
226                    if (!_mergeSpringMethodInterceptors) {
227                            return methodInterceptors;
228                    }
229    
230                    List<Object> list =
231                            _advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
232                                    _advisedSupport, serviceBeanMethodInvocation.getMethod(),
233                                    serviceBeanMethodInvocation.getTargetClass());
234    
235                    Iterator<Object> itr = list.iterator();
236    
237                    while (itr.hasNext()) {
238                            Object obj = itr.next();
239    
240                            if (obj instanceof MethodInterceptor) {
241                                    continue;
242                            }
243    
244                            if (_log.isWarnEnabled()) {
245                                    _log.warn(
246                                            "Skipping unsupported interceptor type " + obj.getClass());
247                            }
248    
249                            itr.remove();
250                    }
251    
252                    if (list.isEmpty()) {
253                            return methodInterceptors;
254                    }
255    
256                    for (Object object : list) {
257                            methodInterceptors.add((MethodInterceptor)object);
258                    }
259    
260                    return methodInterceptors;
261            }
262    
263            private void _setMethodInterceptors(
264                    ServiceBeanMethodInvocation serviceBeanMethodInvocation) {
265    
266                    MethodInterceptorsBag methodInterceptorsBag =
267                            _methodInterceptorBags.get(serviceBeanMethodInvocation);
268    
269                    if (methodInterceptorsBag == null) {
270                            List<MethodInterceptor> methodInterceptors = _getMethodInterceptors(
271                                    serviceBeanMethodInvocation);
272    
273                            methodInterceptorsBag = new MethodInterceptorsBag(
274                                    _classLevelMethodInterceptors, methodInterceptors);
275    
276                            _methodInterceptorBags.put(
277                                    serviceBeanMethodInvocation.toCacheKeyModel(),
278                                    methodInterceptorsBag);
279                    }
280    
281                    serviceBeanMethodInvocation.setMethodInterceptors(
282                            methodInterceptorsBag._mergedMethodInterceptors);
283            }
284    
285            private static Log _log = LogFactoryUtil.getLog(
286                    ServiceBeanAopProxy.class);
287    
288            private static Map <ServiceBeanMethodInvocation, MethodInterceptorsBag>
289                    _methodInterceptorBags = new ConcurrentHashMap
290                            <ServiceBeanMethodInvocation, MethodInterceptorsBag>();
291    
292            private AdvisedSupport _advisedSupport;
293            private AdvisorChainFactory _advisorChainFactory;
294            private final List<MethodInterceptor> _classLevelMethodInterceptors;
295            private final List<MethodInterceptor> _fullMethodInterceptors;
296            private boolean _mergeSpringMethodInterceptors;
297    
298            private static class MethodInterceptorsBag {
299    
300                    public MethodInterceptorsBag(
301                            List<MethodInterceptor> classLevelMethodInterceptors,
302                            List<MethodInterceptor> mergedMethodInterceptors) {
303    
304                            _classLevelMethodInterceptors = classLevelMethodInterceptors;
305                            _mergedMethodInterceptors = mergedMethodInterceptors;
306                    }
307    
308                    private List<MethodInterceptor> _classLevelMethodInterceptors;
309                    private List<MethodInterceptor> _mergedMethodInterceptors;
310    
311            }
312    
313    }