com.comcast.drivethru.spring.ExceptionHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of drive-thru Show documentation
Show all versions of drive-thru Show documentation
Drive-Thru is a helper utility for making HTTP requests
/**
* Copyright 2013 Comcast Cable Communications Management, LLC
*
* 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.
*/
package com.comcast.drivethru.spring;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
* Common exception handler for the TokenController. This will log the error and then present a
* common page with the HTTP status code and reason. The application using this ExceptionHandler
* must provide a view capable of rendering the error dialog. This is set with the
* viewName
property. In addition, an application can provide a custom mapping of error
* codes or mark an exception using the {@link ResponseStatus} annotation. The default HTTP response
* code is 500 Internal Server Error
.
*
*
* An example use of this is below:
*
*
*
* <!-- Common Exception Handling -->
* <bean class="com.comcast.drivethru.spring.ExceptionHandler">
* <property name="defaultResponse" value="500" />
* <property name="viewName" value="error.html" />
* <property name="exceptionMap">
* <map>
* <entry key="com.comcast.xtream.security.SecurityException" value="500" />
* </map>
* </property>
* </bean>
*
*
*
* The view will have access to three values: the status
which is the integer HTTP
* status code, the reason
which is the String reason code and the
* exception
which is the causing exception. The view can decide whether or not to
* include the exception stack trace in it's final output.
*
*
* @author Clark Malmgren
*/
public class ExceptionHandler implements HandlerExceptionResolver, Ordered {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandler.class);
private int defaultResponse = 500;
private String viewName = "error.html";
private Map, Integer> exceptionMap = null;
/**
* Set the default response code. If not set, this will default to 500.
*
* @param defaultResponse
* the new default response code to use
*/
public void setDefaultResponse(int defaultResponse) {
this.defaultResponse = defaultResponse;
}
/**
* Get the default response code.
*
* @return the default response code
*/
public int getDefaultResponse() {
return defaultResponse;
}
/**
* Set the view name to use. If not set, this will default to "error.html"
.
*
* @param viewName
* the new view name to use
*/
public void setViewName(String viewName) {
this.viewName = viewName;
}
/**
* Get the view name
*
* @return the view name
*/
public String getViewName() {
return viewName;
}
/**
* Add a custom mapping of exceptions to HTTP status codes.
*
* @param exceptionMap
* the new custom mapping to use
*/
public void setExceptionMap(Map, Integer> exceptionMap) {
this.exceptionMap = exceptionMap;
}
/**
* Get the custom exception map if one was set.
*
* @return the custom exception mapping
*/
public Map, Integer> getExceptionMap() {
return exceptionMap;
}
/*
* (non-Javadoc)
* @see org.springframework.core.Ordered#getOrder()
*/
@Override
public int getOrder() {
/* Ensure that we are first up! */
return Integer.MIN_VALUE;
}
/*
* (non-Javadoc)
* @see
* org.springframework.web.servlet.HandlerExceptionResolver#resolveException(javax.servlet.http
* .HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object,
* java.lang.Exception)
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
/* Log the exception */
LOGGER.error("Exception thrown by controller: ", ex);
/* Build the response */
HttpStatus status = null;
String reason = null;
/* Look for a @ResponseStatus */
Class extends Exception> clazz = ex.getClass();
ResponseStatus responseStatus = clazz.getAnnotation(ResponseStatus.class);
if (null != responseStatus) {
status = responseStatus.value();
reason = responseStatus.reason();
} else if (null != exceptionMap) {
/* See if there is a specific exception mapping */
for (Entry, Integer> entry : exceptionMap.entrySet()) {
if (entry.getKey().isAssignableFrom(clazz)) {
status = HttpStatus.valueOf(entry.getValue());
break;
}
}
}
/* If no specific status was found, use the default */
if (null == status) {
status = HttpStatus.valueOf(defaultResponse);
}
/* If no custom reason phrase was provide, use the default for the HttpStatus code */
if (null == reason || "".equals(reason)) {
reason = status.getReasonPhrase();
}
/*
* Add the response code to the response, we do not add the custom reason although it will
* be potentially consumed by the view
*/
response.setStatus(status.value());
/* Create the ModelAndView */
ModelAndView mav = new ModelAndView(viewName);
mav.addObject("status", status.value());
mav.addObject("reason", reason);
mav.addObject("exception", ex);
return mav;
}
}