tv.arte.resteventapi.web.errors.GlobalDefaultExceptionHandler.java Source code

Java tutorial

Introduction

Here is the source code for tv.arte.resteventapi.web.errors.GlobalDefaultExceptionHandler.java

Source

package tv.arte.resteventapi.web.errors;

/*
 * #%L
 * RestEventAPI
 * %%
 * Copyright (C) 2014 ARTE G.E.I.E
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of The MIT License (MIT) as published by the Open Source 
 * Initiative.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See The 
 * MIT License (MIT) for more details.
 * 
 * You should have received a copy of The MIT License (MIT) 
 * along with this program.  If not, see <http://opensource.org/licenses/MIT>
 * #L%
 */

import java.util.Collection;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import tv.arte.resteventapi.core.RestEventApiError;
import tv.arte.resteventapi.core.RestEventApiMessage;
import tv.arte.resteventapi.core.RestEventApiStandardResponse;
import tv.arte.resteventapi.core.exceptions.NoResultInApiException;
import tv.arte.resteventapi.core.validation.FieldValidationError;
import tv.arte.resteventapi.core.validation.RestEventApiValidationException;

/**
 * Global exception handling for front controllers
 * 
 * @author Simeon Petev
 * @since 0.1
 */
@ControllerAdvice
public class GlobalDefaultExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);

    public static final String DEFAULT_ERROR_VIEW = "error";

    @Autowired
    @Qualifier("restEventApiDefaultErrorView")
    private MappingJackson2JsonView restEventApiDefaultErrorView;

    @Autowired
    private MessageSource messageSource;

    /**
     * Handle all exceptions of type {@link ImageRepositoryException} thrown by (or passing trough) the Controller's layer
     * 
     * @param response The HttpServletResponse
     * @param e Thrown RestEventApiValidationException
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ModelAndView restEventApiMethodArgumentNotValidExceptionHandler(HttpServletRequest request,
            MethodArgumentNotValidException e) throws Exception {
        RestEventApiStandardResponse<RestEventApiMessage> restEventApiStandardResponse = new RestEventApiStandardResponse<RestEventApiMessage>();
        Locale userLocale = request.getLocale();
        String descriprionNotAvailableDefaultMessage = RestEventApiError.PRE_DEFINED.RIA_ERR_G_DESC_NOT_AVAILABLE
                .getDefaultMessageText();

        for (ObjectError globalError : e.getBindingResult().getGlobalErrors()) {
            restEventApiStandardResponse.addError(new RestEventApiMessage(globalError.getDefaultMessage(),
                    this.messageSource.getMessage(globalError.getCode(), globalError.getArguments(),
                            descriprionNotAvailableDefaultMessage, userLocale)));
        }

        for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {

            String messageCode = null;
            String defaultMessageText = null;

            if (fieldError.isBindingFailure()) {
                messageCode = RestEventApiError.PRE_DEFINED.RIA_ERR_V_BINDING.getCode();
                defaultMessageText = RestEventApiError.PRE_DEFINED.RIA_ERR_V_BINDING.getDefaultMessageText();
            } else {
                //TODO: Find an appropriate way to search pre-defined RestEventAPiError
                messageCode = fieldError.getDefaultMessage();
                defaultMessageText = descriprionNotAvailableDefaultMessage;
            }

            restEventApiStandardResponse
                    .addError(new FieldValidationError(messageCode, this.messageSource.getMessage(messageCode,
                            fieldError.getArguments(), defaultMessageText, userLocale), fieldError.getField()));

        }

        ModelAndView mav = new ModelAndView();
        mav.addObject(restEventApiStandardResponse);
        mav.setView(restEventApiDefaultErrorView);

        return mav;
    }

    /**
     * Handle all exceptions of type {@link ImageRepositoryException} thrown by (or passing trough) the Controller's layer
     * 
     * @param response The HttpServletResponse
     * @param e Thrown RestEventApiValidationException
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    @ExceptionHandler(value = RestEventApiValidationException.class)
    public ModelAndView restEventApiValidationExceptionHandler(HttpServletResponse response,
            RestEventApiValidationException e) throws Exception {
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }

        RestEventApiStandardResponse<RestEventApiMessage> restEventApiStandardResponse = new RestEventApiStandardResponse<RestEventApiMessage>();
        restEventApiStandardResponse
                .setErrors((Collection<RestEventApiMessage>) (Collection<?>) e.getValidationErrorMessages());

        ModelAndView mav = new ModelAndView();
        mav.addObject(restEventApiStandardResponse);
        mav.setView(restEventApiDefaultErrorView);

        if (e.getResponseHttpStatusCode() != null) {
            response.setStatus(e.getResponseHttpStatusCode());
        } else {
            response.setStatus(HttpStatus.BAD_REQUEST.value());
        }

        return mav;
    }

    /**
     * Handle all exceptions of type {@link BindException} thrown by (or passing trough) the Controller's layer
     * 
     * @param response The HttpServletResponse
     * @param e Thrown RestEventApiValidationException
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ModelAndView springBindExceptionExceptionHandler(HttpServletRequest request, BindException e)
            throws Exception {

        RestEventApiStandardResponse<RestEventApiMessage> restEventApiStandardResponse = new RestEventApiStandardResponse<RestEventApiMessage>();
        Locale userLocale = request.getLocale();
        String descriprionNotAvailableDefaultMessage = RestEventApiError.PRE_DEFINED.RIA_ERR_G_DESC_NOT_AVAILABLE
                .getDefaultMessageText();

        for (ObjectError globalError : e.getGlobalErrors()) {
            restEventApiStandardResponse.addError(new RestEventApiMessage(globalError.getDefaultMessage(),
                    this.messageSource.getMessage(globalError.getCode(), globalError.getArguments(),
                            descriprionNotAvailableDefaultMessage, userLocale)));
        }

        for (FieldError fieldError : e.getFieldErrors()) {

            String messageCode = null;
            String defaultMessageText = null;

            if (fieldError.isBindingFailure()) {
                messageCode = RestEventApiError.PRE_DEFINED.RIA_ERR_V_BINDING.getCode();
                defaultMessageText = RestEventApiError.PRE_DEFINED.RIA_ERR_V_BINDING.getDefaultMessageText();
            } else {
                //TODO: Find an appropriate way to search pre-defined RestEventAPiError
                messageCode = fieldError.getDefaultMessage();
                defaultMessageText = descriprionNotAvailableDefaultMessage;
            }

            restEventApiStandardResponse
                    .addError(new FieldValidationError(messageCode, this.messageSource.getMessage(messageCode,
                            fieldError.getArguments(), defaultMessageText, userLocale), fieldError.getField()));

        }

        ModelAndView mav = new ModelAndView();
        mav.addObject(restEventApiStandardResponse);
        mav.setView(restEventApiDefaultErrorView);

        return mav;
    }

    /**
     * Handle all exceptions of type {@link ImageRepositoryException} thrown by (or passing trough) the Controller's layer
     * 
     * @param response The HttpServletResponse
     * @param e Thrown NoResultInApiException
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = NoResultInApiException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView noResultInApiExceptionHandler(HttpServletResponse response, NoResultInApiException e)
            throws Exception {
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }

        RestEventApiStandardResponse<RestEventApiMessage> restEventApiStandardResponse = new RestEventApiStandardResponse<RestEventApiMessage>();
        restEventApiStandardResponse.addError(RestEventApiError.PRE_DEFINED.RIA_ERR_G_SEARCH_NO_RESULTS);

        ModelAndView mav = new ModelAndView();
        mav.addObject(restEventApiStandardResponse);
        mav.setView(restEventApiDefaultErrorView);

        return mav;
    }

    /**
     * Handle all exceptions thrown by Controller's layer and that have not been already handled
     * 
     * @param response The HttpServletResponse
     * @param e Thrown exception
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ModelAndView defaultErrorHandler(HttpServletResponse response, Exception e) throws Exception {
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }

        RestEventApiStandardResponse<RestEventApiMessage> restEventApiStandardResponse = new RestEventApiStandardResponse<RestEventApiMessage>();
        restEventApiStandardResponse.addError(RestEventApiError.PRE_DEFINED.RIA_ERR_G_UNKNOWN);

        if (e instanceof NullPointerException) {
            //Log full stacktrace in case of NullPointer
            logger.error(ExceptionUtils.getFullStackTrace(e));
        }

        ModelAndView mav = new ModelAndView();
        mav.addObject(restEventApiStandardResponse);
        mav.setView(restEventApiDefaultErrorView);

        return mav;
    }
}