1
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
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 }