001
014
015 package com.liferay.portal.spring.aop;
016
017 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
018 import com.liferay.portal.kernel.util.MethodTargetClassKey;
019 import com.liferay.portal.servlet.filters.threadlocal.ThreadLocalFilter;
020
021 import java.lang.annotation.Annotation;
022 import java.lang.reflect.Method;
023
024 import java.util.HashMap;
025 import java.util.Map;
026 import java.util.concurrent.ConcurrentHashMap;
027 import java.util.concurrent.ConcurrentMap;
028
029 import org.aopalliance.intercept.MethodInvocation;
030
031 import org.springframework.beans.factory.BeanFactory;
032 import org.springframework.beans.factory.BeanFactoryAware;
033
034
038 public abstract class AnnotationChainableMethodAdvice<T extends Annotation>
039 extends ChainableMethodAdvice implements BeanFactoryAware {
040
041 public AnnotationChainableMethodAdvice() {
042 _nullAnnotation = getNullAnnotation();
043 _annotationType = _nullAnnotation.annotationType();
044 }
045
046 public abstract T getNullAnnotation();
047
048 public void setBeanFactory(BeanFactory beanFactory) {
049 if (beanFactory == null) {
050 _beanFactoryAnnotations.remove(_beanFactory);
051 }
052 else {
053 _beanFactory = beanFactory;
054
055 _beanFactoryAnnotations.putIfAbsent(
056 _beanFactory,
057 new ConcurrentHashMap<MethodTargetClassKey, Annotation[]>());
058 }
059 }
060
061 protected MethodTargetClassKey buildMethodTargetClassKey(
062 MethodInvocation methodInvocation) {
063
064 Map<MethodInvocation, MethodTargetClassKey> methodTargetClassKeyMap =
065 null;
066
067 if (_methodTargetClassKeyThreadLocalCache != null) {
068 methodTargetClassKeyMap =
069 _methodTargetClassKeyThreadLocalCache.get();
070 }
071
072 MethodTargetClassKey methodTargetClassKey = null;
073
074 if (methodTargetClassKeyMap != null) {
075 methodTargetClassKey = methodTargetClassKeyMap.get(
076 methodInvocation);
077 }
078
079 if (methodTargetClassKey != null) {
080 return methodTargetClassKey;
081 }
082
083 Method method = methodInvocation.getMethod();
084
085 Class<?> targetClass = null;
086
087 Object thisObject = methodInvocation.getThis();
088
089 if (thisObject != null) {
090 targetClass = thisObject.getClass();
091 }
092
093 methodTargetClassKey = new MethodTargetClassKey(method, targetClass);
094
095 if (methodTargetClassKeyMap != null) {
096 methodTargetClassKeyMap.put(methodInvocation, methodTargetClassKey);
097 }
098
099 return methodTargetClassKey;
100 }
101
102 protected T findAnnotation(MethodTargetClassKey methodTargetClassKey){
103 Map<MethodTargetClassKey, Annotation[]> annotationsMap =
104 _beanFactoryAnnotations.get(_beanFactory);
105
106 Annotation[] annotations = annotationsMap.get(methodTargetClassKey);
107
108 if (annotations != null) {
109 return getAnnotation(annotations);
110 }
111
112 Method method = methodTargetClassKey.getMethod();
113
114 Method targetMethod = methodTargetClassKey.getTargetMethod();
115
116 if (targetMethod != null) {
117 annotations = targetMethod.getAnnotations();
118 }
119
120 if ((annotations == null) || (annotations.length == 0)) {
121 annotations = method.getAnnotations();
122 }
123
124 if ((annotations == null) || (annotations.length == 0)) {
125 annotations = _emptyAnnotations;
126 }
127
128 annotationsMap.put(methodTargetClassKey, annotations);
129
130 return getAnnotation(annotations);
131 }
132
133 protected T getAnnotation(Annotation[] annotations) {
134 for(Annotation annotation : annotations) {
135 if (annotation.annotationType() == _annotationType) {
136 return (T)annotation;
137 }
138 }
139
140 return _nullAnnotation;
141 }
142
143 private static ConcurrentMap
144 <BeanFactory, Map<MethodTargetClassKey, Annotation[]>>
145 _beanFactoryAnnotations =
146 new ConcurrentHashMap
147 <BeanFactory, Map<MethodTargetClassKey, Annotation[]>>();
148 private static Annotation[] _emptyAnnotations = new Annotation[0];
149 private static ThreadLocal<Map<MethodInvocation, MethodTargetClassKey>>
150 _methodTargetClassKeyThreadLocalCache;
151
152 private Class<? extends Annotation> _annotationType;
153 private BeanFactory _beanFactory;
154 private T _nullAnnotation;
155
156 static {
157 if (ThreadLocalFilter.ENABLED) {
158 _methodTargetClassKeyThreadLocalCache = new AutoResetThreadLocal
159 <Map<MethodInvocation, MethodTargetClassKey>>(
160 AnnotationChainableMethodAdvice.class +
161 "._methodTargetClassKeyThreadLocalCache",
162 new HashMap<MethodInvocation, MethodTargetClassKey>());
163 }
164 }
165
166 }