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.annotation.AnnotationLocator;
018    
019    import java.lang.annotation.Annotation;
020    import java.lang.reflect.Method;
021    
022    import java.util.HashMap;
023    import java.util.HashSet;
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Set;
028    
029    import org.aopalliance.intercept.MethodInvocation;
030    
031    /**
032     * @author Shuyang Zhou
033     * @author Brian Wing Shun Chan
034     */
035    public abstract class AnnotationChainableMethodAdvice<T extends Annotation>
036            extends ChainableMethodAdvice {
037    
038            public static void registerAnnotationClass(
039                    Class<? extends Annotation> annotationClass) {
040    
041                    _annotationChainableMethodAdvices.put(annotationClass, null);
042            }
043    
044            public AnnotationChainableMethodAdvice() {
045                    _nullAnnotation = getNullAnnotation();
046    
047                    _annotationClass = _nullAnnotation.annotationType();
048            }
049    
050            public void afterPropertiesSet() {
051                    _annotationChainableMethodAdvices.put(_annotationClass, this);
052            }
053    
054            public Class<? extends Annotation> getAnnotationClass() {
055                    return _annotationClass;
056            }
057    
058            public abstract T getNullAnnotation();
059    
060            protected T findAnnotation(MethodInvocation methodInvocation) {
061                    Annotation annotation = ServiceMethodAnnotationCache.get(
062                            methodInvocation, _annotationClass, _nullAnnotation);
063    
064                    if (annotation != null) {
065                            return (T)annotation;
066                    }
067    
068                    Object thisObject = methodInvocation.getThis();
069    
070                    Class<?> targetClass = thisObject.getClass();
071    
072                    Method method = methodInvocation.getMethod();
073    
074                    List<Annotation> annotations = AnnotationLocator.locate(
075                            method, targetClass);
076    
077                    Iterator<Annotation> iterator = annotations.iterator();
078    
079                    while (iterator.hasNext()) {
080                            Annotation curAnnotation = iterator.next();
081    
082                            if (!_annotationChainableMethodAdvices.containsKey(
083                                            curAnnotation.annotationType())) {
084    
085                                    iterator.remove();
086                            }
087                    }
088    
089                    ServiceMethodAnnotationCache.put(
090                            methodInvocation,
091                            annotations.toArray(new Annotation[annotations.size()]));
092    
093                    Set<Class<? extends Annotation>> annotationClasses =
094                            new HashSet<Class<? extends Annotation>>();
095    
096                    annotation = _nullAnnotation;
097    
098                    for (Annotation curAnnotation : annotations) {
099                            Class<? extends Annotation> annotationClass =
100                                    curAnnotation.annotationType();
101    
102                            if (annotationClass == _annotationClass) {
103                                    annotation = curAnnotation;
104                            }
105    
106                            annotationClasses.add(annotationClass);
107                    }
108    
109                    for (Map.Entry<Class<? extends Annotation>,
110                                    AnnotationChainableMethodAdvice<?>> entry :
111                                            _annotationChainableMethodAdvices.entrySet()) {
112    
113                            Class<? extends Annotation> annotationClass = entry.getKey();
114                            AnnotationChainableMethodAdvice<?> annotationChainableMethodAdvice =
115                                    entry.getValue();
116    
117                            if (!annotationClasses.contains(annotationClass) &&
118                                    (annotationChainableMethodAdvice != null)) {
119    
120                                    ServiceBeanAopProxy.removeMethodInterceptor(
121                                            methodInvocation, annotationChainableMethodAdvice);
122                            }
123                    }
124    
125                    return (T)annotation;
126            }
127    
128            private static Map<Class<? extends Annotation>,
129                    AnnotationChainableMethodAdvice<?>> _annotationChainableMethodAdvices =
130                            new HashMap<Class<? extends Annotation>,
131                                    AnnotationChainableMethodAdvice<?>>();
132    
133            private Class<? extends Annotation> _annotationClass;
134            private T _nullAnnotation;
135    
136    }