001package ca.uhn.fhir.jpa.bulk.imprt.job;
002
003/*-
004 * #%L
005 * HAPI FHIR JPA Server
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.jpa.batch.config.BatchConstants;
024import ca.uhn.fhir.jpa.bulk.imprt.api.IBulkDataImportSvc;
025import ca.uhn.fhir.jpa.bulk.imprt.model.BulkImportJobStatusEnum;
026import org.springframework.batch.core.ExitStatus;
027import org.springframework.batch.core.StepExecution;
028import org.springframework.batch.core.StepExecutionListener;
029import org.springframework.batch.core.jsr.RetryListener;
030import org.springframework.beans.factory.annotation.Autowired;
031import org.springframework.retry.ExhaustedRetryException;
032
033import javax.annotation.Nonnull;
034
035import static org.apache.commons.lang3.StringUtils.isNotBlank;
036
037/**
038 * This class sets the job status to ERROR if any failures occur while actually
039 * generating the export files.
040 */
041public class BulkImportStepListener implements StepExecutionListener, RetryListener {
042
043        @Autowired
044        private IBulkDataImportSvc myBulkDataImportSvc;
045
046        @Override
047        public void beforeStep(@Nonnull StepExecution stepExecution) {
048                // nothing
049        }
050
051        @Override
052        public ExitStatus afterStep(StepExecution theStepExecution) {
053                if (theStepExecution.getExitStatus().getExitCode().equals(ExitStatus.FAILED.getExitCode())) {
054                        //Try to fetch it from the parameters first, and if it doesn't exist, fetch it from the context.
055                        String jobUuid = theStepExecution.getJobExecution().getJobParameters().getString(BatchConstants.JOB_UUID_PARAMETER);
056                        if (jobUuid == null) {
057                                jobUuid = theStepExecution.getJobExecution().getExecutionContext().getString(BatchConstants.JOB_UUID_PARAMETER);
058                        }
059                        assert isNotBlank(jobUuid);
060
061                        StringBuilder message = new StringBuilder();
062                        message.append("Job: ").append(theStepExecution.getExecutionContext().getString(BulkImportPartitioner.JOB_DESCRIPTION)).append("\n");
063                        message.append("File: ").append(theStepExecution.getExecutionContext().getString(BulkImportPartitioner.FILE_DESCRIPTION)).append("\n");
064                        for (Throwable next : theStepExecution.getFailureExceptions()) {
065                                if (next instanceof ExhaustedRetryException) {
066                                        next = next.getCause(); // ExhaustedRetryException is a spring exception that wraps the real one
067                                }
068                                String nextErrorMessage = next.toString();
069                                message.append("Error: ").append(nextErrorMessage).append("\n");
070                        }
071
072                        theStepExecution.addFailureException(new RuntimeException(message.toString()));
073
074                        myBulkDataImportSvc.setJobToStatus(jobUuid, BulkImportJobStatusEnum.ERROR, message.toString());
075
076                        ExitStatus exitStatus = ExitStatus.FAILED.addExitDescription(message.toString());
077                        theStepExecution.setExitStatus(exitStatus);
078
079                        // Replace the built-in error message with a better one
080                        return exitStatus;
081                }
082
083                return theStepExecution.getExitStatus();
084        }
085}