Java tutorial
/* * Copyright (C) 2016 KnowledgeNet. * * 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. */ /* * Modified by KnowledgeNet Inc. * <li>Ver.1.0 2016/02/14 ??(Shape-Up)</li> */ package org.kmnet.com.fw.web.exception; import java.util.HashSet; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.kmnet.com.fw.common.exception.ExceptionLogger; import org.kmnet.com.fw.common.exception.ResultMessagesNotificationException; import org.kmnet.com.fw.common.exception.SystemException; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.web.servlet.HandlerExceptionResolver; /** * Interceptor class for logging exceptions which are handled by {@link HandlerExceptionResolver}. * <p> * In this class, log level is changed as per the HTTP response code determined by {@code HandlerExceptionResolver}. * </p> * <p> * <h2>Example of the Settings for inject a custom ExceptionLogger</h2><br> * <strong>[applicationContext.xml]</strong><br> * define bean of custom ExceptionLogger. * * <pre> * <bean id="exceptionLogger" class="org.kmnet.com.fw.common.exception.ExceptionLogger"> * <!-- ... --> * </bean> * </pre> * * <strong>[spring-mvc.xml]</strong><br> * inject bean of custom ExceptionLogger. * * <pre> * <bean id="handlerExceptionResolverLoggingInterceptor" * class="org.kmnet.com.fw.web.exception.HandlerExceptionResolverLoggingInterceptor"> * <property name="exceptionLogger" ref="exceptionLogger" /> * </bean> * </pre> * * </p> */ public class HandlerExceptionResolverLoggingInterceptor implements MethodInterceptor, InitializingBean { /** * Logger for output of application log. */ private static final Logger logger = LoggerFactory.getLogger(HandlerExceptionResolverLoggingInterceptor.class); /** * Logger object for exception output. */ private ExceptionLogger exceptionLogger = null; /** * Set of exception classes for which log output is not to be done. */ private Set<Class<? extends Exception>> ignoreExceptions; /** * Constructor */ public HandlerExceptionResolverLoggingInterceptor() { this.ignoreExceptions = new HashSet<Class<? extends Exception>>(); ignoreExceptions.add(ResultMessagesNotificationException.class); ignoreExceptions.add(SystemException.class); } /** * Sets Logger object for exception output. * <p> * If not set, default Logger object for exception output is used. <br> * </p> * @param exceptionLogger any exception logger. */ public void setExceptionLogger(ExceptionLogger exceptionLogger) { this.exceptionLogger = exceptionLogger; } /** * Sets 'Set' instance of exception classes for which log output is not to be used. * @param ignoreExceptions Set of exception classes for which log output is not to be done. */ public void setIgnoreExceptions(Set<Class<? extends Exception>> ignoreExceptions) { this.ignoreExceptions = ignoreExceptions; } /** * Log exceptions which are handled by {@link HandlerExceptionResolver} * <p> * [Output Specifications] * <ul> * <li>If {@code HandlerExceptionResolver} returns null, exception has not be handled and hence log will not be output</li> * <li>If {@code HandlerExceptionResolver} interface is not implemented, exception has not be handled and hence log will not * be output</li> * <li>If exception class matches with the list of classes for which log output is not to be done, then log output is not * done.</li> * <li>If HTTP response code by {@code HandlerExceptionResolver} is between 100-399 then INFO log, between 400-499 then WARN * log and above 500 ERROR log is output</li> * <li>If exception is handled by a class which is not in the list of {@link HandlerExceptionResolver} classes for WARN log * output, then output the log with ERROR level.</li> * <li></li> * </ul> * </p> * @param invocation {@link MethodInvocation} * @return Object returned by target method of interceptor * @throws Throwable If error occurred in target method of interceptor * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) */ @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object returnObj = invocation.proceed(); if (returnObj == null) { return returnObj; } Object targetObject = invocation.getThis(); if (!(targetObject instanceof HandlerExceptionResolver)) { if (logger.isWarnEnabled()) { logger.warn( "target object does not implement the HandlerExceptionResolver interface. target object is '{}'.", targetObject.getClass().getName()); } return returnObj; } Exception exception = (Exception) invocation.getArguments()[3]; if (isTargetException(exception)) { HttpServletRequest request = (HttpServletRequest) invocation.getArguments()[0]; HttpServletResponse response = (HttpServletResponse) invocation.getArguments()[1]; Object handler = invocation.getArguments()[2]; log(exception, request, response, handler); } return returnObj; } /** * Initializes the HandlerExceptionResolverLoggingInterceptor. * <p> * If exception logger object is not set, use {@link org.kmnet.com.fw.common.exception.ExceptionLogger}. * </p> * <p> * default exception logger's name is 'org.kmnet.com.fw.web.exception.HandlerExceptionResolverLoggingInterceptor'<br> * (this interceptor's class name). * </p> * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { if (exceptionLogger == null) { exceptionLogger = new ExceptionLogger(getClass().getName()); exceptionLogger.afterPropertiesSet(); } } /** * Determines if the exception class is in the list of classes for which log is to be output. * @param ex Exception * @return returns <code>true<code> if in the list. */ protected boolean isTargetException(Exception ex) { if (ignoreExceptions == null) { return true; } for (Class<? extends Exception> ignoreClass : ignoreExceptions) { if (ignoreClass.isInstance(ex)) { return false; } } return true; } /** * Outputs the log * @param ex Exception * @param request HTTP Servlet Request * @param response HTTP Servlet Response * @param handler handler */ protected void log(Exception ex, HttpServletRequest request, HttpServletResponse response, Object handler) { int statusCode = response.getStatus(); if (HttpServletResponse.SC_INTERNAL_SERVER_ERROR <= statusCode) { // responseCode is 500 ~ logServerError(ex, request, response, handler); return; } if (HttpServletResponse.SC_BAD_REQUEST <= statusCode) { // 400 ~ 499 logClientError(ex, request, response, handler); return; } if (HttpServletResponse.SC_MULTIPLE_CHOICES <= statusCode) { // 300 ~ 399 logRedirection(ex, request, response, handler); return; } if (HttpServletResponse.SC_OK <= statusCode) { // 200 ~ 299 logSuccess(ex, request, response, handler); return; } if (HttpServletResponse.SC_CONTINUE <= statusCode) { // 100 ~ 199 logInformational(ex, request, response, handler); return; } } /** * Outputs the log when HTTP status code is Informational (1xx). * <p> * Outputs INFO level log. * </p> * @param ex Exception * @param request HTTP Servlet request * @param response HTTP Servlet response * @param handler handler */ protected void logInformational(Exception ex, HttpServletRequest request, HttpServletResponse response, Object handler) { exceptionLogger.info(ex); } /** * Outputs the log when HTTP status code is Success (2xx) related. * <p> * Outputs INFO level log. * </p> * @param ex Exception * @param request HTTP Servlet request * @param response HTTP Servlet response * @param handler handler */ protected void logSuccess(Exception ex, HttpServletRequest request, HttpServletResponse response, Object handler) { exceptionLogger.info(ex); } /** * Outputs the log when HTTP status code is Redirectional (3xx). * <p> * Outputs INFO level of log. * </p> * @param ex Exception * @param request HTTP Servlet request * @param response HTTP Servlet response * @param handler handler */ protected void logRedirection(Exception ex, HttpServletRequest request, HttpServletResponse response, Object handler) { exceptionLogger.info(ex); } /** * Outputs the log when HTTP status code is Error (4xx) related. * <p> * Outputs WARN level of log. * </p> * @param ex Exception * @param request HTTP Servlet request * @param response HTTP Servlet response * @param handler handler */ protected void logClientError(Exception ex, HttpServletRequest request, HttpServletResponse response, Object handler) { exceptionLogger.warn(ex); } /** * Outputs the log when HTTP status code is Server Error (3xx). * <p> * Outputs Error level of log. * </p> * @param ex Exception * @param request HTTP Servlet request * @param response HTTP Servlet response * @param handler handler */ protected void logServerError(Exception ex, HttpServletRequest request, HttpServletResponse response, Object handler) { exceptionLogger.error(ex); } /** * Fetches logger object for logging exception * @return logger object */ protected ExceptionLogger getExceptionLogger() { return exceptionLogger; } }