org.broadleafcommerce.core.web.api.BroadleafSpringRestExceptionMapper.java Source code

Java tutorial

Introduction

Here is the source code for org.broadleafcommerce.core.web.api.BroadleafSpringRestExceptionMapper.java

Source

/*
 * #%L
 * BroadleafCommerce Framework Web
 * %%
 * Copyright (C) 2009 - 2013 Broadleaf Commerce
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package org.broadleafcommerce.core.web.api;

import java.util.Locale;
import java.util.Set;

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

import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.util.ApplicationContextHolder;
import org.broadleafcommerce.common.web.BroadleafRequestContext;
import org.broadleafcommerce.core.web.api.wrapper.ErrorMessageWrapper;
import org.broadleafcommerce.core.web.api.wrapper.ErrorWrapper;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

/**
 * <p>
 * Handles exceptions that can occur in the Broadleaf REST APIs. Specifically, this will serialize exceptions into
 * consumable JSON or XML so that clients that utilize the API don't have to treat exception responses as special cases.
 *
 * @author Chris Kittrell (ckittrell)
 * @author Phillip Verheyden (phillipuniverse)
 */
public class BroadleafSpringRestExceptionMapper {

    private static final Log LOG = LogFactory.getLog(BroadleafSpringRestExceptionMapper.class);

    protected String messageKeyPrefix = BroadleafWebServicesException.class.getName() + '.';

    @Resource(name = "messageSource")
    protected MessageSource messageSource;

    protected ApplicationContext context = ApplicationContextHolder.getApplicationContext();

