/*
* PatientView
*
* Copyright (c) Worth Solutions Limited 2004-2013
*
* This file is part of PatientView.
*
* PatientView is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
* PatientView 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 General Public License for more details.
* You should have received a copy of the GNU General Public License along with PatientView in a file
* titled COPYING. If not, see <http://www.gnu.org/licenses/>.
*
* @package PatientView
* @link http://www.patientview.org
* @author PatientView <info@patientview.org>
* @copyright Copyright (c) 2004-2013, Worth Solutions Limited
* @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0
*/
package org.patientview.service.impl;
import org.patientview.ibd.model.Allergy;
import org.patientview.ibd.model.MyIbd;
import org.patientview.ibd.model.Procedure;
import org.patientview.model.Patient;
import org.patientview.model.Unit;
import org.patientview.model.enums.SourceType;
import org.patientview.patientview.TestResultDateRange;
import org.patientview.patientview.XmlImportUtils;
import org.patientview.patientview.logging.AddLog;
import org.patientview.patientview.model.Centre;
import org.patientview.patientview.model.Diagnosis;
import org.patientview.patientview.model.Diagnostic;
import org.patientview.patientview.model.Letter;
import org.patientview.patientview.model.Medicine;
import org.patientview.patientview.model.TestResult;
import org.patientview.patientview.parser.ResultParser;
import org.patientview.patientview.user.UserUtils;
import org.patientview.patientview.utils.TimestampUtils;
import org.patientview.quartz.exception.ProcessException;
import org.patientview.quartz.exception.ResultParserException;
import org.patientview.quartz.handler.ErrorHandler;
import org.patientview.repository.UnitDao;
import org.patientview.service.ImportManager;
import org.patientview.service.LogEntryManager;
import org.patientview.utils.LegacySpringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.inject.Inject;
import java.io.File;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
*
*/
@Service(value = "importManager")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = ProcessException.class)
public class ImportManagerImpl implements ImportManager {
private static final Logger LOGGER = LoggerFactory.getLogger(ImportManagerImpl.class);
@Inject
private XmlImportUtils xmlImportUtils;
@Inject
private UnitDao unitDao;
@Inject
private ApplicationContext applicationContext;
@Inject
private LogEntryManager logEntryManager;
@Inject
private ErrorHandler errorHandler;
@Override
public Unit retrieveUnit(String unitCode) {
unitCode = unitCode.toUpperCase();
return unitDao.get(unitCode, null);
}
public void process(File xmlFile) throws ProcessException {
LOGGER.debug("Processing file {}.", xmlFile.getName());
if (xmlFile.length() == 0) {
errorHandler.emptyFile(xmlFile);
throw new ProcessException("The file is empty");
}
ResultParser resultParser = null;
try {
resultParser = new ResultParser(xmlFile);
} catch (ResultParserException pe) {
errorHandler.parserException(xmlFile, pe);
throw new ProcessException("Could not create the parser for the file", pe);
}
// If the file parse process otherwise email the corruptions
if (resultParser.parse()) {
String action = null;
try {
action = processPatientData(resultParser);
} catch (ProcessException pe) {
errorHandler.processingException(xmlFile, pe);
throw pe;
} catch (Exception e) {
errorHandler.processingException(xmlFile, e);
throw new ProcessException("There has been an error processing the data", e);
}
log(xmlFile, action);
} else {
errorHandler.corruptNodes(xmlFile, resultParser);
throw new ProcessException("There are file corruptions");
}
}
private boolean hasPatientLeft(ResultParser parser) {
return ("Remove".equalsIgnoreCase(parser.getFlag()) || "Dead".equalsIgnoreCase(parser.getFlag())
|| "Died".equalsIgnoreCase(parser.getFlag()) || "Lost".equalsIgnoreCase(parser.getFlag())
|| "Suspend".equalsIgnoreCase(parser.getFlag()));
}
private void removePatientFromSystem(ResultParser parser) {
UserUtils.removePatientFromSystem(parser.getData("nhsno"), parser.getData("centrecode"));
}
private String processPatientData(ResultParser resultParser) throws ProcessException {
if (hasPatientLeft(resultParser)) {
removePatientFromSystem(resultParser);
return AddLog.PATIENT_DATA_REMOVE;
} else {
validateUnitCode(resultParser.getCentre());
updatePatientDetails(resultParser.getPatient(), resultParser.getDateRanges());
deleteDateRanges(resultParser.getDateRanges());
insertResults(resultParser.getTestResults());
deleteLetters(resultParser.getLetters());
insertLetters(resultParser.getLetters());
deleteOtherDiagnoses(resultParser.getData("nhsno"), resultParser.getData("centrecode"));
insertOtherDiagnoses(resultParser.getOtherDiagnoses());
deleteMedicines(resultParser.getData("nhsno"), resultParser.getData("centrecode"));
insertMedicines(resultParser.getMedicines());
deleteMyIbd(resultParser.getData("nhsno"), resultParser.getData("centrecode"));
insertMyIbd(resultParser.getMyIbd());
deleteDiagnostics(resultParser.getData("nhsno"), resultParser.getData("centrecode"));
insertDiagnostics(resultParser.getDiagnostics());
deleteProcedures(resultParser.getData("nhsno"), resultParser.getData("centrecode"));
insertProcedures(resultParser.getProcedures());
deleteAllergies(resultParser.getData("nhsno"), resultParser.getData("centrecode"));
insertAllergies(resultParser.getAllergies());
// todo improvement: we should build a set of all units updated, then mark them at the end of the job
markLastImportDateOnUnit(resultParser.getCentre());
return AddLog.PATIENT_DATA_FOLLOWUP;
}
}
private void markLastImportDateOnUnit(Centre centre) {
Unit unit = LegacySpringUtils.getImportManager().retrieveUnit(centre.getCentreCode());
if (unit != null) {
unit.setLastImportDate(new Date());
unitDao.save(unit);
}
}
private void deleteDiagnostics(String nhsno, String unitcode) {
LegacySpringUtils.getDiagnosticManager().delete(nhsno, unitcode);
}
private void insertDiagnostics(Collection<Diagnostic> diagnostics) {
for (Iterator iterator = diagnostics.iterator(); iterator.hasNext();) {
Diagnostic diagnostic = (Diagnostic) iterator.next();
LegacySpringUtils.getDiagnosticManager().save(diagnostic);
}
}
private void deleteProcedures(String nhsno, String unitcode) {
LegacySpringUtils.getIbdManager().deleteProcedure(nhsno, unitcode);
}
private void insertProcedures(Collection<Procedure> procedures) {
for (Iterator iterator = procedures.iterator(); iterator.hasNext();) {
Procedure procedure = (Procedure) iterator.next();
LegacySpringUtils.getIbdManager().saveProcedure(procedure);
}
}
private void deleteAllergies(String nhsno, String unitcode) {
LegacySpringUtils.getIbdManager().deleteAllergy(nhsno, unitcode);
}
private void insertAllergies(Collection<Allergy> allergies) {
for (Iterator iterator = allergies.iterator(); iterator.hasNext();) {
Allergy allergy = (Allergy) iterator.next();
LegacySpringUtils.getIbdManager().saveAllergy(allergy);
}
}
private void deleteMyIbd(String nhsno, String unitcode) {
LegacySpringUtils.getIbdManager().deleteMyIbd(nhsno, unitcode);
}
private void insertMyIbd(MyIbd myIbd) {
if (myIbd != null) {
LegacySpringUtils.getIbdManager().saveMyIbd(myIbd);
}
}
/**
*
* If we have test results that are later than any seen before,
* update the patient mostRecentTestResultDateRangeStopDate.
*
* Only update the mostRecentTestResultDateRangeStopDate if the new values is after the
* existing value on the existing patient record
*
* @param patient new patient details
* @param dateRanges the date ranges for test results found in this import
*/
private void updatePatientDetails(Patient patient, List<TestResultDateRange> dateRanges) throws ProcessException {
Patient existingPatientRecord
= LegacySpringUtils.getPatientManager().get(patient.getNhsno(), patient.getUnitcode());
// This field should be not nullable.
if (existingPatientRecord != null && existingPatientRecord.getSourceType() != null
&& existingPatientRecord.getSourceType().equals(SourceType.RADAR.getName())) {
throw new ProcessException("Cannot update an existing Radar patient record");
}
Date existingTestResultDateRangeStopDate = null;
if (existingPatientRecord != null && existingPatientRecord.hasValidId()) {
existingTestResultDateRangeStopDate = existingPatientRecord.getMostRecentTestResultDateRangeStopDate();
}
patient.setMostRecentTestResultDateRangeStopDate(
getMostRecentTestResultDateRangeStopDate(dateRanges, existingTestResultDateRangeStopDate));
// Have to do it like this because Radar uses JDBC only
patient.setSourceType(SourceType.PATIENT_VIEW.getName());
if (existingPatientRecord != null) {
LegacySpringUtils.getPatientManager().save(XmlImportUtils.copyObject(existingPatientRecord, patient));
} else {
LegacySpringUtils.getPatientManager().save(patient);
}
}
private Date getMostRecentTestResultDateRangeStopDate(List<TestResultDateRange> dateRanges,
Date mostRecentTestResultDateRangeStopDate) {
if (dateRanges != null && dateRanges.size() > 0) {
for (TestResultDateRange testResultDateRange : dateRanges) {
Date stopDate = TimestampUtils.createTimestampEndDay(testResultDateRange.getStopDate()).getTime();
// update the most recent if after
if (mostRecentTestResultDateRangeStopDate == null
|| stopDate.after(mostRecentTestResultDateRangeStopDate)) {
mostRecentTestResultDateRangeStopDate = stopDate;
}
}
}
return mostRecentTestResultDateRangeStopDate;
}
private void validateUnitCode(Centre centre) throws ProcessException {
if (unitDao.get(centre.getCentreCode(), null) == null) {
throw new ProcessException("The unit code supplied by the file does not exist in the database");
}
}
private void deleteDateRanges(Collection dateRanges) {
for (Iterator iterator = dateRanges.iterator(); iterator.hasNext();) {
TestResultDateRange testResultDateRange = (TestResultDateRange) iterator.next();
Calendar startDate = TimestampUtils.createTimestampStartDay(testResultDateRange.getStartDate());
Calendar stopDate = TimestampUtils.createTimestampEndDay(testResultDateRange.getStopDate());
LegacySpringUtils.getTestResultManager().deleteTestResultsWithinTimeRange(testResultDateRange.getNhsNo(),
testResultDateRange.getUnitcode(), testResultDateRange.getTestCode(), startDate.getTime(),
stopDate.getTime());
}
}
private void insertResults(Collection testResults) {
for (Iterator iterator = testResults.iterator(); iterator.hasNext();) {
TestResult testResult = (TestResult) iterator.next();
LegacySpringUtils.getTestResultManager().save(testResult);
}
}
private void deleteLetters(Collection letters) {
for (Iterator iterator = letters.iterator(); iterator.hasNext();) {
Letter letter = (Letter) iterator.next();
// Avoiding NPE in RPV-126. Although this will leave the letter in the DB.
if (letter.getDate() != null) {
LegacySpringUtils.getLetterManager().delete(letter.getNhsno(), letter.getUnitcode(),
letter.getDate().getTime());
} else {
LOGGER.warn("The letter does not come with a date so skipping deletion");
}
}
}
private void insertLetters(Collection letters) {
for (Iterator iterator = letters.iterator(); iterator.hasNext();) {
Letter letter = (Letter) iterator.next();
LegacySpringUtils.getLetterManager().save(letter);
}
}
private void deleteOtherDiagnoses(String nhsno, String unitcode) {
LegacySpringUtils.getDiagnosisManager().deleteOtherDiagnoses(nhsno, unitcode);
}
private void insertOtherDiagnoses(Collection diagnoses) {
for (Iterator iterator = diagnoses.iterator(); iterator.hasNext();) {
Diagnosis diagnosis = (Diagnosis) iterator.next();
LegacySpringUtils.getDiagnosisManager().save(diagnosis);
}
}
private void deleteMedicines(String nhsno, String unitcode) {
LegacySpringUtils.getMedicineManager().delete(nhsno, unitcode);
}
private void insertMedicines(Collection medicines) {
for (Iterator iterator = medicines.iterator(); iterator.hasNext();) {
Medicine medicine = (Medicine) iterator.next();
LegacySpringUtils.getMedicineManager().save(medicine);
}
}
private void log(File xmlFile, String action) {
errorHandler.createLogEntry(xmlFile, action, "");
}
}