org.opentestsystem.shared.docs.RequestLoggingInterceptor.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.shared.docs.RequestLoggingInterceptor.java

Source

/*******************************************************************************
 * 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;
    }
}