package de.rwth.idsg.bikeman.app.exception; import de.rwth.idsg.bikeman.psinterface.Utils; import de.rwth.idsg.bikeman.web.rest.exception.DatabaseException; import lombok.extern.slf4j.Slf4j; import org.hibernate.HibernateException; import org.springframework.beans.TypeMismatchException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import javax.persistence.PersistenceException; import java.util.ArrayList; import java.util.List; import java.util.Locale; /** * @author Sevket Goekay <goekay@dbis.rwth-aachen.de> * @since 23.02.2015 */ @ControllerAdvice(basePackages = "de.rwth.idsg.bikeman.app.resource") @Slf4j public class AppExceptionHandler { @Autowired private MessageSource messageSource; @ExceptionHandler(AppException.class) public ResponseEntity<AppExceptionMessage> processAppException(AppException e) { log.debug("Exception happened", e); HttpStatus status; AppErrorCode errorCode = e.getErrorCode(); switch (errorCode) { case CONSTRAINT_FAILED: status = HttpStatus.BAD_REQUEST; break; case VALIDATION_FAILED: case NOT_REGISTERED: case RENTAL_BLOCKED: case BOOKING_BLOCKED: status = HttpStatus.NOT_ACCEPTABLE; break; case AUTH_ATTEMPTS_EXCEEDED: case AUTH_FAILED: status = HttpStatus.FORBIDDEN; break; default: status = HttpStatus.INTERNAL_SERVER_ERROR; } AppExceptionMessage msg = new AppExceptionMessage( Utils.nowInSeconds(), errorCode.name(), e.getMessage() ); return new ResponseEntity<>(msg, status); } @ExceptionHandler({HibernateException.class, PersistenceException.class, DatabaseException.class}) public ResponseEntity<AppExceptionMessage> processDatabaseException(Exception e) { log.error("Exception happened", e); HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; AppExceptionMessage msg = new AppExceptionMessage( Utils.nowInSeconds(), AppErrorCode.DATABASE_OPERATION_FAILED.name(), e.getMessage() ); return new ResponseEntity<>(msg, status); } /** * Catches the controller path errors of the Rest API. * * Example: If a controller declares an integer in the path, but frontend sends anything but an integer. */ @ExceptionHandler(TypeMismatchException.class) public ResponseEntity<AppExceptionMessage> processTypeException(TypeMismatchException e) { log.error("Exception happened", e); HttpStatus status = HttpStatus.BAD_REQUEST; AppExceptionMessage msg = new AppExceptionMessage( status.value(), status.getReasonPhrase(), e.getMessage() ); return new ResponseEntity<>(msg, status); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<AppExceptionMessage> processValidationException(MethodArgumentNotValidException e) { log.error("Exception happened", e); Locale currentLocale = LocaleContextHolder.getLocale(); List<FieldError> errors = e.getBindingResult().getFieldErrors(); List<String> errorMessages = new ArrayList<>(); for (FieldError fieldError : errors) { String localizedError = fieldError.getField() + ": " + messageSource.getMessage(fieldError, currentLocale); errorMessages.add(localizedError); } HttpStatus status = HttpStatus.BAD_REQUEST; AppExceptionMessage msg = new AppExceptionMessage( status.value(), status.getReasonPhrase(), "Validation failed for the submitted form" ); msg.setFieldErrors(errorMessages); return new ResponseEntity<>(msg, status); } // ------------------------------------------------------------------------- // Fall-back // ------------------------------------------------------------------------- @ExceptionHandler(Exception.class) public ResponseEntity<AppExceptionMessage> processException(Exception e) { log.error("Exception happened", e); HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; AppExceptionMessage msg = new AppExceptionMessage( Utils.nowInSeconds(), AppErrorCode.UNKNOWN_SERVER_ERROR.name(), e.getMessage() ); return new ResponseEntity<>(msg, status); } }