KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > aop > framework > ReflectiveMethodInvocation


1 /*
2  * Copyright 2002-2007 the original author or authors.
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 org.springframework.aop.framework;
18
19 import java.lang.reflect.AccessibleObject JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.aopalliance.intercept.MethodInterceptor;
26 import org.aopalliance.intercept.MethodInvocation;
27
28 import org.springframework.aop.ProxyMethodInvocation;
29 import org.springframework.aop.support.AopUtils;
30
31 /**
32  * Spring's implementation of the AOP Alliance
33  * {@link org.aopalliance.intercept.MethodInvocation} interface,
34  * implementing the extended
35  * {@link org.springframework.aop.ProxyMethodInvocation} interface.
36  *
37  * <p>Invokes the target object using reflection. Subclasses can override the
38  * {@link #invokeJoinpoint()} method to change this behavior, so this is also
39  * a useful base class for more specialized MethodInvocation implementations.
40  *
41  * <p>It is possible to clone an invocation, to invoke {@link #proceed()}
42  * repeatedly (once per clone), using the {@link #invocableClone()} method.
43  * It is also possible to attach custom attributes to the invocation,
44  * using the {@link #setUserAttribute} / {@link #getUserAttribute} methods.
45  *
46  * @author Rod Johnson
47  * @author Juergen Hoeller
48  * @see #invokeJoinpoint
49  * @see #proceed
50  * @see #invocableClone
51  * @see #setUserAttribute
52  * @see #getUserAttribute
53  */

54 public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable JavaDoc {
55
56     protected final Object JavaDoc proxy;
57
58     protected final Object JavaDoc target;
59
60     protected final Method JavaDoc method;
61
62     protected Object JavaDoc[] arguments;
63
64     private final Class JavaDoc targetClass;
65
66     /**
67      * Lazily initialized map of user-specific attributes for this invocation.
68      */

69     private Map JavaDoc userAttributes;
70
71     /**
72      * List of MethodInterceptor and InterceptorAndDynamicMethodMatcher
73      * that need dynamic checks.
74      */

75     protected final List JavaDoc interceptorsAndDynamicMethodMatchers;
76
77     /**
78      * Index from 0 of the current interceptor we're invoking.
79      * -1 until we invoke: then the current interceptor.
80      */

81     private int currentInterceptorIndex = -1;
82
83
84     /**
85      * Construct a new ReflectiveMethodInvocation with the given arguments.
86      * @param proxy the proxy object that the invocation was made on
87      * @param target the target object to invoke
88      * @param method the method to invoke
89      * @param arguments the arguments to invoke the method with
90      * @param targetClass the target class, for MethodMatcher invocations
91      * @param interceptorsAndDynamicMethodMatchers interceptors that should be applied,
92      * along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime.
93      * MethodMatchers included in this struct must already have been found to have matched
94      * as far as was possibly statically. Passing an array might be about 10% faster,
95      * but would complicate the code. And it would work only for static pointcuts.
96      */

97     public ReflectiveMethodInvocation(
98         Object JavaDoc proxy, Object JavaDoc target, Method JavaDoc method, Object JavaDoc[] arguments,
99         Class JavaDoc targetClass, List JavaDoc interceptorsAndDynamicMethodMatchers) {
100
101         this.proxy = proxy;
102         this.target = target;
103         this.targetClass = targetClass;
104         this.method = method;
105         this.arguments = arguments;
106         this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
107     }
108
109
110     public final Object JavaDoc getProxy() {
111         return this.proxy;
112     }
113
114     public final Object JavaDoc getThis() {
115         return this.target;
116     }
117
118     public final AccessibleObject JavaDoc getStaticPart() {
119         return this.method;
120     }
121
122     /**
123      * Return the method invoked on the proxied interface.
124      * May or may not correspond with a method invoked on an underlying
125      * implementation of that interface.
126      */

127     public final Method JavaDoc getMethod() {
128         return this.method;
129     }
130
131     public final Object JavaDoc[] getArguments() {
132         return (this.arguments != null ? this.arguments : new Object JavaDoc[0]);
133     }
134
135
136     public Object JavaDoc proceed() throws Throwable JavaDoc {
137         // We start with an index of -1 and increment early.
138
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
139             return invokeJoinpoint();
140         }
141
142         Object JavaDoc interceptorOrInterceptionAdvice =
143             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
144         if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
145             // Evaluate dynamic method matcher here: static part will already have
146
// been evaluated and found to match.
147
InterceptorAndDynamicMethodMatcher dm =
148                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
149             if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
150                 return dm.interceptor.invoke(this);
151             }
152             else {
153                 // Dynamic matching failed.
154
// Skip this interceptor and invoke the next in the chain.
155
return proceed();
156             }
157         }
158         else {
159             // It's an interceptor, so we just invoke it: The pointcut will have
160
// been evaluated statically before this object was constructed.
161
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
162         }
163     }
164
165     /**
166      * Invoke the joinpoint using reflection.
167      * Subclasses can override this to use custom invocation.
168      * @return the return value of the joinpoint
169      * @throws Throwable if invoking the joinpoint resulted in an exception
170      */

