/*
* Copyright (C) 2013-2017 NTT DATA Corporation
*
* 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 org.terasoluna.gfw.web.exception;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.terasoluna.gfw.common.exception.ExceptionCodeResolver;
import org.terasoluna.gfw.common.exception.ResultMessagesNotificationException;
import org.terasoluna.gfw.common.exception.SimpleMappingExceptionCodeResolver;
import org.terasoluna.gfw.common.message.ResultMessages;
/**
* Class that performs exception handling.
*/
public class SystemExceptionResolver extends SimpleMappingExceptionResolver {
/**
* Attribute name for storing result message in flash map.
*/
private String resultMessagesAttribute = ResultMessages.DEFAULT_MESSAGES_ATTRIBUTE_NAME;
/**
* Attribute name to set exception code in request scope.
*/
private String exceptionCodeAttribute = "exceptionCode";
/**
* Header name to set exception code in response header.
*/
private String exceptionCodeHeader = "X-Exception-Code";
/**
* Exception code resolution object.
*/
private ExceptionCodeResolver exceptionCodeResolver = new SimpleMappingExceptionCodeResolver();
/**
* Sets the value for exception Code Attribute name.
* <p>
* This value is used as the attribute name to set exception code in request scope and {@code FlashMap}. Calling this method
* overwrites the default value {@code "exceptionCode"}. <br>
* If {@code null} or blank or space is set, then exception code will not be set in request scope and {@code FlashMap} when
* {@link #setExceptionCode(Exception, HttpServletRequest, HttpServletResponse)} is called.
* </p>
* @param exceptionCodeAttribute Attribute name of the exception code to be set in request scope and {@code FlashMap}.
*/
public void setExceptionCodeAttribute(String exceptionCodeAttribute) {
this.exceptionCodeAttribute = exceptionCodeAttribute;
}
/**
* Sets the header name to set exception code in the response header.
* <p>
* Calling this method overwrites the default value {@code "X-Exception-Code"}. <br>
* If {@code null} or blank or space is set, then exception code will not be set in the response header when
* {@link #setExceptionCode(Exception, HttpServletRequest, HttpServletResponse)} is called..
* </p>
* @param exceptionCodeHeader Attribute name of the exception code to be set in the response header.
*/
public void setExceptionCodeHeader(String exceptionCodeHeader) {
this.exceptionCodeHeader = exceptionCodeHeader;
}
/**
* Sets the attribute name used for storing result message in request scope and {@code FlashMap}.
* <p>
* Calling this method overwrites the default value {@code "resultMessages"}. <br>
* If {@code null} or blank or space is set, then {@code ResultMessages} will not be set in request scope and
* {@code FlashMap} when {@link #setResultMessages(Exception, HttpServletRequest)} is called.
* </p>
* @param resultMessagesAttribute Attribute name used for storing result message in request scope and {@code FlashMap}.
*/
public void setResultMessagesAttribute(String resultMessagesAttribute) {
this.resultMessagesAttribute = resultMessagesAttribute;
}
/**
* Sets the object for resolving exception code.
* <p>
* If not set, exception code will not be set in request scope and response header when
* {@link #setExceptionCode(Exception, HttpServletRequest, HttpServletResponse)} is called.
* </p>
* @param exceptionCodeResolver Exception code resolution object.
*/
public void setExceptionCodeResolver(
ExceptionCodeResolver exceptionCodeResolver) {
this.exceptionCodeResolver = exceptionCodeResolver;
}
/**
* Performs exception handling.
* <p>
* Decides the View and resolves the Model necessary for display of View.
* </p>
* @param request {@link HttpServletRequest}
* @param response {@link HttpServletResponse}
* @param handler Request handler
* @param ex Exception
* @see org.springframework.web.servlet.handler.SimpleMappingExceptionResolver#doResolveException(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
*/
@Override
protected ModelAndView doResolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = super.doResolveException(request, response,
handler, ex);
if (modelAndView == null) {
return modelAndView;
}
setExceptionInfo(ex, request, response);
return modelAndView;
}
/**
* Sets the exception information
* <p>
* Sets exception information in {@code HttpServletRequest} and {@code HttpServletResponse}.
* </p>
* @param ex Exception
* @param request {@link HttpServletRequest}
* @param response {@link HttpServletResponse}
*/
protected void setExceptionInfo(Exception ex, HttpServletRequest request,
HttpServletResponse response) {
setExceptionCode(ex, request, response);
setResultMessages(ex, request);
}
/**
* Sets exception code in {@code HttpServletRequest} and {@code HttpServletResponse} header.
* <p>
* Sets exception code in {@code HttpServletRequest} and {@code HttpServletResponse} header. If exceptionCodeAttribute is
* {@code null} or blank or space is set, then exception code is not set.
* </p>
* @param ex Exception
* @param request {@link HttpServletRequest}
* @param response {@link HttpServletResponse}
*/
protected void setExceptionCode(Exception ex, HttpServletRequest request,
HttpServletResponse response) {
String exceptionCode = null;
if (exceptionCodeResolver != null
&& (StringUtils.hasText(exceptionCodeAttribute) || StringUtils
.hasText(exceptionCodeHeader))) {
exceptionCode = exceptionCodeResolver.resolveExceptionCode(ex);
}
if (exceptionCode == null) {
return;
}
if (StringUtils.hasText(exceptionCodeAttribute)) {
request.setAttribute(exceptionCodeAttribute, exceptionCode);
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
if (flashMap != null) {
flashMap.put(exceptionCodeAttribute, exceptionCode);
}
}
if (StringUtils.hasText(exceptionCodeHeader)) {
response.setHeader(exceptionCodeHeader, exceptionCode);
}
}
/**
* Sets result message
* <p>
* Sets result message in {@code HttpServletRequest}({@code FlashMap})
* </p>
* @param ex Exception
* @param request {@link HttpServletRequest}
*/
protected void setResultMessages(Exception ex, HttpServletRequest request) {
if (!StringUtils.hasText(resultMessagesAttribute)) {
return;
}
if (!(ex instanceof ResultMessagesNotificationException)) {
return;
}
ResultMessages resultMessages = ((ResultMessagesNotificationException) ex)
.getResultMessages();
request.setAttribute(resultMessagesAttribute, resultMessages);
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
if (flashMap != null) {
flashMap.put(resultMessagesAttribute, resultMessages);
}
}
}