    @ExceptionHandler(BroadleafWebServicesException.class)
    public @ResponseBody ErrorWrapper handleBroadleafWebServicesException(HttpServletRequest request,
            HttpServletResponse response, Exception ex) {
        ErrorWrapper errorWrapper = (ErrorWrapper) context.getBean(ErrorWrapper.class.getName());
        BroadleafWebServicesException blcException = (BroadleafWebServicesException) ex;
        Locale locale = null;
        BroadleafRequestContext requestContext = BroadleafRequestContext.getBroadleafRequestContext();
        if (requestContext != null) {
            locale = requestContext.getJavaLocale();
        }

        if (ex.getCause() != null) {
            LOG.error("An error occured invoking a REST service.", ex.getCause());
        }
        errorWrapper.setHttpStatusCode(blcException.getHttpStatusCode());
        response.setStatus(resolveResponseStatusCode(ex, errorWrapper));
        if (blcException.getLocale() != null) {
            locale = blcException.getLocale();
        }
        if (locale == null) {
            locale = Locale.getDefault();
        }

        if (blcException.getMessages() != null && !blcException.getMessages().isEmpty()) {
            Set<String> keys = blcException.getMessages().keySet();
            for (String key : keys) {
                ErrorMessageWrapper errorMessageWrapper = (ErrorMessageWrapper) context
                        .getBean(ErrorMessageWrapper.class.getName());
                errorMessageWrapper.setMessageKey(resolveClientMessageKey(key));
                errorMessageWrapper.setMessage(
                        messageSource.getMessage(key, blcException.getMessages().get(key), key, locale));
                errorWrapper.getMessages().add(errorMessageWrapper);
            }
        } else {
            ErrorMessageWrapper errorMessageWrapper = (ErrorMessageWrapper) context
                    .getBean(ErrorMessageWrapper.class.getName());
            errorMessageWrapper.setMessageKey(resolveClientMessageKey(BroadleafWebServicesException.UNKNOWN_ERROR));
            errorMessageWrapper.setMessage(messageSource.getMessage(BroadleafWebServicesException.UNKNOWN_ERROR,
                    null, BroadleafWebServicesException.UNKNOWN_ERROR, locale));
            errorWrapper.getMessages().add(errorMessageWrapper);
        }

        return errorWrapper;
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public @ResponseBody ErrorWrapper handleNoHandlerFoundException(HttpServletRequest request,
            HttpServletResponse response, Exception ex) {
        ErrorWrapper errorWrapper = (ErrorWrapper) context.getBean(ErrorWrapper.class.getName());
        Locale locale = null;
        BroadleafRequestContext requestContext = BroadleafRequestContext.getBroadleafRequestContext();
        if (requestContext != null) {
            locale = requestContext.getJavaLocale();
        }

        LOG.error("An error occured invoking a REST service", ex);
        if (locale == null) {
            locale = Locale.getDefault();
        }
        errorWrapper.setHttpStatusCode(HttpStatus.SC_NOT_FOUND);
        response.setStatus(resolveResponseStatusCode(ex, errorWrapper));
        ErrorMessageWrapper errorMessageWrapper = (ErrorMessageWrapper) context
                .getBean(ErrorMessageWrapper.class.getName());
        errorMessageWrapper.setMessageKey(resolveClientMessageKey(BroadleafWebServicesException.NOT_FOUND));
        errorMessageWrapper.setMessage(messageSource.getMessage(BroadleafWebServicesException.NOT_FOUND, null,
                BroadleafWebServicesException.NOT_FOUND, locale));
        errorWrapper.getMessages().add(errorMessageWrapper);

        return errorWrapper;
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public @ResponseBody ErrorWrapper handleHttpMediaTypeNotSupportedException(HttpServletRequest request,
            HttpServletResponse response, Exception ex) {
        ErrorWrapper errorWrapper = (ErrorWrapper) context.getBean(ErrorWrapper.class.getName());
        Locale locale = null;
        BroadleafRequestContext requestContext = BroadleafRequestContext.getBroadleafRequestContext();
        if (requestContext != null) {
            locale = requestContext.getJavaLocale();
        }

        LOG.error("An error occured invoking a REST service", ex);
        if (locale == null) {
            locale = Locale.getDefault();
        }
        errorWrapper.setHttpStatusCode(HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE);
        response.setStatus(resolveResponseStatusCode(ex, errorWrapper));
        ErrorMessageWrapper errorMessageWrapper = (ErrorMessageWrapper) context
                .getBean(ErrorMessageWrapper.class.getName());
        errorMessageWrapper
                .setMessageKey(resolveClientMessageKey(BroadleafWebServicesException.CONTENT_TYPE_NOT_SUPPORTED));
        errorMessageWrapper.setMessage(messageSource.getMessage(
                BroadleafWebServicesException.CONTENT_TYPE_NOT_SUPPORTED, new String[] { request.getContentType() },
                BroadleafWebServicesException.CONTENT_TYPE_NOT_SUPPORTED, locale));
        errorWrapper.getMessages().add(errorMessageWrapper);

        return errorWrapper;
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public @ResponseBody ErrorWrapper handleMissingServletRequestParameterException(HttpServletRequest request,
            HttpServletResponse response, Exception ex) {
        ErrorWrapper errorWrapper = (ErrorWrapper) context.getBean(ErrorWrapper.class.getName());
        Locale locale = null;
        String parameterType = null;
        String parameterName = null;
        BroadleafRequestContext requestContext = BroadleafRequestContext.getBroadleafRequestContext();
        if (requestContext != null) {
            locale = requestContext.getJavaLocale();
        }
        if (ex instanceof MissingServletRequestParameterException) {
            MissingServletRequestParameterException castedException = (MissingServletRequestParameterException) ex;
            parameterType = castedException.getParameterType();
            parameterName = castedException.getParameterName();
        }

        LOG.error("An error occured invoking a REST service", ex);
        if (locale == null) {
            locale = Locale.getDefault();
        }
        if (parameterType == null) {
            parameterType = "String";
        }
        if (parameterName == null) {
            parameterName = "[unknown name]";
        }
        errorWrapper.setHttpStatusCode(HttpStatus.SC_BAD_REQUEST);
        response.setStatus(resolveResponseStatusCode(ex, errorWrapper));
        ErrorMessageWrapper errorMessageWrapper = (ErrorMessageWrapper) context
                .getBean(ErrorMessageWrapper.class.getName());
        errorMessageWrapper
                .setMessageKey(resolveClientMessageKey(BroadleafWebServicesException.QUERY_PARAMETER_NOT_PRESENT));
        errorMessageWrapper
                .setMessage(messageSource.getMessage(BroadleafWebServicesException.QUERY_PARAMETER_NOT_PRESENT,
                        new String[] { parameterType, parameterName },
                        BroadleafWebServicesException.QUERY_PARAMETER_NOT_PRESENT, locale));
        errorWrapper.getMessages().add(errorMessageWrapper);

        return errorWrapper;
    }

    @ExceptionHandler(Exception.class)
    public @ResponseBody ErrorWrapper handleException(HttpServletRequest request, HttpServletResponse response,
            Exception ex) {
        ErrorWrapper errorWrapper = (ErrorWrapper) context.getBean(ErrorWrapper.class.getName());
        Locale locale = null;
        BroadleafRequestContext requestContext = BroadleafRequestContext.getBroadleafRequestContext();
        if (requestContext != null) {
            locale = requestContext.getJavaLocale();
        }

        LOG.error("An error occured invoking a REST service", ex);
        if (locale == null) {
            locale = Locale.getDefault();
        }
        errorWrapper.setHttpStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
        response.setStatus(resolveResponseStatusCode(ex, errorWrapper));
        ErrorMessageWrapper errorMessageWrapper = (ErrorMessageWrapper) context
                .getBean(ErrorMessageWrapper.class.getName());
        errorMessageWrapper.setMessageKey(resolveClientMessageKey(BroadleafWebServicesException.UNKNOWN_ERROR));
        errorMessageWrapper.setMessage(messageSource.getMessage(BroadleafWebServicesException.UNKNOWN_ERROR, null,
                BroadleafWebServicesException.UNKNOWN_ERROR, locale));
        errorWrapper.getMessages().add(errorMessageWrapper);
        return errorWrapper;
    }

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    /**
     * This key is the prefix that will be stripped off of all message keys that are returned to a client.
     * The default is "org.broadleafcommerce.core.web.api.BroadleafWebServicesException.". So, if a message key contained
     * in a BroadleafWebServicesException is org.broadleafcommerce.core.web.api.BroadleafWebServicesException.unknownError,
     * just "unknownError" will be returned to the client. This behavior can be changed by overriding the
     * <code>resolveClientMessageKey</code> method.
     * @param prefix
     */
    public void setMessageKeyPrefix(String prefix) {
        this.messageKeyPrefix = prefix;
    }

    /*
     * This allows you to return a different HTTP response code in the HTTP response than what is in the response wrapper.
     * For example, some clients may wish to always return a 200 (SUCCESS), even when there is an error.
     * The default behavior is to return the same status code associated with the error wrapper, or 500 if it is not known.
     */
    protected int resolveResponseStatusCode(Throwable t, ErrorWrapper error) {
        if (error.getHttpStatusCode() == null) {
            return 500;
        }
        return error.getHttpStatusCode();
    }

    protected String resolveClientMessageKey(String key) {
        if (messageKeyPrefix != null) {
            return StringUtils.remove(key, messageKeyPrefix);
        }
        return key;
    }
}