Package com.blazebit.cdi.exception

Source Code of com.blazebit.cdi.exception.CatchHandlerInterceptor

/*
* Copyright 2011 Blazebit
*/
package com.blazebit.cdi.exception;

import com.blazebit.annotation.AnnotationUtils;
import com.blazebit.cdi.cleanup.annotation.Cleanup;
import com.blazebit.cdi.exception.annotation.CatchHandler;
import com.blazebit.cdi.exception.annotation.CatchHandling;
import com.blazebit.exception.ExceptionUtils;
import com.blazebit.reflection.ReflectionUtils;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import org.apache.deltaspike.core.api.exception.control.event.ExceptionToCatchEvent;

/**
*
* @author Christian Beikov
* @since 0.1.2
* @see CatchHandler
* @see CatchHandling
*
*/
@Interceptor
@CatchHandler
public class CatchHandlerInterceptor implements Serializable {

  private static final long serialVersionUID = 1L;

  @Inject
  private Event<ExceptionToCatchEvent> catchEvent;

  /**
   * Handles the exception.
   *
   * @param ic
   *            The InvocationContext.
   * @return The result of the intercepted method.
   * @throws Exception
   *             if an error occurs the handling
   */
  @AroundInvoke
  public Object handle(InvocationContext ic) throws Exception {
    Method m = ic.getMethod();
    Object targetObject = ic.getTarget();
    Class<?> targetClass = targetObject == null ? m.getDeclaringClass()
        : targetObject.getClass();
    CatchHandler exceptionHandlerAnnotation = AnnotationUtils
        .findAnnotation(m, targetClass, CatchHandler.class);
    Exception unexpectedException = null;

    if (exceptionHandlerAnnotation == null) {
      throw new IllegalStateException(
          "The interceptor annotation can not be determined!");
    }

    CatchHandling[] exceptionHandlingAnnotations = exceptionHandlerAnnotation
        .value();
    Class<? extends Throwable>[] unwrap = exceptionHandlerAnnotation
        .unwrap();

    try {
      return ic.proceed();
    } catch (Exception ex) {
      if (!contains(unwrap, InvocationTargetException.class)) {
        unwrap = Arrays.copyOf(unwrap, unwrap.length + 1);
        unwrap[unwrap.length - 1] = InvocationTargetException.class;
      }

      // Unwrap Exception if ex is instanceof InvocationTargetException
      Throwable t = ExceptionUtils.unwrap(ex,
          InvocationTargetException.class);
      boolean exceptionHandled = false;
                        boolean cleanupInvoked = false;

      if (exceptionHandlingAnnotations.length > 0) {
        for (CatchHandling handling : exceptionHandlingAnnotations) {
          if (handling.exception().isInstance(t)) {
            try {
              handleThrowable(t);
              exceptionHandled = true;
            } catch (Exception unexpected) {
              unexpectedException = unexpected;
            }

            // Only invoke cleanup declared at handling level
            if (!handling.cleanup().equals(Object.class)) {
                                                        cleanupInvoked = invokeCleanups(targetClass, targetObject,
                                                                    handling.cleanup(), t);
            }

            break;
          }
        }
      }

      // Handle the default exception type if no handlings are
      // declared or the handling did not handle the exception
      if (!exceptionHandled) {
        if (exceptionHandlerAnnotation.exception().isInstance(t)) {
          try {
            handleThrowable(t);
            exceptionHandled = true;
          } catch (Exception unexpected) {
            unexpectedException = unexpected;
          }

          if (!exceptionHandlerAnnotation.cleanup().equals(
              Object.class) && !cleanupInvoked) {
            if(!cleanupInvoked) {
                                                    invokeCleanups(targetClass, targetObject,
                exceptionHandlerAnnotation.cleanup(), t);
                                                }
          }
        }
      }

      if (!exceptionHandled) {
        if (t instanceof Exception) {
          unexpectedException = (Exception) t;
        } else {
          unexpectedException = new Exception(t);
        }
      }
    }

    if (unexpectedException != null) {
      throw unexpectedException;
    }

    return null;
  }

  private static boolean contains(Class<? extends Throwable>[] classes,
      Class<? extends Throwable> clazz) {
    for (int i = 0; i < classes.length; i++) {
      if (classes[i].getName().equals(clazz.getName())) {
        return true;
      }
    }

    return false;
  }

  /**
   * This method should populate the given throwable to a handler that will do
   * the appropriate exception handling. The default implementation will
   * populate the throwable via CDI-Event.
   *
   * @param t
   *            The throwable to handle
   */
  protected void handleThrowable(Throwable t) {
    catchEvent.fire(new ExceptionToCatchEvent(t));
  }

  /**
   * Invokes the cleanup methods of the exception handler or exception
   * handling.
   *
   * @param clazz
   *            the class of the bean to get the methods from
   * @param target
   *            the target on which the method is invoked
   * @param cleanupName
   *            the name of the cleanup method
   * @return true if the cleanup method were found and invoked
   * @throws Exception
   *             if an reflection specific exception occurs
   */
  private boolean invokeCleanups(Class<?> clazz, Object target,
      Class<?> cleanupClazz, Throwable exception) throws Exception {
    boolean invoked = false;

    if (!cleanupClazz.equals(Object.class)) {
                        // Christian Beikov 29.07.2013: Traverse whole hierarchy
                        // instead of retrieving the annotation directly from
                        // the class object.
                        Method m = ReflectionUtils.getMethod(clazz, Cleanup.class);
                       
                        if(m != null) {
                            final Class<?>[] parameterTypes = m.getParameterTypes();
                            if (parameterTypes.length == 1) {
                                if (ReflectionUtils.isSubtype(exception.getClass(), parameterTypes[0])) {
                                    m.invoke(target, exception);
                                    invoked = true;
                                } else {
                                    throw new IllegalArgumentException("Cleanup method with name " + cleanupClazz.getName() + " requires a parameter that is not a subtype of the exception class " + exception.getClass().getName());
                                }
                            } else {
                                m.invoke(target);
                                invoked = true;
                            }
                        }
    }
               
    return invoked;
  }
}
TOP

Related Classes of com.blazebit.cdi.exception.CatchHandlerInterceptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.