All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.erigir.wrench.ape.exception.ApeExceptionWriter Maven / Gradle / Ivy

There is a newer version: 2.2.16+16
Show newest version
package com.erigir.wrench.ape.exception;

import com.erigir.wrench.ape.http.ApeException;
import com.erigir.wrench.ape.model.ApeResponse;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.util.NestedServletException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.zip.GZIPOutputStream;

/**
 * Basically making this a seperate class so I can use it in both the filter and the exception handler
 * Created by chrweiss on 7/6/14.
 */
public class ApeExceptionWriter {
  private static final Logger LOG = LoggerFactory.getLogger(ApeExceptionWriter.class);
  private ObjectMapper objectMapper = createMapper();
  private String apiDocUrlPrefix;

  private ObjectMapper createMapper() {
    ObjectMapper rval = new ObjectMapper();
    rval.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    rval.configure(SerializationFeature.INDENT_OUTPUT, true);
    return rval;
  }

  public void writeExceptionToResponse(HttpServletRequest request, HttpServletResponse resp, Exception inEx) {
    try {
      Exception ex = preprocessException(inEx);


      LOG.debug("Handling failure to {}", request.getRequestURI(), ex);

      ApeException se = AnnotationUtils.findAnnotation(ex.getClass(), ApeException.class);

      ApeErrorData sed = null;
      if (se == null) {
        sed = new ApeErrorData(500, 100, "An unexpected error occurred", ex.getClass().getSimpleName(), apiDocUrlPrefix + 500100, ex.getLocalizedMessage());
      } else {
        Object details = (StringUtils.trimToNull(se.detailObjectPropertyName()) == null) ? null : safeGetProperty(ex, se.detailObjectPropertyName());
        sed = new ApeErrorData(se.httpStatusCode(), se.detailCode(), se.message(), se.developerMessage(), apiDocUrlPrefix + se.httpStatusCode() + se.detailCode(), details);
      }

      resp.setStatus(sed.getHttpStatusCode());
      resp.setContentType("application/json");

      // If gzip has already been set, use it
      OutputStream os = resp.getOutputStream();
      if ("gzip".equalsIgnoreCase(resp.getHeader("Content-Encoding"))) {
        os = new GZIPOutputStream(os);
      }

      objectMapper.writeValue(os, new ApeResponse(sed, sed.getHttpStatusCode()));
    } catch (Exception e) {
      LOG.error("Really bad!  Error when trying to write error", e);
    }
  }

  /**
   * Converts certain types of generic exceptions to more usable and secure ones
   *
   * @param input
   * @return
   */
  private Exception preprocessException(Exception input) {
    Exception rval = input;

    if (HttpMessageNotReadableException.class.isAssignableFrom(input.getClass()) && input.getCause() != null && JsonMappingException.class.isAssignableFrom(input.getCause().getClass())) {
      JsonMappingException jme = (JsonMappingException) input.getCause();
      rval = new BadJsonException(jme.getLocation());
      rval.initCause(input);
    }

    if (NestedServletException.class.isAssignableFrom(rval.getClass())) {
      LOG.debug("Unwrapping NestedServletException");
      rval = (Exception) ((NestedServletException) rval).getCause();
    }
    return rval;
  }

  private Object safeGetProperty(Object bean, String propName) {
    Object rval = null;
    if (bean != null && propName != null) {
      try {
        rval = PropertyUtils.getProperty(bean, propName);
      } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
        LOG.error("Invalid property name '{}' on bean of type '{}' ", propName, bean.getClass());
      }
    }
    return rval;
  }

  public void setApiDocUrlPrefix(String apiDocUrlPrefix) {
    this.apiDocUrlPrefix = apiDocUrlPrefix;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy