package com.griddynamics.jagger.jaas.rest;
import com.griddynamics.jagger.jaas.exceptions.InvalidTestExecutionException;
import com.griddynamics.jagger.jaas.exceptions.ResourceAlreadyExistsException;
import com.griddynamics.jagger.jaas.exceptions.ResourceNotFoundException;
import com.griddynamics.jagger.jaas.exceptions.TestEnvironmentInvalidIdException;
import com.griddynamics.jagger.jaas.exceptions.TestEnvironmentNoSessionException;
import com.griddynamics.jagger.jaas.exceptions.TestEnvironmentSessionNotFoundException;
import com.griddynamics.jagger.jaas.exceptions.WrongTestEnvironmentRunningLoadScenarioException;
import com.griddynamics.jagger.jaas.exceptions.WrongTestEnvironmentStatusException;
import com.griddynamics.jagger.jaas.rest.error.ErrorResponse;
import org.hibernate.StaleStateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.griddynamics.jagger.jaas.rest.error.ErrorResponse.errorResponse;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CONFLICT;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.MediaType.APPLICATION_JSON;
/**
* Handles all exceptional situations for all rest controllers.
*/
@RestControllerAdvice
public class GlobalControllerExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalControllerExceptionHandler.class);
/**
* Catches an {@link org.hibernate.StaleStateException} exception which occurs if we try delete or update a row that
* does not exist.
*/
@ResponseStatus(NOT_FOUND)
@ExceptionHandler(StaleStateException.class)
public void noDataFound(StaleStateException exception) {
LOGGER.error(exception.getMessage(), exception);
}
/**
* Catches:
* <p>
* - {@link ResourceNotFoundException} exception which occurs
* once requested resource not found.
* <p>
* - {@link TestEnvironmentSessionNotFoundException} exception which occurs once session id
* from PUT request to /envs/{envId} doesn't match to env's session id.
*/
@ExceptionHandler({ResourceNotFoundException.class, TestEnvironmentSessionNotFoundException.class})
public ResponseEntity<ErrorResponse> resourceNotFound(RuntimeException exception) {
LOGGER.error(exception.getMessage(), exception);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(APPLICATION_JSON);
return new ResponseEntity<>(errorResponse(exception.getMessage(), NOT_FOUND), httpHeaders, NOT_FOUND);
}
/**
* Catches an {@link com.griddynamics.jagger.jaas.exceptions.ResourceAlreadyExistsException} exception which occurs
* once somebody tries to create already existing resource.
*/
@ExceptionHandler(ResourceAlreadyExistsException.class)
public ResponseEntity<ErrorResponse> resourceExists(ResourceAlreadyExistsException exception) {
LOGGER.error(exception.getMessage(), exception);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(APPLICATION_JSON);
return new ResponseEntity<>(errorResponse(exception.getMessage(), CONFLICT), httpHeaders, CONFLICT);
}
@ResponseStatus(value = INTERNAL_SERVER_ERROR)
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<?> foreignKeyException(DataIntegrityViolationException error) {
LOGGER.error(error.getMessage(), error);
ResponseEntity<?> responseEntity;
if (error.getMessage().contains("FOREIGN KEY")) {
responseEntity = new ResponseEntity<>("There is no such database.", BAD_REQUEST);
} else {
responseEntity = new ResponseEntity<>(error, INTERNAL_SERVER_ERROR);
}
return responseEntity;
}
/**
* Handles an exception which occurs if we try to access unavailable endpoint.
*/
@ResponseStatus(NOT_FOUND)
@ExceptionHandler(ResourceAccessException.class)
public void serverUnavailable(ResourceAccessException exception) {
LOGGER.error(exception.getMessage(), exception);
}
/**
* Handles an exception which occurs if client provided incorrect request
* such as 404 http response.
*/
@ExceptionHandler(HttpClientErrorException.class)
public void resourceNotFound(HttpClientErrorException exception, HttpServletResponse response) throws IOException {
LOGGER.error(exception.getMessage(), exception);
response.setContentType(APPLICATION_JSON.getType());
response.setStatus(exception.getRawStatusCode());
}
/**
* Handles:
* <p>
* - {@link WrongTestEnvironmentRunningLoadScenarioException} client tries to set runningLoadScenario which doesn't belong to that Test
* Environment;
* <p>
* - {@link WrongTestEnvironmentStatusException} client tries to set status which doesn't corresponds to runningLoadScenario value; <p>
* - {@link TestEnvironmentNoSessionException} client tries to perform PUT /envs/{envId} request without Environment-Session cookie. <p>
* - {@link TestEnvironmentInvalidIdException} client tries to create TestEnvironment with invalid id. <p>
* - {@link InvalidTestExecutionException} client tries to create not valid TestExecution. <p>
*/
@ExceptionHandler({WrongTestEnvironmentRunningLoadScenarioException.class, WrongTestEnvironmentStatusException.class,
TestEnvironmentNoSessionException.class, TestEnvironmentInvalidIdException.class, InvalidTestExecutionException.class})
public ResponseEntity<ErrorResponse> badRequest(RuntimeException exception) {
LOGGER.error(exception.getMessage(), exception);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(APPLICATION_JSON);
return new ResponseEntity<>(errorResponse(exception.getMessage(), BAD_REQUEST), httpHeaders, BAD_REQUEST);
}
}