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