171     protected Object JavaDoc invokeJoinpoint() throws Throwable JavaDoc {
172         return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
173     }
174
175
176     /**
177      * This implementation returns a shallow copy of this invocation object,
178      * including an independent copy of the original arguments array.
179      * <p>We want a shallow copy in this case: We want to use the same interceptor
180      * chain and other object references, but we want an independent value for the
181      * current interceptor index.
182      * @see java.lang.Object#clone()
183      */

184     public MethodInvocation invocableClone() {
185         Object JavaDoc[] cloneArguments = null;
186         if (this.arguments != null) {
187             // Build an independent copy of the arguments array.
188
cloneArguments = new Object JavaDoc[this.arguments.length];
189             System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length);
190         }
191         return invocableClone(cloneArguments);
192     }
193
194     /**
195      * This implementation returns a shallow copy of this invocation object,
196      * using the given arguments array for the clone.
197      * <p>We want a shallow copy in this case: We want to use the same interceptor
198      * chain and other object references, but we want an independent value for the
199      * current interceptor index.
200      * @see java.lang.Object#clone()
201      */

202     public MethodInvocation invocableClone(Object JavaDoc[] arguments) {
203         try {
204             ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
205             clone.arguments = arguments;
206             return clone;
207         }
208         catch (CloneNotSupportedException JavaDoc ex) {
209             throw new IllegalStateException JavaDoc(
210                     "Should be able to clone object of type [" + getClass() + "]: " + ex);
211         }
212     }
213
214
215     public void setUserAttribute(String JavaDoc key, Object JavaDoc value) {
216         if (value != null) {
217             if (this.userAttributes == null) {
218                 this.userAttributes = new HashMap JavaDoc();
219             }
220             this.userAttributes.put(key, value);
221         }
222         else {
223             if (this.userAttributes != null) {
224                 this.userAttributes.remove(key);
225             }
226         }
227     }
228
229     public Object JavaDoc getUserAttribute(String JavaDoc key) {
230         return (this.userAttributes != null ? this.userAttributes.get(key) : null);
231     }
232
233     /**
234      * Return user attributes associated with this invocation.
235      * This method provides an invocation-bound alternative to a ThreadLocal.
236      * <p>This map is initialized lazily and is not used in the AOP framework itself.
237      * @return any user attributes associated with this invocation
238      * (never <code>null</code>)
239      */

240     public Map JavaDoc getUserAttributes() {
241         if (this.userAttributes == null) {
242             this.userAttributes = new HashMap JavaDoc();
243         }
244         return this.userAttributes;
245     }
246
247
248     public String JavaDoc toString() {
249         // Don't do toString on target, it may be proxied.
250
StringBuffer JavaDoc sb = new StringBuffer JavaDoc("ReflectiveMethodInvocation: ");
251         sb.append(this.method).append("; ");
252         if (this.target == null) {
253             sb.append("target is null");
254         }
255         else {
256             sb.append("target is of class [").append(this.target.getClass().getName()).append(']');
257         }
258         return sb.toString();
259     }
260
261 }
262
Popular Tags