1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.spring.aop;
16  
17  import com.liferay.portal.kernel.util.AutoResetThreadLocal;
18  import com.liferay.portal.kernel.util.MethodTargetClassKey;
19  import com.liferay.portal.servlet.filters.threadlocal.ThreadLocalFilter;
20  
21  import java.lang.annotation.Annotation;
22  import java.lang.reflect.Method;
23  
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.concurrent.ConcurrentHashMap;
27  import java.util.concurrent.ConcurrentMap;
28  
29  import org.aopalliance.intercept.MethodInvocation;
30  
31  import org.springframework.beans.factory.BeanFactory;
32  import org.springframework.beans.factory.BeanFactoryAware;
33  
34  /**
35   * <a href="AnnotationChainableMethodAdvice.java.html"><b><i>View Source</i></b>
36   * </a>
37   *
38   * @author Shuyang Zhou
39   * @author Brian Wing Shun Chan
40   */
41  public abstract class AnnotationChainableMethodAdvice<T extends Annotation>
42      extends ChainableMethodAdvice implements BeanFactoryAware {
43  
44      public AnnotationChainableMethodAdvice() {
45          _nullAnnotation = getNullAnnotation();
46          _annotationType = _nullAnnotation.annotationType();
47      }
48  
49      public abstract T getNullAnnotation();
50  
51      public void setBeanFactory(BeanFactory beanFactory) {
52          if (beanFactory == null) {
53              _beanFactoryAnnotations.remove(_beanFactory);
54          }
55          else {
56              _beanFactory = beanFactory;
57  
58              _beanFactoryAnnotations.putIfAbsent(
59                  _beanFactory,
60                  new ConcurrentHashMap<MethodTargetClassKey, Annotation[]>());
61          }
62      }
63  
64      protected MethodTargetClassKey buildMethodTargetClassKey(
65          MethodInvocation methodInvocation) {
66  
67          Map<MethodInvocation, MethodTargetClassKey> methodTargetClassKeyMap =
68              null;
69  
70          if ((_methodTargetClassKeyThreadLocalCache != null) &&
71              ThreadLocalFilter.isInUse()) {
72  
73              methodTargetClassKeyMap =
74                  _methodTargetClassKeyThreadLocalCache.get();
75          }
76  
77          MethodTargetClassKey methodTargetClassKey = null;
78  
79          if (methodTargetClassKeyMap != null) {
80              methodTargetClassKey = methodTargetClassKeyMap.get(
81                  methodInvocation);
82          }
83  
84          if (methodTargetClassKey != null) {
85              return methodTargetClassKey;
86          }
87  
88          Method method = methodInvocation.getMethod();
89  
90          Class<?> targetClass = null;
91  
92          Object thisObject = methodInvocation.getThis();
93  
94          if (thisObject != null) {
95              targetClass = thisObject.getClass();
96          }
97  
98          methodTargetClassKey = new MethodTargetClassKey(method, targetClass);
99  
100         if (methodTargetClassKeyMap != null) {
101             methodTargetClassKeyMap.put(methodInvocation, methodTargetClassKey);
102         }
103 
104         return methodTargetClassKey;
105     }
106 
107     protected T findAnnotation(MethodTargetClassKey methodTargetClassKey){
108         Map<MethodTargetClassKey, Annotation[]> annotationsMap =
109             _beanFactoryAnnotations.get(_beanFactory);
110 
111         if (annotationsMap == null) {
112             return _nullAnnotation;
113         }
114 
115         Annotation[] annotations = annotationsMap.get(methodTargetClassKey);
116 
117         if (annotations != null) {
118             return getAnnotation(annotations);
119         }
120 
121         Method method = methodTargetClassKey.getMethod();
122 
123         Method targetMethod = methodTargetClassKey.getTargetMethod();
124 
125         if (targetMethod != null) {
126             annotations = targetMethod.getAnnotations();
127         }
128 
129         if ((annotations == null) || (annotations.length == 0)) {
130             annotations = method.getAnnotations();
131         }
132 
133         if ((annotations == null) || (annotations.length == 0)) {
134             annotations = _emptyAnnotations;
135         }
136 
137         annotationsMap.put(methodTargetClassKey, annotations);
138 
139         return getAnnotation(annotations);
140     }
141 
142     protected T getAnnotation(Annotation[] annotations) {
143         for (Annotation annotation : annotations) {
144             if (annotation.annotationType() == _annotationType) {
145                 return (T)annotation;
146             }
147         }
148 
149         return _nullAnnotation;
150     }
151 
152     private static ConcurrentMap
153         <BeanFactory, Map<MethodTargetClassKey, Annotation[]>>
154             _beanFactoryAnnotations =
155                 new ConcurrentHashMap
156                     <BeanFactory, Map<MethodTargetClassKey, Annotation[]>>();
157     private static Annotation[] _emptyAnnotations = new Annotation[0];
158     private static ThreadLocal<Map<MethodInvocation, MethodTargetClassKey>>
159         _methodTargetClassKeyThreadLocalCache;
160 
161     private Class<? extends Annotation> _annotationType;
162     private BeanFactory _beanFactory;
163     private T _nullAnnotation;
164 
165     static {
166         if (ThreadLocalFilter.ENABLED) {
167             _methodTargetClassKeyThreadLocalCache = new AutoResetThreadLocal
168                 <Map<MethodInvocation, MethodTargetClassKey>>(
169                     new HashMap<MethodInvocation, MethodTargetClassKey>());
170         }
171     }
172 
173 }