CommonResponseEntityExceptionHandler.java

  1. /*
  2.  * This file is part of Openrouteservice.
  3.  *
  4.  * Openrouteservice is free software; you can redistribute it and/or modify it under the terms of the
  5.  * GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1
  6.  * of the License, or (at your option) any later version.
  7.  *
  8.  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  9.  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10.  * See the GNU Lesser General Public License for more details.
  11.  *
  12.  * You should have received a copy of the GNU Lesser General Public License along with this library;
  13.  * if not, see <https://www.gnu.org/licenses/>.
  14.  */

  15. package org.heigit.ors.api.errors;

  16. import com.fasterxml.jackson.databind.exc.ValueInstantiationException;
  17. import org.apache.log4j.Logger;
  18. import org.heigit.ors.api.util.AppInfo;
  19. import org.heigit.ors.exceptions.ParameterValueException;
  20. import org.heigit.ors.exceptions.StatusCodeException;
  21. import org.heigit.ors.exceptions.UnknownParameterException;
  22. import org.heigit.ors.isochrones.IsochronesErrorCodes;
  23. import org.heigit.ors.util.DebugUtility;
  24. import org.json.simple.JSONObject;
  25. import org.springframework.http.HttpHeaders;
  26. import org.springframework.http.HttpStatus;
  27. import org.springframework.http.MediaType;
  28. import org.springframework.http.ResponseEntity;
  29. import org.springframework.web.bind.annotation.ControllerAdvice;
  30. import org.springframework.web.bind.annotation.RestController;
  31. import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

  32. @ControllerAdvice
  33. @RestController
  34. public class CommonResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
  35.     private static final String EXCEPTION_MESSAGE = "Exception";
  36.     private static final Logger LOCAL_LOGGER = Logger.getLogger(CommonResponseEntityExceptionHandler.class.getName());

  37.     final int errorCodeBase;

  38.     public CommonResponseEntityExceptionHandler() { // required for Tomcat
  39.         errorCodeBase = 0;
  40.     }

  41.     public CommonResponseEntityExceptionHandler(int errorCodeBase) {
  42.         this.errorCodeBase = errorCodeBase;
  43.     }

  44.     public ResponseEntity handleStatusCodeException(StatusCodeException exception) {
  45.         HttpHeaders headers = new HttpHeaders();
  46.         headers.setContentType(MediaType.APPLICATION_JSON);
  47.         logException(exception);
  48.         return new ResponseEntity(constructErrorBody(exception), headers, convertOrsToSpringHttpCode(exception.getStatusCode()));
  49.     }

  50.     public ResponseEntity handleUnknownParameterException(UnknownParameterException exception) {
  51.         HttpHeaders headers = new HttpHeaders();
  52.         headers.setContentType(MediaType.APPLICATION_JSON);
  53.         logException(exception);
  54.         return new ResponseEntity(constructErrorBody(exception), headers, convertOrsToSpringHttpCode(exception.getStatusCode()));
  55.     }

  56.     public ResponseEntity handleGenericException(Exception exception) {
  57.         HttpHeaders headers = new HttpHeaders();
  58.         headers.setContentType(MediaType.APPLICATION_JSON);
  59.         logException(exception);
  60.         Throwable cause = exception.getCause();
  61.         if (cause instanceof ValueInstantiationException e) {
  62.             if (e.getCause() instanceof StatusCodeException origExc) {
  63.                 return new ResponseEntity(constructErrorBody(origExc), headers, HttpStatus.BAD_REQUEST);
  64.             }
  65.             return new ResponseEntity(constructErrorBody(new ParameterValueException(IsochronesErrorCodes.INVALID_PARAMETER_VALUE, "")), headers, HttpStatus.BAD_REQUEST);
  66.         }
  67.         return new ResponseEntity(constructGenericErrorBody(exception), headers, HttpStatus.INTERNAL_SERVER_ERROR);
  68.     }

  69.     private void logException(Exception exception) {
  70.         if (DebugUtility.isDebug()) {
  71.             if (LOCAL_LOGGER.isDebugEnabled()) {
  72.                 // Log also the stack trace
  73.                 LOCAL_LOGGER.error(EXCEPTION_MESSAGE, exception);
  74.             } else {
  75.                 // Log only the error message
  76.                 LOCAL_LOGGER.error(exception);
  77.             }
  78.         }
  79.     }

  80.     private HttpStatus convertOrsToSpringHttpCode(int statusCode) {
  81.         return HttpStatus.valueOf(statusCode);
  82.     }

  83.     private String constructErrorBody(StatusCodeException exception) {
  84.         int errorCode = exception.getInternalCode();
  85.         if (errorCode < 100) {
  86.             errorCode = errorCodeBase + errorCode;
  87.         }

  88.         JSONObject json = constructJsonBody(exception, errorCode);

  89.         return json.toString();
  90.     }

  91.     private JSONObject constructJsonBody(Exception exception, int internalErrorCode) {
  92.         JSONObject json = new JSONObject();

  93.         JSONObject jError = new JSONObject();
  94.         jError.put("message", exception.getMessage());

  95.         if (internalErrorCode > 0) {
  96.             jError.put("code", internalErrorCode);
  97.         }

  98.         json.put("error", jError);

  99.         JSONObject jInfo = new JSONObject();
  100.         jInfo.put("engine", AppInfo.getEngineInfo());
  101.         jInfo.put("timestamp", System.currentTimeMillis());
  102.         json.put("info", jInfo);

  103.         return json;
  104.     }

  105.     private String constructGenericErrorBody(Exception exception) {
  106.         return constructJsonBody(exception, -1).toString();
  107.     }
  108. }