/*
* Copyright 2002-2011 the original author or authors.
*
* 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.springframework.test.web.server.matcher;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.server.MvcResultMatcher;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
public class LoggingMatcher implements MvcResultMatcher {
private static final Log logger = LogFactory.getLog(LoggingMatcher.class);
public void match(MockHttpServletRequest request,
MockHttpServletResponse response,
Object handler,
Exception handlerException,
ModelAndView mav) {
StringBuilder sb = new StringBuilder();
appendRequest(sb, request);
appendHandler(sb, handler, handlerException);
appendModelAndView(sb, mav);
appendResponse(sb, response);
logger.info(sb.toString());
}
private void appendRequest(StringBuilder sb, MockHttpServletRequest request) {
sb.append("\n\n" + request.getMethod() + " " + request.getRequestURI() + "\n");
appendLabelAndValue(sb, "Params", request.getParameterMap());
appendLabelAndValue(sb, "Headers", MockRequestMatchers.getHeaderValueMap(request));
}
private void appendHandler(StringBuilder sb, Object handler, Exception handlerException) {
if (handler == null) {
sb.append("\nSelected Handler: null\n");
return;
}
sb.append("\nSelected Handler:\n");
if (!HandlerMethod.class.isInstance(handler)) {
appendLabelAndValue(sb, "Type", handler.getClass().getName());
appendLabelAndValue(sb, "Method", "Not available");
}
else {
HandlerMethod hm = (HandlerMethod) handler;
appendLabelAndValue(sb, "Type", hm.getBeanType().getName());
appendLabel(sb, "Method");
sb.append(hm.getReturnType().getParameterType().getSimpleName());
sb.append(" " + hm.getMethod().getName() + "(");
for (int i = 0; i < hm.getMethod().getParameterTypes().length; i++) {
if (i != 0) {
sb.append(", ");
}
sb.append(hm.getMethod().getParameterTypes()[i].getSimpleName());
}
sb.append(") \n");
}
if (handlerException == null) {
sb.append("\nHandler Exception Raised: none\n");
}
else {
sb.append("\nHandler Exception Raised:\n" + handlerException + "\n");
}
}
private void appendLabel(StringBuilder sb, String label) {
for (int i = 0; i < (17 - label.length()); i++) {
sb.append(" ");
}
sb.append(label + ": ");
}
private void appendLabelAndValue(StringBuilder sb, String label, Object value) {
appendLabel(sb, label);
sb.append(value + "\n");
}
private void appendModelAndView(StringBuilder sb, ModelAndView mav) {
sb.append("\nModelAndView: ");
if (mav != null) {
sb.append("\n");
appendView(sb, mav);
appendModel(sb, mav.getModel());
}
else {
sb.append("null\n");
}
}
private void appendView(StringBuilder sb, ModelAndView mav) {
Assert.notNull(mav);
if (mav.isReference()) {
appendLabelAndValue(sb, "View name", "\"" + mav.getViewName() + "\"");
}
else {
appendLabelAndValue(sb, "View", mav.getView());
}
}
private void appendModel(StringBuilder sb, Map<String, Object> model) {
if (model.size() == 0) {
appendLabelAndValue(sb, "Attributes", "none");
sb.append("none");
return;
}
for (String name : model.keySet()) {
if (!name.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
Object value = model.get(name);
Errors errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + name);
if (errors == null) {
appendLabelAndValue(sb, "Attribute", name);
}
else {
appendLabelAndValue(sb, "Attribute", name + " has " + errors.getErrorCount() + " errors");
}
if (logger.isTraceEnabled()) {
appendLabelAndValue(sb, "value", value);
if (errors != null) {
appendLabelAndValue(sb, "errors", errors.getAllErrors());
}
}
}
}
}
private void appendResponse(StringBuilder sb, MockHttpServletResponse response) {
sb.append("\nResponse:\n");
appendLabelAndValue(sb, "status", response.getStatus());
appendLabelAndValue(sb, "error message", response.getErrorMessage());
appendLabelAndValue(sb, "headers", MockResponseMatchers.getHeaderValueMap(response));
appendLabelAndValue(sb, "content type", response.getContentType());
appendResponseBody(sb, response);
appendLabelAndValue(sb, "forwarded URL", response.getForwardedUrl());
appendLabelAndValue(sb, "redirected URL", response.getRedirectedUrl());
appendLabelAndValue(sb, "included URLs", response.getIncludedUrls());
appendLabelAndValue(sb, "cookies", MockResponseMatchers.getCookieValueMap(response));
sb.append("\n");
}
private void appendResponseBody(StringBuilder sb, MockHttpServletResponse response) {
String content;
try {
content = response.getContentAsString();
} catch (UnsupportedEncodingException e) {
String message = "Failed to get the response content: ";
content = message + e.toString();
logger.error(message, e);
}
if (content != null) {
int length = content.length();
if (length > 50) {
content = content.substring(0, 50);
appendLabelAndValue(sb, "response body", "[" + content + "] <trunkated> (50 of " + " " + length + " chars)");
}
else {
appendLabelAndValue(sb, "response body", "[" + content + "]");
}
}
}
}