package de.superx.rest; import java.io.IOException; import java.sql.SQLException; import java.text.ParseException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.log4j.Logger; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DuplicateKeyException; import org.springframework.data.relational.core.conversion.DbActionExecutionException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import de.memtext.tree.KeyParentEqualException; import de.memtext.tree.NoMainEntryException; import de.superx.bianalysis.FaultyMetadataException; import de.superx.bianalysis.service.IllegalMetaDataOperation; import de.superx.common.AccessDeniedException; import de.superx.common.ConfigurationException; import de.superx.common.DBServletException; import de.superx.common.InvalidDataTypeException; import de.superx.common.InvalidEntityException; import de.superx.common.InvalidKeyException; import de.superx.common.EtlConfigurationException; import de.superx.common.NotYetImplementedException; import de.superx.common.ObligatoryFieldEmptyException; import de.superx.common.SichtException; import de.superx.common.UngueltigeEingabeException; import de.superx.dbt.UnsupportedPythonVersionException; import de.superx.rest.model.ExceptionResponse; import de.superx.rest.model.RestMessageWrapperException; import freemarker.template.TemplateException; import net.sf.jasperreports.engine.JRException; /*** * Rip-Off of HISinOne's 'RestControllerBase' class. * Contains common functionality of REST controllers. * @author witt * */ abstract public class RestControllerBase { protected static ResponseEntity handleServerError(String message) { ExceptionResponse er = new ExceptionResponse(null, message, null); ResponseEntity re = new ResponseEntity(er, HttpStatus.INTERNAL_SERVER_ERROR); return re; } protected static ResponseEntity handleUserInputError(String message) { ExceptionResponse er = new ExceptionResponse(null, message, null); ResponseEntity re = new ResponseEntity(er, HttpStatus.UNPROCESSABLE_ENTITY); return re; } protected static ResponseEntity handleUserInputError(ExceptionResponse er, HttpStatus status) { ResponseEntity re = new ResponseEntity(er, status); return re; } abstract protected Logger getLogger(); /*** * changed dispatching of exception to handlers to explicit/central point, so we do not miss unexpected exceptions * @param ex - the exception to be dispatched to a specific handler * @return the response object for the web service call */ @ExceptionHandler(Exception.class) public ResponseEntity dispatchExceptionHandler(Exception ex) { if (ex instanceof MethodArgumentTypeMismatchException) { return handleMethodArgumentTypeMismatchException((MethodArgumentTypeMismatchException)ex); } else if (ex instanceof DBServletException) { return handleDBServletException((DBServletException)ex); } else if (ex instanceof IOException) { return handleIOException((IOException)ex); } else if (ex instanceof CloneNotSupportedException) { return handleCloneNotSupportedException((CloneNotSupportedException)ex); } else if (ex instanceof TemplateException) { return handleTemplateException((TemplateException)ex); } else if (ex instanceof SQLException) { return handleSQLException((SQLException)ex); } else if (ex instanceof ParserConfigurationException) { return handleParserConfigurationException((ParserConfigurationException)ex); } else if (ex instanceof ParseException) { return handleParseException((ParseException)ex); } else if (ex instanceof JRException) { return handleJRException((JRException)ex); } else if (ex instanceof KeyParentEqualException) { return handleKeyParentEqualException((KeyParentEqualException)ex); } else if (ex instanceof NoMainEntryException) { return handleNoMainEntryException((NoMainEntryException)ex); } else if (ex instanceof InvalidDataTypeException) { return handleInvalidDataTypeException((InvalidDataTypeException)ex); } else if (ex instanceof SichtException) { return handleSichtException((SichtException)ex); } else if (ex instanceof UngueltigeEingabeException) { return handleUngueltigeEingabeException((UngueltigeEingabeException)ex); } else if (ex instanceof ObligatoryFieldEmptyException) { return handleObligatoryFieldEmptyException((ObligatoryFieldEmptyException)ex); } else if (ex instanceof InvalidKeyException) { return handleInvalidKeyException((InvalidKeyException)ex); } else if (ex instanceof TransformerException) { return handleTransformerException((TransformerException)ex); } else if (ex instanceof NotYetImplementedException) { return handleNotYetImplementedException((NotYetImplementedException)ex); } else if (ex instanceof UnsupportedPythonVersionException) { return handleUnsupportedPythonVersionException((UnsupportedPythonVersionException)ex); } else if (ex instanceof InvalidEntityException) { return handleInvalidEntityException((InvalidEntityException)ex); } else if (ex instanceof DbActionExecutionException) { return handleDbActionExecutionException((DbActionExecutionException)ex); } else if (ex instanceof EtlConfigurationException) { return handleEtlConfigurationException((EtlConfigurationException)ex); } else if (ex instanceof ConfigurationException) { return handleConfigurationException((ConfigurationException)ex); } else if (ex instanceof AccessDeniedException) { return handleAccessDeniedException((AccessDeniedException)ex); } else if (ex instanceof InputValidationError) { return handleUserInputError(ex.getMessage()); } else if (ex instanceof FaultyMetadataException) { return handleFaultyMetadataException((FaultyMetadataException)ex); } else if (ex instanceof RestMessageWrapperException) { return handleRestMessageWrapperException((RestMessageWrapperException)ex); } else if (ex instanceof IllegalMetaDataOperation) { return handleIllegalMetaDataOperation((IllegalMetaDataOperation)ex); } else if (ex instanceof RuntimeException) { // Log stacktraces of runtime exceptions, otherwise the information is lost! getLogger().error("RuntimeException:", ex); } getLogger().error("an unexpected exception occured; exception type: ", ex); return handleServerError("an exception occured: " + ex.getCause()); } /*** * This exception occurs for example under the following circumstance: * Say we have a method annotated with "@RequestMapping". * This method has a parameter "int bla" that is annotated with "@RequestParam". * If someone calls this method (via web service), but the mapped parameter cannot * be transformed to an "int", this handler is entered. * @param ex * @return */ public ResponseEntity handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) { getLogger().error("MethodArgumentTypeMismatchException occured", ex); return handleUserInputError(ex.getMessage()); } public ResponseEntity handleDBServletException(DBServletException ex) { getLogger().error("DBServletException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleIOException(IOException ex) { getLogger().error("IOException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleCloneNotSupportedException(CloneNotSupportedException ex) { getLogger().error("CloneNotSupportedException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleTemplateException(TemplateException ex) { getLogger().error("TemplateException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleAccessDeniedException(AccessDeniedException ex) { getLogger().error("AccessDeniedException occured", ex); ExceptionResponse exceptionResponse = new ExceptionResponse("", "Kein Zugriff", null); // the original consideration was the following: // only return '404 - nor found' for security reasons: // caller must not even know, whether a resource exists or not // but: // HISinOne-Web Services send status 401 in case of missing permissions, // so we should do it as well... ResponseEntity responseEntity = new ResponseEntity(exceptionResponse, HttpStatus.UNAUTHORIZED); return responseEntity; } public ResponseEntity handleSQLException(SQLException ex) { getLogger().error("SQLException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleParserConfigurationException(ParserConfigurationException ex) { getLogger().error("ParserConfigurationException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleParseException(ParseException ex) { getLogger().error("ParseException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleJRException(JRException ex) { getLogger().error("ParserConfigurationException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleKeyParentEqualException(KeyParentEqualException ex) { getLogger().error("KeyParentEqualException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleNoMainEntryException(NoMainEntryException ex) { getLogger().error("NoMainEntryException occured", ex); return handleServerError("Interner Serverfehler"); } public ResponseEntity handleInvalidDataTypeException(InvalidDataTypeException ex) { getLogger().error("InvalidDataTypeException occured", ex); return handleUserInputError(ex.getMessage()); } public ResponseEntity handleSichtException(SichtException ex) { getLogger().error("SichtException occured", ex); return handleServerError(ex.getMessage()); } public ResponseEntity handleUngueltigeEingabeException(UngueltigeEingabeException ex) { getLogger().error("UngueltigeEingabeException occured", ex); return handleUserInputError(ex.getMessage()); } public ResponseEntity handleObligatoryFieldEmptyException(ObligatoryFieldEmptyException ex) { getLogger().error("ObligatoryFieldEmptyException occured", ex); return handleUserInputError(ex.getMessage()); } public ResponseEntity handleInvalidKeyException(InvalidKeyException ex) { getLogger().error("InvalidKeyException occured", ex); return handleUserInputError(ex.getMessage()); } public ResponseEntity handleTransformerException(TransformerException ex) { getLogger().error("TransformerException occured", ex); return handleServerError(ex.getMessage()); } public ResponseEntity handleNotYetImplementedException(NotYetImplementedException ex) { getLogger().error("NotYetImplementedException occured", ex); return handleServerError(ex.getMessage()); } public ResponseEntity handleIllegalMetaDataOperation(IllegalMetaDataOperation ex) { getLogger().error("IllegalMetaDataOperation occured", ex); return handleServerError(ex.getMessage()); } public ResponseEntity handleFaultyMetadataException(FaultyMetadataException ex) { getLogger().error("FaultyMetadataException occured", ex); return handleServerError(ex.getMessage()); } public ResponseEntity handleInvalidEntityException(InvalidEntityException ex) { getLogger().error("InvalidEntityException occured", ex); return handleUserInputError(ex.getMessage()); } public ResponseEntity handleDbActionExecutionException(DbActionExecutionException ex) { getLogger().error("DbActionExecutionException occured", ex); String nestedExceptionMessage = ex.getCause().getCause().getMessage(); if (ex.getCause().getClass().equals(DuplicateKeyException.class)) { return handleUserInputError(nestedExceptionMessage); } if (ex.getCause().getClass().equals(DataIntegrityViolationException.class)) { return handleUserInputError(nestedExceptionMessage); } return handleServerError("Interner Serverfehler"); } public ResponseEntity handleEtlConfigurationException(EtlConfigurationException ex) { getLogger().error("EtlConfigurationException occured", ex); return handleServerError("Invalid etl configuration: " + ex.getMessage()); } public ResponseEntity handleConfigurationException(ConfigurationException ex) { getLogger().error("ConfigurationException occured", ex); return handleUserInputError(ex.getMessage()); } public ResponseEntity handleRestMessageWrapperException(RestMessageWrapperException ex) { getLogger().error("RestMessageWrapperException occured", ex); return handleUserInputError(ex.exceptionResponse, ex.httpStatus); } public ResponseEntity handleUnsupportedPythonVersionException(UnsupportedPythonVersionException ex) { getLogger().error("UnsupportedPythonVersionException occured", ex); return handleServerError(ex.getMessage()); } protected static boolean isHttpRequestPresent() { RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); return (attrs instanceof ServletRequestAttributes); } }