• 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 
21 import net.sf.cglib.proxy.MethodProxy;
22 
23 import org.aopalliance.intercept.MethodInterceptor;
24 import org.aopalliance.intercept.MethodInvocation;
25 
26 import java.lang.reflect.AccessibleObject;
27 import java.lang.reflect.Method;
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Set;
32 
33 /**
34  * Intercepts a method with a stack of interceptors.
35  *
36  * @author crazybob@google.com (Bob Lee)
37  */
38 final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterceptor {
39   private static final Set<String> AOP_INTERNAL_CLASSES = new HashSet<String>(Arrays.asList(
40       InterceptorStackCallback.class.getName(),
41       InterceptedMethodInvocation.class.getName(),
42       MethodProxy.class.getName()));
43 
44   final MethodInterceptor[] interceptors;
45   final Method method;
46 
InterceptorStackCallback(Method method, List<MethodInterceptor> interceptors)47   public InterceptorStackCallback(Method method,
48       List<MethodInterceptor> interceptors) {
49     this.method = method;
50     this.interceptors = interceptors.toArray(new MethodInterceptor[interceptors.size()]);
51   }
52 
intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)53   public Object intercept(Object proxy, Method method, Object[] arguments,
54       MethodProxy methodProxy) throws Throwable {
55     return new InterceptedMethodInvocation(proxy, methodProxy, arguments, 0).proceed();
56   }
57 
58   private class InterceptedMethodInvocation implements MethodInvocation {
59 
60     final Object proxy;
61     final Object[] arguments;
62     final MethodProxy methodProxy;
63     final int index;
64 
InterceptedMethodInvocation(Object proxy, MethodProxy methodProxy, Object[] arguments, int index)65     public InterceptedMethodInvocation(Object proxy, MethodProxy methodProxy,
66         Object[] arguments, int index) {
67       this.proxy = proxy;
68       this.methodProxy = methodProxy;
69       this.arguments = arguments;
70       this.index = index;
71     }
72 
proceed()73     public Object proceed() throws Throwable {
74       try {
75         return index == interceptors.length
76             ? methodProxy.invokeSuper(proxy, arguments)
77             : interceptors[index].invoke(
78                 new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1));
79       } catch (Throwable t) {
80         pruneStacktrace(t);
81         throw t;
82       }
83     }
84 
getMethod()85     public Method getMethod() {
86       return method;
87     }
88 
getArguments()89     public Object[] getArguments() {
90       return arguments;
91     }
92 
getThis()93     public Object getThis() {
94       return proxy;
95     }
96 
getStaticPart()97     public AccessibleObject getStaticPart() {
98       return getMethod();
99     }
100   }
101 
102   /**
103    * Removes stacktrace elements related to AOP internal mechanics from the
104    * throwable's stack trace and any causes it may have.
105    */
pruneStacktrace(Throwable throwable)106   private void pruneStacktrace(Throwable throwable) {
107     for(Throwable t = throwable; t != null; t = t.getCause()) {
108       StackTraceElement[] stackTrace = t.getStackTrace();
109       List<StackTraceElement> pruned = Lists.newArrayList();
110       for (StackTraceElement element : stackTrace) {
111         String className = element.getClassName();
112         if (!AOP_INTERNAL_CLASSES.contains(className) && !className.contains("$EnhancerByGuice$")) {
113           pruned.add(element);
114         }
115       }
116       t.setStackTrace(pruned.toArray(new StackTraceElement[pruned.size()]));
117     }
118   }
119 }
120