package com.redblackit.web.server.mvc; import org.apache.log4j.*; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.spi.ErrorHandler; import org.apache.log4j.spi.Filter; import org.apache.log4j.spi.LoggingEvent; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.mock.web.MockServletConfig; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.StringReader; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Unit test class for {@link LoggingInterceptor}. * There is a separate (small) test class to test for correct treatment of null logger and servlet config. * * @author Dominic North */ @RunWith(Parameterized.class) public class LoggingInterceptorTest { public static final String LOGGER_NAME = "testLoggingInterceptor"; public static final String SERVLET_NAME = "test-servlet"; /** * Name parameter combinations */ public static final NameParameters[] NAME_PARAMETER_DATA = new NameParameters[]{ new NameParameters(LOGGER_NAME, null, "^"), new NameParameters(null, SERVLET_NAME, "^"), new NameParameters(LOGGER_NAME, SERVLET_NAME, "^" + SERVLET_NAME + " ") }; /** * Fixed lengths */ public static final Integer[] FIXED_MAX_LOGGED_BODY_LENGTHS = new Integer[]{null, Integer.MAX_VALUE, 0, 1, -1}; /** * Test data method */ @Parameterized.Parameters public static List<Object[]> testData() { final HttpHeaders requestHeaders0 = new HttpHeaders(); requestHeaders0.setContentType(MediaType.TEXT_PLAIN); requestHeaders0.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN)); final String schemeHttp = "http"; final String schemeHttps = "https"; final HttpHeaders responseHeaders0 = new HttpHeaders(); responseHeaders0.setContentType(MediaType.TEXT_PLAIN); final ModelAndView modelAndView0 = new ModelAndView("view0"); modelAndView0.addObject("attribute0", "attributeValue0"); /** * All name parameter combinations */ /** * Test parameter combinations */ RequestResponseParameters[] requestResponseParameterData = { new RequestResponseParameters(requestHeaders0, HttpMethod.GET.toString(), schemeHttp, "myhost.com", "8080", "context1", "servlet1", "path1", "entityId=id1&name=name1", "some content which is nice", HttpStatus.OK.value(), responseHeaders0, modelAndView0), new RequestResponseParameters(requestHeaders0, HttpMethod.GET.toString(), schemeHttps, "myhost.com", "8443", "context2", "servlet2", "path2/entities/id1/names/name1", null, "a little bit of content", 666, responseHeaders0, modelAndView0), new RequestResponseParameters(requestHeaders0, HttpMethod.PUT.toString(), schemeHttps, "myhost.com", "8443", "context2", "servlet2", "path2/entities/id1/names/name1", null, "a little bit of content", HttpStatus.NO_CONTENT.value(), responseHeaders0, null) }; final List<Object[]> parameterCombinations = new ArrayList<Object[]>(); for (NameParameters nameParameters : NAME_PARAMETER_DATA) { for (RequestResponseParameters requestResponseParameters : requestResponseParameterData) { for (Integer fixedMaxLoggedBodyLength : FIXED_MAX_LOGGED_BODY_LENGTHS) { Object[] testData = {nameParameters, requestResponseParameters, fixedMaxLoggedBodyLength}; parameterCombinations.add(testData); } if (requestResponseParameters.getRequestBody() != null && requestResponseParameters.getRequestBody().length() > 1) { Object[] testData = {nameParameters, requestResponseParameters, requestResponseParameters.getRequestBody().length() - 1}; parameterCombinations.add(testData); } } } return parameterCombinations; } /** * LoggingInterceptor under test */ private LoggingInterceptor loggingInterceptor; /** * Logger */ private Logger logger; /** * Appender (Mock) */ private TestAppender appender; /** * ServletConfig (mock) */ private ServletConfig servletConfig; /** * HttpServletRequest (Mock) */ private HttpServletRequest request; /** * HttpServletRequest (Mock) */ private HttpServletResponse response; /** * Dummy handler (not called) */ private TestController handler; /** * Name combination parameters */ private final NameParameters nameParameters; /** * Request/Response parameters */ private final RequestResponseParameters requestResponseParameters; /** * Maximum logged body length parameter */ private final Integer maxLoggedBodyLength; /** * Expected maxLoggedBodyLength in interceptor */ private final int expectedMaxLoggedBodyLength; /** * Constructor taking test parameters * * @param nameParameters * @param requestResponseParameters * @param maxLoggedBodyLength */ public LoggingInterceptorTest(NameParameters nameParameters, RequestResponseParameters requestResponseParameters, Integer maxLoggedBodyLength) { this.nameParameters = nameParameters; this.requestResponseParameters = requestResponseParameters; this.maxLoggedBodyLength = maxLoggedBodyLength; if (maxLoggedBodyLength == null || maxLoggedBodyLength.intValue() < 0) { expectedMaxLoggedBodyLength = Integer.MAX_VALUE; } else { expectedMaxLoggedBodyLength = maxLoggedBodyLength.intValue(); } } /** * Set up interceptor with logger, using our appender. */ @Before public void setupInterceptor() throws Exception { loggingInterceptor = new LoggingInterceptor(); String expectedLoggerName = null; if (nameParameters.getLoggerName() != null) { expectedLoggerName = nameParameters.getLoggerName(); loggingInterceptor.setLoggerName(nameParameters.getLoggerName()); } if (nameParameters.getServletName() != null) { if (nameParameters.getLoggerName() == null) { expectedLoggerName = nameParameters.getServletName(); } servletConfig = new MockServletConfig(nameParameters.getServletName()); } Assert.assertNotNull(expectedLoggerName); loggingInterceptor.initializeServletName(servletConfig); loggingInterceptor.afterPropertiesSet(); if (maxLoggedBodyLength != null) { loggingInterceptor.setMaxLoggedBodyLength(maxLoggedBodyLength.intValue()); } request = EasyMock.createMock(HttpServletRequest.class); response = EasyMock.createMock(HttpServletResponse.class); appender = new TestAppender(); logger = Logger.getLogger(expectedLoggerName); logger.addAppender(appender); handler = new TestController(); } /** * Ensure maxBodyLength has been set correctly */ @Test public void testMaxLoggedBodyLengthSet() { Assert.assertEquals(assertMsg("maxLoggedBodyLength"), expectedMaxLoggedBodyLength, loggingInterceptor.getMaxLoggedBodyLength()); } /** * Test preHandle logging with no override level, logger set to DEBUG */ @Test public void testPreHandleLogDEBUG() throws Exception { logger.setLevel(Level.DEBUG); verifyPreHandleNoLogging(); } /** * Test preHandle logging with explicit set override level DEBUG, logger set to DEBUG, unlimited max length */ @Test public void testPreHandleLogDEBUGOverrideDEBUG() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.setOverrideLevel(Level.DEBUG); verifyPreHandleWithLogging(); } /** * Test preHandle logging with forceloggingAtEffectiveLevel, logger set to DEBUG, unlimited max length */ @Test public void testPreHandleLogDEBUGForceLogging() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.forceLoggingAtEffectiveLevel(); verifyPreHandleWithLogging(); } /** * Test postHandle logging with no override level, logger set to DEBUG */ @Test public void testPostHandleLogDEBUG() throws Exception { logger.setLevel(Level.DEBUG); verifyPostHandleNoLogging(); } /** * Test postHandle logging with explicit set override level DEBUG, logger set to DEBUG, unlimited max length */ @Test public void testPostHandleLogDEBUGOverrideDEBUG() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.setOverrideLevel(Level.DEBUG); verifyPostHandleWithLogging(); } /** * Test postHandle logging with forceloggingAtEffectiveLevel, logger set to DEBUG, unlimited max length */ @Test public void testPostHandleLogDEBUGForceLogging() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.forceLoggingAtEffectiveLevel(); verifyPostHandleWithLogging(); } /** * Test afterCompletion logging with no override level, logger set to DEBUG */ @Test public void testAfterCompletionNoExceptionLogDEBUG() throws Exception { logger.setLevel(Level.DEBUG); verifyAfterCompletionNoExceptionNoLogging(); } /** * Test afterCompletion logging with no override level, logger set to DEBUG */ @Test public void testAfterCompletionWithExceptionLogDEBUG() throws Exception { logger.setLevel(Level.DEBUG); verifyAfterCompletionWithExceptionNoLogging(); } /** * Test afterCompletion logging with explicit set override level DEBUG, logger set to DEBUG, unlimited max length, no exception */ @Test public void testAfterCompletionNoExceptionLogDEBUGOverrideDEBUG() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.setOverrideLevel(Level.DEBUG); verifyAfterCompletionWithLogging(null); } /** * Test afterCompletion logging with forceloggingAtEffectiveLevel, logger set to DEBUG, unlimited max length, no exception */ @Test public void testAfterCompletionNoExceptionLogDEBUGForceLogging() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.forceLoggingAtEffectiveLevel(); verifyAfterCompletionWithLogging(null); } /** * Test afterCompletion logging with explicit set override level DEBUG, logger set to DEBUG, unlimited max length, with exception */ @Test public void testAfterCompletionWithExceptionLogDEBUGOverrideDEBUG() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.setOverrideLevel(Level.DEBUG); verifyAfterCompletionWithLogging(new IllegalStateException("test message 1")); } /** * Test afterCompletion logging with forceloggingAtEffectiveLevel, logger set to DEBUG, unlimited max length, with exception */ @Test public void testAfterCompletionWithExceptionLogDEBUGForceLogging() throws Exception { logger.setLevel(Level.DEBUG); loggingInterceptor.forceLoggingAtEffectiveLevel(); verifyAfterCompletionWithLogging(new RuntimeException("test message 2", new IllegalArgumentException("test message 3"))); } /** * Helper to run test base on supplied parameters for preHandle when no logging expected */ protected void verifyPreHandleNoLogging() throws Exception { startTestNoLogging(); boolean preHandleRet = loggingInterceptor.preHandle(request, response, handler); Assert.assertTrue("preHandle should return true", preHandleRet); EasyMock.verify(request, response); } /** * Helper to run test base on supplied parameters for preHandle when logging should occur */ protected void verifyPreHandleWithLogging() throws Exception { final StringBuffer url = startTestWithLogging(); final int bodyLength = requestResponseParameters.getRequestBody().length(); EasyMock.expect(request.getContentLength()).andReturn(bodyLength); EasyMock.expect(request.getContextPath()).andReturn(requestResponseParameters.getContext()); EasyMock.expect(request.getServletPath()).andReturn(requestResponseParameters.getServlet()); EasyMock.expect(request.getPathInfo()).andReturn(requestResponseParameters.getHandlerPath()); Enumeration<String> headerNames = Collections.enumeration(requestResponseParameters.getRequestHeaders().keySet()); EasyMock.expect(request.getHeaderNames()).andReturn(headerNames); for (String header : requestResponseParameters.getRequestHeaders().keySet()) { EasyMock.expect(request.getHeaders(header)) .andReturn(Collections.enumeration(requestResponseParameters.getRequestHeaders().get(header))); } final int expectedBodyLength = Math.min(expectedMaxLoggedBodyLength, bodyLength); if (expectedBodyLength > 0) { EasyMock.expect(request.getReader()).andReturn(new BufferedReader(new StringReader(requestResponseParameters.getRequestBody()))); } EasyMock.replay(request, response); boolean preHandleRet = loggingInterceptor.preHandle(request, response, handler); Assert.assertTrue("preHandle should return true", preHandleRet); String logMessage = verifyLogRequestUrl(url, "preHandle"); assertMsgMatches(logMessage, "handler", handler, "^ handler=", "$"); assertMsgMatches(logMessage, "contextPath", requestResponseParameters.getContext(), "^ contextPath=", "$"); assertMsgMatches(logMessage, "servletPath", requestResponseParameters.getServlet(), "^ servletPath=", "$"); assertMsgMatches(logMessage, "handlerPath", requestResponseParameters.getHandlerPath(), "^ handlerPath=", "$"); verifyLoggedHeaders(logMessage, "^ request ", requestResponseParameters.getRequestHeaders()); StringBuilder bodyRegexPfx = new StringBuilder("^ body ").append(Pattern.quote("(")); StringBuilder bodyRegexSfx = new StringBuilder(" chars"); if (expectedBodyLength == 0) { bodyRegexSfx.append(", omitted"); } else if (bodyLength > expectedBodyLength) { bodyRegexSfx.append(", truncated to ").append(expectedBodyLength); } bodyRegexSfx.append(Pattern.quote(")")).append("$"); assertMsgMatches(logMessage, "body heading", Integer.valueOf(bodyLength), bodyRegexPfx.toString(), bodyRegexSfx.toString()); if (expectedBodyLength > 0) { assertMsgMatches(logMessage, "body", requestResponseParameters.getRequestBody().substring(0, expectedBodyLength), "^==>\n", "\n<==$"); } EasyMock.verify(request, response); } /** * Helper to run test base on supplied parameters for postHandle when no logging expected */ protected void verifyPostHandleNoLogging() throws Exception { startTestNoLogging(); loggingInterceptor.postHandle(request, response, handler, requestResponseParameters.getModelAndView()); EasyMock.verify(request, response); } /** * Helper to run test base on supplied parameters for postHandle when logging should occur */ protected void verifyPostHandleWithLogging() throws Exception { final StringBuffer url = startResponseTestWithLogging(); loggingInterceptor.postHandle(request, response, handler, requestResponseParameters.getModelAndView()); String logMessage = verifyLogRequestUrl(url, "postHandle response to"); verifyLoggedResponseContent(logMessage); EasyMock.verify(request, response); } /** * Helper to run test base on supplied parameters for afterCompletion when no logging expected, and no exception provided */ protected void verifyAfterCompletionNoExceptionNoLogging() throws Exception { startTestNoLogging(); loggingInterceptor.afterCompletion(request, response, handler, null); EasyMock.verify(request, response); } /** * Helper to run test base on supplied parameters for afterCompletion when no logging expected, and an exception is provided */ protected void verifyAfterCompletionWithExceptionNoLogging() throws Exception { startTestNoLogging(); loggingInterceptor.afterCompletion(request, response, handler, new NullPointerException("test exception")); EasyMock.verify(request, response); } /** * Helper to run test base on supplied parameters for afterCompletion witgh supplied exception when logging should occur * * @param exception */ protected void verifyAfterCompletionWithLogging(Exception exception) throws Exception { final StringBuffer url = startResponseTestWithLogging(); loggingInterceptor.afterCompletion(request, response, handler, exception); String logMessage = verifyLogRequestUrl(url, "afterCompletion response to"); verifyLoggedResponseContent(logMessage); if (exception != null) { assertMsgMatches(logMessage, "exception", exception, "^ exception=", "$"); StackTraceElement[] stackTrace = exception.getStackTrace(); for (int i = 0; i < stackTrace.length; ++i) { assertMsgMatches(logMessage, "stackTrace[" + i + "]", stackTrace[i], "^\\s+", "$"); } } EasyMock.verify(request, response); } /** * Helper for starting tests on response * * @return */ protected StringBuffer startResponseTestWithLogging() { final StringBuffer url = startTestWithLogging(); EasyMock.expect(response.getStatus()).andReturn(requestResponseParameters.getStatus()); Set<String> headerNames = requestResponseParameters.getResponseHeaders().keySet(); EasyMock.expect(response.getHeaderNames()).andReturn(headerNames); for (String header : headerNames) { EasyMock.expect(response.getHeaders(header)) .andReturn(requestResponseParameters.getResponseHeaders().get(header)); } EasyMock.replay(request, response); return url; } /** * Helper to verify logging response content * * @param logMessage */ protected void verifyLoggedResponseContent(String logMessage) { final int statusInt = requestResponseParameters.getStatus(); StringBuilder statusReasonRegexSfx = new StringBuilder(' '); try { HttpStatus status = HttpStatus.valueOf(statusInt); statusReasonRegexSfx.append(' ').append(status.getReasonPhrase()); } catch (Throwable t) { statusReasonRegexSfx.append(" *** undefined status code (").append(t.getMessage()).append(')'); } assertMsgMatches(logMessage, "httpStatus", requestResponseParameters.getStatus(), "^ httpStatus=", Pattern.quote(statusReasonRegexSfx.toString()) + "$"); verifyLoggedHeaders(logMessage, "^ response ", requestResponseParameters.getResponseHeaders()); } /** * Common start to no logging tests */ protected void startTestNoLogging() { Assert.assertFalse(assertMsg("should not be able to log"), loggingInterceptor.isLoggingAtEffectiveLevel()); EasyMock.replay(request, response); } /** * Common start to test where logging should occur * * @return */ protected StringBuffer startTestWithLogging() { Assert.assertTrue(assertMsg("should be able to log"), loggingInterceptor.isLoggingAtEffectiveLevel()); final StringBuffer url = new StringBuffer(); url.append(requestResponseParameters.getScheme()).append("://") .append(requestResponseParameters.getHostname()).append(':').append(requestResponseParameters.getPort()) .append('/').append(requestResponseParameters.getContext()) .append('/').append(requestResponseParameters.getServlet()) .append('/').append(requestResponseParameters.getHandlerPath()); EasyMock.expect(request.getMethod()).andReturn(requestResponseParameters.getMethod()); EasyMock.expect(request.getRequestURL()).andReturn(url); EasyMock.expect(request.getQueryString()).andReturn(requestResponseParameters.getQueryString()); return url; } /** * Common assertions on request URL * * @param url StringBuffer * @param requestPrefix * @return full log message for remaining assertions */ protected String verifyLogRequestUrl(StringBuffer url, String requestPrefix) { List<LoggingEvent> loggedEvents = appender.getLoggingEvents(); Assert.assertEquals(assertMsg("one logging event should be added"), 1, loggedEvents.size()); String logMessage = loggedEvents.get(0).getMessage().toString(); assertMsgMatches(logMessage, "method", requestResponseParameters.getMethod(), nameParameters.getMethodRegexPrefix() + requestPrefix + " request: ", " http"); if (requestResponseParameters.getQueryString() == null) { assertMsgMatches(logMessage, "url", url, " ", "$"); } else { assertMsgMatches(logMessage, "url", url, " ", Pattern.quote("?")); assertMsgMatches(logMessage, "queryString", requestResponseParameters.getQueryString(), Pattern.quote("?"), "$"); } assertMsgMatches(logMessage, "handler", handler, "^ handler=", "$"); return logMessage; } /** * Helper verifying headers * * @param logMessage * @param specificHeaderHeadingPrefix * @param headers */ protected void verifyLoggedHeaders(String logMessage, String specificHeaderHeadingPrefix, HttpHeaders headers) { assertMsgMatches(logMessage, "headers heading", "", specificHeaderHeadingPrefix + "headers:", "$"); for (String header : headers.keySet()) { List<String> headerValue = headers.get(header); final String headerUC = header.toUpperCase(); assertMsgMatches(logMessage, "requestHeaders[" + headerUC + "]", headerValue, "^ " + headerUC + "=", "$"); } } /** * Assert message content matches regex * * @param logMessage * @param regexPfx * @param content * @param regexSfx * @return offset after match */ protected void assertMsgMatches(String logMessage, String contentName, Object content, String regexPfx, String regexSfx) { StringBuilder sb = new StringBuilder(regexPfx).append(Pattern.quote(content.toString())).append(regexSfx); final String regex = sb.toString(); final Matcher matcher = Pattern.compile(regex, Pattern.CASE_INSENSITIVE + Pattern.MULTILINE).matcher(logMessage); sb = new StringBuilder(contentName).append('=').append(content) .append(":message '").append(logMessage) .append("' should match regex '") .append(regex).append("'"); Assert.assertTrue(assertMsg(sb.toString()), matcher.find()); } /** * Helper to create assertMsg */ protected String assertMsg(String message) { final StringBuilder msgsb = new StringBuilder(message); msgsb.append("\n loggingInterceptor=").append(loggingInterceptor); msgsb.append("\n nameParameters=").append(nameParameters); msgsb.append("\n requestResponseParameters=").append(requestResponseParameters); msgsb.append("\n maxLoggedBodyLength=").append(maxLoggedBodyLength); return msgsb.toString(); } /** * Stub appender (equals not there for logging events etc) */ protected class TestAppender implements Appender { /** * Name */ private String name; /** * LoggingEvent last appended */ private List<LoggingEvent> loggingEvents = new ArrayList<LoggingEvent>(); /** * Add a filter to the end of the filter list. * * @since 0.9.0 */ @Override public void addFilter(Filter newFilter) { throw new UnsupportedOperationException("filter=" + newFilter); } /** * Returns the head Filter. The Filters are organized in a linked list * and so all Filters on this Appender are available through the result. * * @return the head Filter or null, if no Filters are present * @since 1.1 */ @Override public Filter getFilter() { return null; //To change body of implemented methods use File | Settings | File Templates. } /** * Clear the list of filters by removing all the filters in it. * * @since 0.9.0 */ @Override public void clearFilters() { //To change body of implemented methods use File | Settings | File Templates. } /** * Release any resources allocated within the appender such as file * handles, network connections, etc. * <p/> * <p>It is a programming error to append to a closed appender. * * @since 0.8.4 */ @Override public void close() { loggingEvents.clear(); } /** * Log in <code>Appender</code> specific way. When appropriate, * Loggers will call the <code>doAppend</code> method of appender * implementations in order to log. */ @Override public void doAppend(LoggingEvent event) { loggingEvents.add(event); } /** * Get the name of this appender. * * @return name, may be null. */ @Override public String getName() { return name; //To change body of implemented methods use File | Settings | File Templates. } /** * Set the {@link org.apache.log4j.spi.ErrorHandler} for this appender. * * @since 0.9.0 */ @Override public void setErrorHandler(ErrorHandler errorHandler) { //To change body of implemented methods use File | Settings | File Templates. } /** * Returns the {@link org.apache.log4j.spi.ErrorHandler} for this appender. * * @since 1.1 */ @Override public ErrorHandler getErrorHandler() { return null; //To change body of implemented methods use File | Settings | File Templates. } /** * Set the {@link org.apache.log4j.Layout} for this appender. * * @since 0.8.1 */ @Override public void setLayout(Layout layout) { //To change body of implemented methods use File | Settings | File Templates. } /** * Returns this appenders layout. * * @since 1.1 */ @Override public Layout getLayout() { return null; //To change body of implemented methods use File | Settings | File Templates. } /** * Set the name of this appender. The name is used by other * components to identify this appender. * * @since 0.8.1 */ @Override public void setName(String name) { this.name = name; } /** * Configurators call this method to determine if the appender * requires a layout. If this method returns <code>true</code>, * meaning that layout is required, then the configurator will * configure an layout using the configuration information at its * disposal. If this method returns <code>false</code>, meaning that * a layout is not required, then layout configuration will be * skipped even if there is available layout configuration * information at the disposal of the configurator.. * <p/> * <p>In the rather exceptional case, where the appender * implementation admits a layout but can also work without it, then * the appender should return <code>true</code>. * * @since 0.8.4 */ @Override public boolean requiresLayout() { return false; //To change body of implemented methods use File | Settings | File Templates. } /** * Get our events * * @return event list */ public List<LoggingEvent> getLoggingEvents() { return loggingEvents; } } /** * Parameter class for logger name and servlet name combinations */ protected static class NameParameters { private final String loggerName; private final String servletName; private final String methodRegexPrefix; /** * Constructor taking all parameters * * @param loggerName * @param servletName * @param methodRegexPrefix */ public NameParameters(String loggerName, String servletName, String methodRegexPrefix) { this.loggerName = loggerName; this.servletName = servletName; this.methodRegexPrefix = methodRegexPrefix; } public String getLoggerName() { return loggerName; } public String getServletName() { return servletName; } public String getMethodRegexPrefix() { return methodRegexPrefix; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("NameParameters"); sb.append("{loggerName='").append(loggerName).append('\''); sb.append(", servletName='").append(servletName).append('\''); sb.append(", methodRegexPrefix='").append(methodRegexPrefix).append('\''); sb.append('}'); return sb.toString(); } } /** * Parameter class for request and response content */ protected static class RequestResponseParameters { private final HttpHeaders requestHeaders; private final String method; private final String scheme; private final String hostname; private final String port; private final String context; private final String servlet; private final String handlerPath; private final String queryString; private final String requestBody; private final int status; private final HttpHeaders responseHeaders; private final ModelAndView modelAndView; /** * @param requestHeaders * @param method * @param scheme * @param hostname * @param port * @param context * @param servlet * @param handlerPath * @param queryString * @param requestBody * @param status * @param responseHeaders * @param modelAndView */ public RequestResponseParameters(HttpHeaders requestHeaders, String method, String scheme, String hostname, String port, String context, String servlet, String handlerPath, String queryString, String requestBody, int status, HttpHeaders responseHeaders, ModelAndView modelAndView) { this.method = method; this.scheme = scheme; this.hostname = hostname; this.port = port; this.context = context; this.servlet = servlet; this.handlerPath = handlerPath; this.queryString = queryString; this.requestBody = requestBody; this.status = status; this.requestHeaders = new HttpHeaders(); for (String header : requestHeaders.keySet()) { this.requestHeaders.put(header, requestHeaders.get(header)); } if (requestBody == null) { this.requestHeaders.setContentLength(0); } else { this.requestHeaders.setContentLength(requestBody.length()); } this.responseHeaders = new HttpHeaders(); for (String header : responseHeaders.keySet()) { this.responseHeaders.put(header, responseHeaders.get(header)); } if (modelAndView == null) { this.modelAndView = null; } else { this.modelAndView = new ModelAndView(modelAndView.getViewName()); this.modelAndView.addAllObjects(modelAndView.getModel()); } } public HttpHeaders getRequestHeaders() { return requestHeaders; } public String getMethod() { return method; } public String getScheme() { return scheme; } public String getHostname() { return hostname; } public String getPort() { return port; } public String getContext() { return context; } public String getServlet() { return servlet; } public String getHandlerPath() { return handlerPath; } public String getQueryString() { return queryString; } public String getRequestBody() { return requestBody; } public int getStatus() { return status; } public HttpHeaders getResponseHeaders() { return responseHeaders; } public ModelAndView getModelAndView() { return modelAndView; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("RequestResponseParameters"); sb.append("{requestHeaders=").append(requestHeaders); sb.append(", method='").append(method).append('\''); sb.append(", scheme='").append(scheme).append('\''); sb.append(", hostname='").append(hostname).append('\''); sb.append(", port='").append(port).append('\''); sb.append(", context='").append(context).append('\''); sb.append(", servlet='").append(servlet).append('\''); sb.append(", handlerPath='").append(handlerPath).append('\''); sb.append(", queryString='").append(queryString).append('\''); sb.append(", requestBody='").append(requestBody).append('\''); sb.append(", status='").append(status).append('\''); sb.append(", responseHeaders=").append(responseHeaders); sb.append(", modelAndView=").append(modelAndView); sb.append('}'); return sb.toString(); } } /** * Test controller for handler */ @Controller protected class TestController { /** * test method */ @RequestMapping("/test") public String testMethod(Model model) { return "view0"; } } }