1 package org.apache.onami.autobind.aop.feature;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import java.lang.annotation.Annotation;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Type;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27
28 import javax.inject.Singleton;
29 import javax.interceptor.Interceptor;
30
31 import org.aopalliance.intercept.MethodInterceptor;
32 import org.aopalliance.intercept.MethodInvocation;
33 import org.apache.onami.autobind.aop.ClassMatcher;
34 import org.apache.onami.autobind.aop.GuiceMethodInterceptor;
35 import org.apache.onami.autobind.aop.Invoke;
36 import org.apache.onami.autobind.aop.MethodMatcher;
37 import org.apache.onami.autobind.install.BindingStage;
38 import org.apache.onami.autobind.scanner.features.BindingScannerFeature;
39
40 import com.google.inject.matcher.Matcher;
41 import com.google.inject.matcher.Matchers;
42
43
44 @Singleton
45 public class InterceptorFeature extends BindingScannerFeature {
46 private Logger _logger = Logger.getLogger(InterceptorFeature.class.getName());
47
48 @Override
49 public BindingStage accept(Class<Object> annotatedClass, Map<String, Annotation> annotations) {
50 if (annotations.containsKey(Interceptor.class.getName())) {
51 return BindingStage.BOOT;
52 }
53 return BindingStage.IGNORE;
54 }
55
56 @SuppressWarnings("unchecked")
57 @Override
58 public void process(Class<Object> annotatedClass, Map<String, Annotation> annotations) {
59 MethodInterceptor interceptor;
60 final Object possibleInterceptor = injector.getInstance(annotatedClass);
61
62 Matcher<? super Class<?>> classMatcher = null;
63 Matcher<? super Method> methodMatcher = null;
64 if (possibleInterceptor instanceof GuiceMethodInterceptor) {
65 interceptor = (MethodInterceptor) possibleInterceptor;
66 GuiceMethodInterceptor guiceInterceptor = (GuiceMethodInterceptor) interceptor;
67 classMatcher = guiceInterceptor.getClassMatcher();
68 methodMatcher = guiceInterceptor.getMethodMatcher();
69 } else {
70 Method[] declaredMethods = annotatedClass.getDeclaredMethods();
71 Map<Class<? extends Annotation>, Method> methods = new HashMap<Class<? extends Annotation>, Method>();
72
73 for (Method method : declaredMethods) {
74 Annotation[] methodAnnotations = method.getAnnotations();
75 for (Annotation methodAnnotation : methodAnnotations) {
76 methods.put(methodAnnotation.annotationType(), method);
77 }
78 }
79 try {
80 if (methods.containsKey(ClassMatcher.class)) {
81 Method method = methods.get(ClassMatcher.class);
82 Type genericReturnType = method.getGenericReturnType();
83 if (GuiceMethodInterceptor.CLASS_MATCHER_TYPE.equals(genericReturnType)) {
84 classMatcher = (Matcher<? super Class<?>>) method.invoke(
85 possibleInterceptor, new Object[0]);
86 } else {
87 _logger.log(Level.WARNING,
88 "Return Type of the annotated @ClassMatcher-Method, does not return: "
89 + GuiceMethodInterceptor.CLASS_MATCHER_TYPE
90 + " instead it returns " + genericReturnType);
91 }
92 }
93
94 if (methods.containsKey(MethodMatcher.class)) {
95 Method method = methods.get(MethodMatcher.class);
96 Type genericReturnType = method.getGenericReturnType();
97 if (GuiceMethodInterceptor.METHOD_MATCHER_TYPE.equals(genericReturnType)) {
98 methodMatcher = (Matcher<? super Method>) method.invoke(
99 possibleInterceptor, new Object[0]);
100 } else {
101 _logger.log(Level.WARNING,
102 "Return Type of the annotated @MethodMatcher-Method, does not return: "
103 + GuiceMethodInterceptor.METHOD_MATCHER_TYPE
104 + " instead it returns " + genericReturnType);
105 }
106 }
107 } catch (Exception e) {
108 _logger
109 .log(
110 Level.WARNING,
111 "Skipping process(..) of \""
112 + annotatedClass
113 + "\", because an Exception occured while trying to invoke a Method of the found Intercepter.",
114 e);
115 return;
116 }
117
118 if (possibleInterceptor instanceof MethodInterceptor) {
119 interceptor = (MethodInterceptor) possibleInterceptor;
120 } else {
121 if (methods.containsKey(Invoke.class)) {
122 final Method method = methods.get(Invoke.class);
123 Class<?>[] parameterTypes = method.getParameterTypes();
124 if (parameterTypes != null && parameterTypes.length == 1
125 && parameterTypes[0] == MethodInvocation.class) {
126 interceptor = new MethodInterceptor() {
127 @Override
128 public Object invoke(MethodInvocation invocation) throws Throwable {
129 return method.invoke(possibleInterceptor, invocation);
130 }
131 };
132 } else {
133 _logger
134 .log(
135 Level.WARNING,
136 "Skipping \""
137 + annotatedClass
138 + "\", because the Parameter of the with @Invoke annotated Method \""
139 + method.getName()
140 + "\" doesn't match the expected one. "
141 + method.getName() + "(MethodInvocation invocation)");
142 return;
143 }
144 } else {
145 _logger.log(Level.WARNING, "Skipping \"" + annotatedClass
146 + "\" is either Child of \""
147 + GuiceMethodInterceptor.class.getName() + "\" / \""
148 + MethodInterceptor.class.getName()
149 + "\" nor has a Method annotated with \"" + Invoke.class.getName()
150 + "\"");
151 return;
152 }
153 }
154 }
155
156 if (classMatcher == null) {
157 classMatcher = Matchers.any();
158 }
159
160 if (methodMatcher == null) {
161 methodMatcher = Matchers.any();
162 }
163
164 _binder.bindInterceptor(classMatcher, methodMatcher, interceptor);
165 }
166 }