1. /*
  2. * Copyright 2002-2004 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. package org.springframework.aop.framework;
  17. import java.lang.reflect.AccessibleObject;
  18. import java.lang.reflect.Method;
  19. import java.util.List;
  20. import org.aopalliance.intercept.MethodInterceptor;
  21. import org.aopalliance.intercept.MethodInvocation;
  22. /**
  23. * Spring implementation of AOP Alliance MethodInvocation interface.
  24. *
  25. * <p>Invokes target using reflection. Subclasses can override the
  26. * invokeJoinpoint() method to change this behaviour, so this is a
  27. * useful base class for MethodInvocation implementations.
  28. *
  29. * @author Rod Johnson
  30. * @version $Id: ReflectiveMethodInvocation.java,v 1.5 2004/04/21 17:49:36 jhoeller Exp $
  31. * @see #invokeJoinpoint
  32. */
  33. public class ReflectiveMethodInvocation implements MethodInvocation {
  34. protected Method method;
  35. protected Object[] arguments;
  36. protected Object target;
  37. protected Object proxy;
  38. /**
  39. * List of Methodnterceptor and InterceptorAndDynamicMethodMatcher
  40. * that need dynamic checks.
  41. */
  42. protected List interceptorsAndDynamicMethodMatchers;
  43. /**
  44. * Index from 0 of the current interceptor we're invoking.
  45. * -1 until we invoke: then the current interceptor
  46. */
  47. private int currentInterceptorIndex = -1;
  48. private Class targetClass;
  49. /**
  50. * Construct a new MethodInvocation with given arguments
  51. * @param interceptorsAndDynamicMethodMatchers interceptors that should be applied,
  52. * along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime.
  53. * MethodMatchers included in this struct must already have been found to have matched as far
  54. * as was possibly statically. Passing an array might be about 10% faster, but would complicate
  55. * the code. And it would work only for static pointcuts.
  56. */
  57. public ReflectiveMethodInvocation(Object proxy, Object target,
  58. Method m, Object[] arguments,
  59. Class targetClass, List interceptorsAndDynamicMethodMatchers) {
  60. this.proxy = proxy;
  61. this.target = target;
  62. this.targetClass = targetClass;
  63. this.method = m;
  64. this.arguments = arguments;
  65. this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
  66. }
  67. /**
  68. * Return the method invoked on the proxied interface.
  69. * May or may not correspond with a method invoked on an underlying
  70. * implementation of that interface.
  71. * @return Method
  72. */
  73. public final Method getMethod() {
  74. return this.method;
  75. }
  76. public final AccessibleObject getStaticPart() {
  77. return this.method;
  78. }
  79. /**
  80. * Return the proxy that this interception was made through
  81. * @return Object
  82. */
  83. public final Object getProxy() {
  84. return this.proxy;
  85. }
  86. /**
  87. * Private optimization method
  88. * @return Object[]
  89. */
  90. public final Object[] getArguments() {
  91. return this.arguments;
  92. }
  93. /**
  94. * @see org.aopalliance.intercept.Invocation#proceed
  95. */
  96. public Object proceed() throws Throwable {
  97. // We start with an index of -1 and increment early
  98. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  99. return invokeJoinpoint();
  100. }
  101. Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  102. if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
  103. // Evaluate dynamic method matcher here: static part will already have
  104. // been evaluated and found to match
  105. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
  106. if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
  107. return dm.interceptor.invoke(this);
  108. }
  109. else {
  110. // Dynamic matching failed
  111. // Skip this interceptor and invoke the next in the chain
  112. return proceed();
  113. }
  114. }
  115. else {
  116. // It's an interceptor so we just invoke it: The pointcut will have
  117. // been evaluated statically before this object was constructed.
  118. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  119. }
  120. }
  121. /**
  122. * Invoke the joinpoint using reflection.
  123. * Subclasses can override this to use custom invocation.
  124. * @return the return value of the joinpoint
  125. * @throws Throwable if invoking the joinpoint resulted in an exception
  126. */
  127. protected Object invokeJoinpoint() throws Throwable {
  128. return AopProxyUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
  129. }
  130. /**
  131. * @see org.aopalliance.intercept.Invocation#getThis
  132. */
  133. public final Object getThis() {
  134. return this.target;
  135. }
  136. public String toString() {
  137. // Don't do toString on target, it may be proxied.
  138. // toString on args may also fail.
  139. StringBuffer sb = new StringBuffer("Invocation: method=[");
  140. sb.append(this.method).append("] ").append("args=").append(this.arguments).append("] ");
  141. if (this.target == null) {
  142. sb.append("target is null");
  143. }
  144. else {
  145. sb.append("target is of class [").append(this.target.getClass().getName()).append(']');
  146. }
  147. return sb.toString();
  148. }
  149. }