• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject.internal;
18 
19 import com.google.common.collect.Lists;
20 import java.lang.reflect.AccessibleObject;
21 import java.lang.reflect.Method;
22 import java.util.Arrays;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import net.sf.cglib.proxy.MethodProxy;
27 import org.aopalliance.intercept.MethodInterceptor;
28 import org.aopalliance.intercept.MethodInvocation;
29 
30 /**
31  * Intercepts a method with a stack of interceptors.
32  *
33  * @author crazybob@google.com (Bob Lee)
34  */
35 final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterceptor {
36   private static final Set<String> AOP_INTERNAL_CLASSES =
37       new HashSet<String>(
38           Arrays.asList(
39               InterceptorStackCallback.class.getName(),
40               InterceptedMethodInvocation.class.getName(),
41               MethodProxy.class.getName()));
42 
43   final MethodInterceptor[] interceptors;
44   final Method method;
45 
InterceptorStackCallback(Method method, List<MethodInterceptor> interceptors)46   public InterceptorStackCallback(Method method, List<MethodInterceptor> interceptors) {
47     this.method = method;
48     this.interceptors = interceptors.toArray(new MethodInterceptor[interceptors.size()]);
49   }
50 
51   @Override
intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)52   public Object intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)
53       throws Throwable {
54     return new InterceptedMethodInvocation(proxy, methodProxy, arguments, 0).proceed();
55   }
56 
57   private class InterceptedMethodInvocation implements MethodInvocation {
58 
59     final Object proxy;
60     final Object[] arguments;
61     final MethodProxy methodProxy;
62     final int index;
63 
InterceptedMethodInvocation( Object proxy, MethodProxy methodProxy, Object[] arguments, int index)64     public InterceptedMethodInvocation(
65         Object proxy, MethodProxy methodProxy, Object[] arguments, int index) {
66       this.proxy = proxy;
67       this.methodProxy = methodProxy;
68       this.arguments = arguments;
69       this.index = index;
70     }
71 
72     @Override
proceed()73     public Object proceed() throws Throwable {
74       try {
75         return index == interceptors.length
76             ? methodProxy.invokeSuper(proxy, arguments)
77             : interceptors[index]
78                 .invoke(new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1));
79       } catch (Throwable t) {
80         pruneStacktrace(t);
81         throw t;
82       }
83     }
84 
85     @Override
getMethod()86     public Method getMethod() {
87       return method;
88     }
89 
90     @Override
getArguments()91     public Object[] getArguments() {
92       return arguments;
93     }
94 
95     @Override
getThis()96     public Object getThis() {
97       return proxy;
98     }
99 
100     @Override
getStaticPart()101     public AccessibleObject getStaticPart() {
102       return getMethod();
103     }
104   }
105 
106   /**
107    * Removes stacktrace elements related to AOP internal mechanics from the throwable's stack trace
108    * and any causes it may have.
109    */
pruneStacktrace(Throwable throwable)110   private void pruneStacktrace(Throwable throwable) {
111     for (Throwable t = throwable; t != null; t = t.getCause()) {
112       StackTraceElement[] stackTrace = t.getStackTrace();
113       List<StackTraceElement> pruned = Lists.newArrayList();
114       for (StackTraceElement element : stackTrace) {
115         String className = element.getClassName();
116         if (!AOP_INTERNAL_CLASSES.contains(className) && !className.contains("$EnhancerByGuice$")) {
117           pruned.add(element);
118         }
119       }
120       t.setStackTrace(pruned.toArray(new StackTraceElement[pruned.size()]));
121     }
122   }
123 }
124