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.adapter;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.util.HashMap;
  20. import java.util.Map;
  21. import org.aopalliance.intercept.MethodInterceptor;
  22. import org.aopalliance.intercept.MethodInvocation;
  23. import org.apache.commons.logging.Log;
  24. import org.apache.commons.logging.LogFactory;
  25. /**
  26. * Interceptor to wrap an after throwing advice.
  27. *
  28. * <p>The signatures on handler methods on the throwsAdvice constructor argument
  29. * must be of form:<br>
  30. * <code>void afterThrowing([Method], [args], [target], ThrowableSubclass);</code><br>
  31. * Only the last argument is required.
  32. *
  33. * <p>This is a framework class that need not be used directly by Spring users.
  34. *
  35. * @author Rod Johnson
  36. * @version $Id: ThrowsAdviceInterceptor.java,v 1.3 2004/04/01 15:35:47 jhoeller Exp $
  37. */
  38. final class ThrowsAdviceInterceptor implements MethodInterceptor {
  39. private static final String AFTER_THROWING = "afterThrowing";
  40. private final Log logger = LogFactory.getLog(getClass());
  41. private Object throwsAdvice;
  42. /** Methods on throws advice, keyed by exception class */
  43. private Map exceptionHandlerHash;
  44. public ThrowsAdviceInterceptor(Object throwsAdvice) {
  45. this.throwsAdvice = throwsAdvice;
  46. Method[] methods = throwsAdvice.getClass().getMethods();
  47. exceptionHandlerHash = new HashMap();
  48. for (int i = 0; i < methods.length; i++) {
  49. Method m = methods[i];
  50. if (m.getName().equals(AFTER_THROWING) &&
  51. //m.getReturnType() == null &&
  52. (m.getParameterTypes().length == 1 || m.getParameterTypes().length == 4) &&
  53. Throwable.class.isAssignableFrom(m.getParameterTypes()[m.getParameterTypes().length - 1])
  54. ) {
  55. // Have an exception handler
  56. exceptionHandlerHash.put(m.getParameterTypes()[m.getParameterTypes().length - 1], m);
  57. logger.info("Found exception handler method [" + m + "]");
  58. }
  59. }
  60. if (exceptionHandlerHash.isEmpty()) {
  61. throw new IllegalArgumentException("At least one handler method must be found in class " +
  62. throwsAdvice.getClass());
  63. }
  64. }
  65. public int getHandlerMethodCount() {
  66. return exceptionHandlerHash.size();
  67. }
  68. /**
  69. * Can return null if not found.
  70. *
  71. * @return a handler for the given exception type
  72. * @param exception
  73. * Won't be a ServletException or IOException
  74. */
  75. private Method getExceptionHandler(Throwable exception) {
  76. Class exceptionClass = exception.getClass();
  77. logger.info("Trying to find handler for exception of " + exceptionClass);
  78. Method handler = (Method) this.exceptionHandlerHash.get(exceptionClass);
  79. while (handler == null && !exceptionClass.equals(Throwable.class)) {
  80. logger.info("Looking at superclass " + exceptionClass);
  81. exceptionClass = exceptionClass.getSuperclass();
  82. handler = (Method) this.exceptionHandlerHash.get(exceptionClass);
  83. }
  84. return handler;
  85. }
  86. /**
  87. * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
  88. */
  89. public Object invoke(MethodInvocation mi) throws Throwable {
  90. try {
  91. return mi.proceed();
  92. }
  93. catch (Throwable t) {
  94. Method handlerMethod = getExceptionHandler(t);
  95. if (handlerMethod != null) {
  96. invokeHandlerMethod(mi, t, handlerMethod);
  97. }
  98. throw t;
  99. }
  100. }
  101. private void invokeHandlerMethod(MethodInvocation mi, Throwable t, Method m) throws Throwable {
  102. Object[] handlerArgs;
  103. if (m.getParameterTypes().length == 1) {
  104. handlerArgs = new Object[] { t };
  105. }
  106. else {
  107. handlerArgs = new Object[] { mi.getMethod(), mi.getArguments(), mi.getThis(), t };
  108. }
  109. try {
  110. m.invoke(this.throwsAdvice, handlerArgs);
  111. }
  112. catch (InvocationTargetException ex) {
  113. throw ex.getTargetException();
  114. }
  115. }
  116. }