org.openlmis.fulfillment.web.errorhandler.ServiceErrorHandling.java Source code

Java tutorial

Introduction

Here is the source code for org.openlmis.fulfillment.web.errorhandler.ServiceErrorHandling.java

Source

/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright  2017 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms
 * of the GNU Affero General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details. You should have received a copy of
 * the GNU Affero General Public License along with this program. If not, see
 * http://www.gnu.org/licenses. For additional information contact info@OpenLMIS.org.
 */

package org.openlmis.fulfillment.web.errorhandler;

import static org.openlmis.fulfillment.i18n.MessageKeys.DATA_INTEGRITY_VIOLATION;
import static org.openlmis.fulfillment.i18n.MessageKeys.ERROR_JASPER_REPORT_CREATION_WITH_MESSAGE;
import static org.openlmis.fulfillment.i18n.MessageKeys.ERROR_REFERENCE_DATA_RETRIEVE;
import static org.openlmis.fulfillment.i18n.MessageKeys.SHIPMENT_DRAT_ORDER_DUPLICATE;
import static org.openlmis.fulfillment.i18n.MessageKeys.SHIPMENT_ORDER_DUPLICATE;
import static org.springframework.http.HttpStatus.CONFLICT;

import net.sf.jasperreports.engine.JRException;
import org.hibernate.exception.ConstraintViolationException;
import org.openlmis.fulfillment.i18n.MessageKeys;
import org.openlmis.fulfillment.service.DuplicateTransferPropertiesException;
import org.openlmis.fulfillment.service.ExternalApiException;
import org.openlmis.fulfillment.service.IncorrectTransferPropertiesException;
import org.openlmis.fulfillment.service.OrderFileException;
import org.openlmis.fulfillment.service.OrderStorageException;
import org.openlmis.fulfillment.service.ReportingException;
import org.openlmis.fulfillment.service.DataRetrievalException;
import org.openlmis.fulfillment.util.Message;
import org.openlmis.fulfillment.web.ServerException;
import org.openlmis.fulfillment.web.util.LocalizedMessageDto;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.HashMap;
import java.util.Map;

/**
 * Controller advice responsible for handling errors from service layer.
 */
@ControllerAdvice
public class ServiceErrorHandling extends AbstractErrorHandling {

    private static final Map<String, String> CONSTRAINT_MAP = new HashMap<>();
    private static final String CONSTRAINT_VIOLATION = "Constraint violation";

    static {
        CONSTRAINT_MAP.put("shipments_order_unq", SHIPMENT_ORDER_DUPLICATE);
        CONSTRAINT_MAP.put("shipment_drafts_orderid_unq", SHIPMENT_DRAT_ORDER_DUPLICATE);
    }

    @ExceptionHandler(OrderFileException.class)
    public Message.LocalizedMessage handleOrderFileGenerationError(OrderFileException ex) {
        return logErrorAndRespond("Unable to generate the order file", ex);
    }

    @ExceptionHandler(ReportingException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Message.LocalizedMessage handlerReportingException(ReportingException ex) {
        return logErrorAndRespond("Reporting error", ex);
    }

    /**
     * Handles data integrity violation exception.
     *
     * @param ex the data integrity exception
     * @return the user-oriented error message.
     */
    @ExceptionHandler(DataIntegrityViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<Message.LocalizedMessage> handleDataIntegrityViolation(
            DataIntegrityViolationException ex) {
        if (ex.getCause() instanceof ConstraintViolationException) {
            ConstraintViolationException cause = (ConstraintViolationException) ex.getCause();
            String messageKey = CONSTRAINT_MAP.get(cause.getConstraintName());
            if (messageKey != null) {
                logger.error(CONSTRAINT_VIOLATION, ex);
                return new ResponseEntity<>(getLocalizedMessage(new Message(messageKey)), HttpStatus.BAD_REQUEST);
            } else {
                return new ResponseEntity<>(
                        logErrorAndRespond(CONSTRAINT_VIOLATION, MessageKeys.CONSTRAINT_VIOLATION, ex.getMessage()),
                        HttpStatus.BAD_REQUEST);
            }
        }

        return new ResponseEntity<>(
                logErrorAndRespond("Data integrity violation", DATA_INTEGRITY_VIOLATION, ex.getMessage()),
                CONFLICT);
    }

    /**
     * Handles the {@link DataRetrievalException} which we were unable to retrieve
     * reference data due to a communication error.
     *
     * @param ex the exception that caused the issue
     * @return the error response
     */
    @ExceptionHandler(DataRetrievalException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Message.LocalizedMessage handleRefDataException(DataRetrievalException ex) {
        return logErrorAndRespond("Error fetching from reference data", ERROR_REFERENCE_DATA_RETRIEVE,
                ex.getResource(), ex.getStatus().toString(), ex.getResponse());
    }

    /**
     * Handles the {@link ServerException} that indicates server error.
     *
     * @param ex the exception that caused the issue
     * @return the error response
     */
    @ExceptionHandler(ServerException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Message.LocalizedMessage handleServerException(ServerException ex) {
        logger.error("An internal error occurred", ex);
        return getLocalizedMessage(ex.getErrorMessage());
    }

    @ExceptionHandler(OrderStorageException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Message.LocalizedMessage handleOrderStorageException(OrderStorageException ex) {
        return logErrorAndRespond("Unable to store the order", ex);
    }

    @ExceptionHandler(DuplicateTransferPropertiesException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Message.LocalizedMessage handleDuplicateTransferPropertiesException(
            DuplicateTransferPropertiesException ex) {
        return logErrorAndRespond("Duplicate facility transfer properties", ex);
    }

    @ExceptionHandler(IncorrectTransferPropertiesException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Message.LocalizedMessage handleIncorrectTransferPropertiesException(
            IncorrectTransferPropertiesException ex) {
        return logErrorAndRespond("Incorrect facility transfer properties", ex);
    }

    /**
     * Handles the {@link JRException} which may be thrown during Jasper report generation.
     *
     * @param err exception that caused the issue
     * @return error response
     */
    @ExceptionHandler(JRException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Message.LocalizedMessage handleJrRuntimeException(JRException err) {
        return logErrorAndRespond("Error during Jasper Report generation",
                ERROR_JASPER_REPORT_CREATION_WITH_MESSAGE, err.getMessage());
    }

    @ExceptionHandler(ExternalApiException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public LocalizedMessageDto handleExternalApiException(ExternalApiException ex) {
        logger.error("An external api error occurred", ex);
        return ex.getMessageLocalized();
    }

}