Java tutorial
/******************************************************************************* * Educational Online Test Delivery System * Copyright (c) 2013 American Institutes for Research * * Distributed under the AIR Open Source License, Version 1.0 * See accompanying file AIR-License-1_0.txt or at * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf ******************************************************************************/ package org.opentestsystem.shared.docs; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpStatus; import org.opentestsystem.shared.docs.annotation.ApiDocExample; import org.opentestsystem.shared.docs.domain.ApiExample; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.http.HttpMethod; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Joiner; @SuppressWarnings({ "PMD.VariableNamingConventions", "PMD.SuspiciousConstantFieldName", "PMD.NullAssignment" }) public class RequestLoggingInterceptor implements HandlerInterceptor { private static File API_EXAMPLE_FILE; private static final Logger LOGGER = LoggerFactory.getLogger(RequestLoggingInterceptor.class); private static final int ZERO = 0; static { String path = "uneditedPath"; try { LOGGER.warn("the path starts as: " + path); path = new ClassPathResource(".").getFile().getAbsolutePath() + "/api_examples.json"; LOGGER.warn("attempting to write file to: " + path); API_EXAMPLE_FILE = new File(path); if (API_EXAMPLE_FILE.exists()) { API_EXAMPLE_FILE.delete(); } API_EXAMPLE_FILE.createNewFile(); } catch (IOException e) { LOGGER.error("unable to create api_example file: " + path, e); API_EXAMPLE_FILE = null; } } @Override public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception { // NOPMD return true; } @Override public void postHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final ModelAndView modelAndView) throws Exception { // NOPMD } @Override public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final Exception ex) throws Exception { // NOPMD FileOutputStream fileOut = null; try { LOGGER.debug(" "); LOGGER.debug(" "); LOGGER.debug("Request "); int rank = getRankOfApiDoc(); // if rank is -1 skip it: that's the way to hide a api doc. Also exclude negative security testing if (rank >= ZERO && response.getStatus() != HttpStatus.SC_UNAUTHORIZED) { // block pmd concurrent hashmap warning ApiExample example = new ApiExample(); example.setApiDocRank(rank); example.setRequestMethod(HttpMethod.valueOf(request.getMethod())); example.setRequestContentType(request.getContentType()); example.setRequestUri(request.getRequestURI()); String reqQueryString = request.getQueryString(); //grab the parameters off the request instead if (StringUtils.isBlank(reqQueryString)) { if (request.getParameterMap() != null) { List<String> params = new ArrayList<String>(); for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) { String temp = entry.getKey() + "="; if (entry.getValue() != null) { temp += Joiner.on(",").join(entry.getValue()); } params.add(temp); } reqQueryString = Joiner.on("&").join(params.toArray()); } } example.setRequestQueryString(reqQueryString); LOGGER.debug(example.toString()); InputStream instream = request.getInputStream(); String requestData = ""; if (instream != null) { StringWriter writer = new StringWriter(); IOUtils.copy(instream, writer, "UTF-8"); requestData = writer.toString(); } example.setRequestData(requestData); LOGGER.debug("request data :" + example.getRequestData()); LOGGER.debug(" "); LOGGER.debug("Response "); MockHttpServletResponse res = (MockHttpServletResponse) response; example.setResponseContent(res.getContentAsString()); example.setResponseCode(res.getStatus()); LOGGER.debug("Server Response:" + example.getResponseContent()); LOGGER.debug(" "); LOGGER.debug(" "); if (API_EXAMPLE_FILE != null) { fileOut = new FileOutputStream(API_EXAMPLE_FILE, true); ObjectMapper mapper = new ObjectMapper(); byte[] bytes = mapper.writeValueAsBytes(example); fileOut.write(bytes); String str = ","; fileOut.write(str.getBytes()); fileOut.close(); } } } finally { if (fileOut != null) { fileOut.close(); } } } /** * NOTE: this is a brittle example of walking up the stack to find * an annotated method to determine how to treat the API doc captured in this * Intercepter. The use of annotations provides a lightweight mechanism of doing just that. * * @return the rank if found (or the ApiDocExample.DEFAULT_RANK if not) */ private int getRankOfApiDoc() { StackTraceElement[] stack = Thread.currentThread().getStackTrace(); // default to DEFAULT_RANK which will capture the doc, but put it at the bottom if no annotation is found. int rank = ApiDocExample.DEFAULT_RANK; // loop up the stack to find the annotation for (int i = 0; i < stack.length; i++) { StackTraceElement ste = stack[i]; // shortcut up the stack: once we get to the MocMvc call, we're in business: start interrogating the methods if (ste.getClassName().equals(MockMvc.class.getName())) { for (int j = i; j < stack.length; j++) { StackTraceElement theOne = stack[j]; try { Class<?> clazz = Class.forName(theOne.getClassName()); // following JUnit convention, the root test will have no args Method theMethod = clazz.getMethod(theOne.getMethodName(), (Class[]) null); // find the ApiDocExample if it exists ApiDocExample example = theMethod.getAnnotation(ApiDocExample.class); if (example != null) { rank = example.rank(); // once we find an example annotation, break out of loops. break; } } catch (ClassNotFoundException | NoSuchMethodException e) { // getMethod failed to find a no arg method, continue down the stack. continue; } } break; } } return rank; } }