diff --git a/connector/Dockerfile b/connector/Dockerfile index 8a9dc63..a1bd264 100644 --- a/connector/Dockerfile +++ b/connector/Dockerfile @@ -36,8 +36,8 @@ WORKDIR /app ARG DEPENDENCY=/app/target/dependency COPY --from=build /app/target/*.jar /app/ -COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib -COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF +# COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib +# COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF COPY mvnw . diff --git a/connector/pom.xml b/connector/pom.xml index 8cc195e..e786951 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -19,6 +19,13 @@ UTF-8 4.1 + 3.0.41 + ${project.basedir}/src/main/resources/ohpp-api.yaml + ${project.build.directory}/generated-sources + main/java + 2.6.1 + 2.1 + org.isf.patientportal.connector.ConnectorApplication org.springframework.boot @@ -76,16 +83,6 @@ spring-batch-test test - - org.springframework.boot - spring-boot-starter-log4j2 - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.springframework.boot spring-boot-devtools @@ -98,7 +95,43 @@ 3.0.0 + + com.fasterxml.jackson.core + jackson-databind + 2.14.2 + + + io.springfox + springfox-boot-starter + 3.0.0 + + + + io.swagger.core.v3 + swagger-annotations + 2.2.8 + + + + + javax.validation + validation-api + 2.0.1.Final + + + + org.openapitools + jackson-databind-nullable + 0.2.1 + + + + joda-time + joda-time + ${joda.version} + + org.isf OH-core @@ -130,6 +163,15 @@ --> + + + src/main/resources + true + + **/conf.properties + + + maven-compiler-plugin @@ -143,8 +185,11 @@ spring-boot-maven-plugin + + repackage + - org.isf.patientportal.connector.ConnectorApplication + ${spring.boot.mainclass} @@ -155,6 +200,9 @@ release + + org.isf.patientportal.connector.ConnectorApplication + diff --git a/connector/src/main/java/org/isf/patientportal/connector/ConnectorApplication.java b/connector/src/main/java/org/isf/patientportal/connector/ConnectorApplication.java index 23b9b33..aa58c11 100644 --- a/connector/src/main/java/org/isf/patientportal/connector/ConnectorApplication.java +++ b/connector/src/main/java/org/isf/patientportal/connector/ConnectorApplication.java @@ -1,12 +1,26 @@ package org.isf.patientportal.connector; -import org.isf.generaldata.GeneralData; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.isf.patientportal.connector.common.SyncReport; +import org.isf.patientportal.connector.config.ConnectorConfiguration; +import org.isf.patientportal.connector.sync.common.SyncResult; +import org.isf.patientportal.connector.sync.patient.PatientSource; +import org.isf.patientportal.connector.sync.patient.PatientSyncer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ImportResource; @ImportResource({"classpath*:**/applicationContext.xml"}) @@ -15,14 +29,45 @@ public class ConnectorApplication implements CommandLineRunner { private static final Logger logger = LoggerFactory.getLogger(ConnectorApplication.class); + @Autowired + private PatientSource patientSource; + + public static void main(String[] args) { SpringApplication.run(ConnectorApplication.class, args); } + @Bean + protected PatientSyncer patientSyncer() { + return new PatientSyncer(); + } + @Override public void run(String... args) throws Exception { - logger.debug("Starting oh connector using config file"); - GeneralData.getGeneralData(); + logger.info("Starting oh connector using config "); + logger.info("Api url " + ConnectorConfiguration.API_URL); + logger.info("Using " + ConnectorConfiguration.PARALLEL + " threads"); + + ExecutorService executor = Executors.newFixedThreadPool(ConnectorConfiguration.PARALLEL); + List patientIds = patientSource.getPatientIds(); + logger.info("Found " + patientIds.size() + " patients to sync"); + List> patientsToSync = new ArrayList>(); + for (Integer patientId : patientIds) { + PatientSyncer patientSyncer = new PatientSyncer(patientId); + patientSyncer.setPatientManager(patientSource.getPatientManager()); + patientsToSync.add(patientSyncer); + } + List> results = executor.invokeAll(patientsToSync); + executor.shutdown(); + + SyncReport report = new SyncReport(); + for (Future future : results) { + SyncResult result = future.get(); + report.addResult(result); + } + + logger.info("Sync report: " + report); + } } diff --git a/connector/src/main/java/org/isf/patientportal/connector/common/SyncReport.java b/connector/src/main/java/org/isf/patientportal/connector/common/SyncReport.java new file mode 100644 index 0000000..efa3c0e --- /dev/null +++ b/connector/src/main/java/org/isf/patientportal/connector/common/SyncReport.java @@ -0,0 +1,34 @@ +package org.isf.patientportal.connector.common; + +import java.util.ArrayList; + +import org.isf.patientportal.connector.sync.common.SyncResult; + +public class SyncReport { + + protected ArrayList results; + + public SyncReport() { + results = new ArrayList(); + } + + + public void addResult(SyncResult result) { + results.add(result); + } + + public ArrayList getResults() { + return results; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Sync report:\n"); + for (SyncResult result : results) { + sb.append("Synced " + result.getObjectId() + "[" + result.getObjectType() + "] OP " + result.getOp().name() + " with result " + result.isSuccess() + " and message " + result.getMessage() + "\n"); + sb.append("\n"); + } + return sb.toString(); + } + +} diff --git a/connector/src/main/java/org/isf/patientportal/connector/config/Configuration.java b/connector/src/main/java/org/isf/patientportal/connector/config/ConnectorConfiguration.java similarity index 55% rename from connector/src/main/java/org/isf/patientportal/connector/config/Configuration.java rename to connector/src/main/java/org/isf/patientportal/connector/config/ConnectorConfiguration.java index 855e6f9..76a3f28 100644 --- a/connector/src/main/java/org/isf/patientportal/connector/config/Configuration.java +++ b/connector/src/main/java/org/isf/patientportal/connector/config/ConnectorConfiguration.java @@ -1,14 +1,20 @@ package org.isf.patientportal.connector.config; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; -public class Configuration { +@Configuration +public class ConnectorConfiguration { @Value("${oh.api.key}") public static String API_KEY = "1234567890"; @Value("${oh.api.token}") public static String API_TOKEN = "1234567890"; + @Value("${oh.api.url}") + public static String API_URL = "http://localhost:8080/patient-portal/api"; + @Value("${oh.api.parallel}") public static int PARALLEL = 2; diff --git a/connector/src/main/java/org/isf/patientportal/connector/patient/PatientSyncer.java b/connector/src/main/java/org/isf/patientportal/connector/patient/PatientSyncer.java deleted file mode 100644 index 565c0b9..0000000 --- a/connector/src/main/java/org/isf/patientportal/connector/patient/PatientSyncer.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.isf.patientportal.connector.patient; - -import org.isf.patient.manager.PatientBrowserManager; -import org.isf.patient.model.Patient; -import org.isf.utils.exception.OHServiceException; -import org.springframework.beans.factory.annotation.Autowired; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class PatientSyncer implements Runnable { - private int patientId; - - @Autowired - protected PatientBrowserManager patientManager; - - private static final Logger logger = LoggerFactory.getLogger(PatientSyncer.class); - - public PatientSyncer(int patientId) { - this.patientId = patientId; - - } - - @Override - public void run() { - // TODO Auto-generated method stub - logger.debug("Syncing patient with id: " + patientId); - try { - Patient patient = patientManager.getPatientById(patientId); - - System.out.println(patient.getSecondName()); - } catch (OHServiceException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } -} diff --git a/connector/src/main/java/org/isf/patientportal/connector/runner/ImportRunner.java b/connector/src/main/java/org/isf/patientportal/connector/runner/ImportRunner.java index 44cf086..c178b8f 100644 --- a/connector/src/main/java/org/isf/patientportal/connector/runner/ImportRunner.java +++ b/connector/src/main/java/org/isf/patientportal/connector/runner/ImportRunner.java @@ -1,7 +1,7 @@ package org.isf.patientportal.connector.runner; -import org.isf.patientportal.connector.config.Configuration; +import org.isf.patientportal.connector.config.ConnectorConfiguration; public class ImportRunner { public void syncPatient(int patientId) { @@ -9,7 +9,7 @@ public void syncPatient(int patientId) { } public void run() { - int numThreads = Configuration.PARALLEL; + int numThreads = ConnectorConfiguration.PARALLEL; } diff --git a/connector/src/main/java/org/isf/patientportal/connector/sync/common/SyncResult.java b/connector/src/main/java/org/isf/patientportal/connector/sync/common/SyncResult.java new file mode 100644 index 0000000..42e06ef --- /dev/null +++ b/connector/src/main/java/org/isf/patientportal/connector/sync/common/SyncResult.java @@ -0,0 +1,57 @@ +package org.isf.patientportal.connector.sync.common; + + +public class SyncResult { + + public enum Op { + NOOP, UPDATE, CREATE, DELETE, ERROR + } + + private int objectId; + private String objectType; + private boolean success; + private String message; + private Op resultType; + + public SyncResult() { + } + + public SyncResult(int objectId, String objectType, boolean success, String message, Op resultType) { + this.objectId = objectId; + this.objectType = objectType; + this.success = success; + this.message = message; + this.resultType = resultType; + } + + public int getObjectId() { + return objectId; + } + public void setObjectId(int objectId) { + this.objectId = objectId; + } + public String getObjectType() { + return objectType; + } + public void setObjectType(String objectType) { + this.objectType = objectType; + } + public boolean isSuccess() { + return success; + } + public void setSuccess(boolean success) { + this.success = success; + } + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + public Op getOp() { + return resultType; + } + public void setOp(Op resultType) { + this.resultType = resultType; + } +} diff --git a/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientMapper.java b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientMapper.java new file mode 100644 index 0000000..9945b66 --- /dev/null +++ b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientMapper.java @@ -0,0 +1,28 @@ +package org.isf.patientportal.connector.sync.patient; + +import org.isf.patient.model.Patient; +// import org.isf.patientportal.client.v1.model.Role; +// import org.isf.patientportal.client.v1.model.User; + +public class PatientMapper { + // public static org.isf.patientportal.client.v1.model.PatientDto mapPatientToPatientDto(org.isf.patient.model.Patient patient) { + // org.isf.patientportal.client.v1.model.PatientDto patientDto = new org.isf.patientportal.client.v1.model.PatientDto(); + // patientDto.setAddress(patient.getAddress()); + // patientDto.setAge(patient.getAge()); + // patientDto.setBirthDate(patient.getBirthDate()); + // patientDto.setCity(patient.getCity()); + // patientDto.setFirstName(patient.getFirstName()); + // patientDto.setSecondName(patient.getSecondName()); + // patientDto.setSex(String.valueOf(patient.getSex())); + // patientDto.setTelephone(patient.getTelephone()); + // return patientDto; + // } + + // public static User mapPatientToUser(Patient patient) { + // User user = new User(); + // // user.setEmail(patient.getEmail()); + // user.setActive(true); + // user.setUsername(patient.getName() + patient.getSecondName()); + // return user; + // } +} diff --git a/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSource.java b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSource.java new file mode 100644 index 0000000..2c988a5 --- /dev/null +++ b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSource.java @@ -0,0 +1,51 @@ +package org.isf.patientportal.connector.sync.patient; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +import org.isf.patient.manager.PatientBrowserManager; +import org.isf.patient.model.Patient; +import org.isf.utils.exception.OHServiceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Component +public class PatientSource { + @Autowired + protected PatientBrowserManager patientManager; + + private static final Logger logger = LoggerFactory.getLogger(PatientSource.class); + + public PatientSource() { + } + + public PatientBrowserManager getPatientManager() { + return patientManager; + } + + public void setPatientManager(PatientBrowserManager patientManager) { + this.patientManager = patientManager; + } + + public List getPatientIds() throws PatientSourceException { + logger.info("Reading patient ids from open hospital database"); + logger.info("Manager is " + patientManager); + try { + + return patientManager.getPatient().stream() + .map(Patient::getCode) + .collect(Collectors.toList()); + } catch (OHServiceException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + throw new PatientSourceException(e); + } + + } + + +} diff --git a/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSourceException.java b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSourceException.java new file mode 100644 index 0000000..98170af --- /dev/null +++ b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSourceException.java @@ -0,0 +1,11 @@ +package org.isf.patientportal.connector.sync.patient; + +public class PatientSourceException extends Exception { + + /** + * Creates a new instance of PatientSourceException without detail message. + */ + public PatientSourceException(Throwable e) { + super(e); + } +} diff --git a/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSyncer.java b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSyncer.java new file mode 100644 index 0000000..9d4a3d4 --- /dev/null +++ b/connector/src/main/java/org/isf/patientportal/connector/sync/patient/PatientSyncer.java @@ -0,0 +1,93 @@ +package org.isf.patientportal.connector.sync.patient; + +import java.util.concurrent.Callable; + +import org.isf.patient.manager.PatientBrowserManager; +import org.isf.patient.model.Patient; +// import org.isf.patientportal.client.v1.api.AuthApi; +// import org.isf.patientportal.client.v1.api.PatientsApi; +// import org.isf.patientportal.client.v1.api.UserApi; +// import org.isf.patientportal.client.v1.model.PatientDto; +// import org.isf.patientportal.client.v1.model.User; +import org.isf.patientportal.connector.sync.common.SyncResult; +import org.isf.utils.exception.OHServiceException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Component +public class PatientSyncer implements Callable { + private int patientId; + private String apiKey; + + @Autowired + protected PatientBrowserManager patientManager; + + // @Autowired + // protected PatientsApi patientsApi; + + // @Autowired + // protected UserApi userApi; + + private static final Logger logger = LoggerFactory.getLogger(PatientSyncer.class); + + public PatientSyncer() { + } + + public PatientSyncer(int patientId) { + this.patientId = patientId; + } + + public int getPatientId() { + return patientId; + } + + public void setPatientId(int patientId) { + this.patientId = patientId; + } + + public PatientBrowserManager getPatientManager() { + return patientManager; + } + + public void setPatientManager(PatientBrowserManager patientManager) { + this.patientManager = patientManager; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + protected SyncResult syncPatient(Patient patient) { + logger.debug("Syncing patient with id: " + patientId); + logger.info("Checking patient with name: " + patient.getFirstName() + " " + patient.getSecondName()); + // set api key + // User userDto = PatientMapper.mapPatientToUser(patient); + // logger.info("User: " + userDto.toString()); + // userApi.createUserUsingPOST(userDto); + // PatientDto patientDto = PatientMapper.mapPatientToPatientDto(patient); + // patientDto.setUsers(userDto); + // logger.info("PatientDto: " + patientDto.toString()); + // patientsApi.createPatientUsingPOST(patientDto); + return new SyncResult(patientId, "patient", true, "Patient synced successfully", SyncResult.Op.CREATE); + } + + @Override + public SyncResult call() throws Exception { + // TODO Auto-generated method stub + logger.debug("Syncing patient with id: " + patientId); + try { + Patient patient = patientManager.getPatientById(patientId); + return syncPatient(patient); + } catch (OHServiceException e) { + // TODO Auto-generated catch block + logger.error("Error syncing patient", e); + return new SyncResult(patientId, "patient", false, "Patient sync failed: " + e.getMessage(), SyncResult.Op.ERROR); + } + } +} diff --git a/connector/src/main/resources/settings.properties.dist b/connector/src/main/resources/settings.properties.dist index 268fb09..341c0e2 100644 --- a/connector/src/main/resources/settings.properties.dist +++ b/connector/src/main/resources/settings.properties.dist @@ -1 +1,49 @@ -LANGUAGE=ohlanguage \ No newline at end of file +# This file contains Open Hospital settings +LANGUAGE=en +SINGLEUSER=no +AUTOMATICLOT_IN=no +AUTOMATICLOT_OUT=no +AUTOMATICLOTWARD_TOWARD=no +LOTWITHCOST=yes +VISITSHEET=WardVisits +PATIENTSHEET=patient_clinical_sheet_ver3 +EXAMINATIONCHART=patient_examination +OPDCHART=patient_opd_chart +ADMCHART=patient_adm_chart +DISCHART=patient_dis_chart +PATIENTBILL=PatientBill +BILLSREPORT=BillsReport +BILLSREPORTPENDING=BillsReportPending +BILLSREPORTMONTHLY=BillsReportMonthly +PHARMACEUTICALORDER=PharmaceuticalOrder +PHARMACEUTICALSTOCK=PharmaceuticalStock_ver4 +PHARMACEUTICALSTOCKLOT=PharmaceuticalStock_ver5 +PHARMACEUTICALAMC=PharmaceuticalAMC +PATIENTEXTENDED=yes +OPDEXTENDED=yes +MATERNITYRESTARTINJUNE=no +LABEXTENDED=yes +LABMULTIPLEINSERT=yes +INTERNALPHARMACIES=yes +MERGEFUNCTION=yes +SMSENABLED=no +INTERNALVIEWER=yes +DOC_DIR=../doc +MAINMENUALWAYSONTOP=no +RECEIPTPRINTER=yes +VIDEOMODULEENABLED=yes +PATIENTVACCINEEXTENDED=yes +ENHANCEDSEARCH=yes +XMPPMODULEENABLED=no +DICOMMODULEENABLED=yes +DICOMTHUMBNAILS=yes +ALLOWPRINTOPENEDBILL=yes +ALLOWMULTIPLEOPENEDBILL=yes +PATIENTBILLGROUPED=PatientBillGrouped +PATIENTBILLSTATEMENT=PatientBillStatement +DEBUG=no +USERSLISTLOGIN=no +STRONGPASSWORD=yes +STRONGLENGTH=10 +PATIENTPHOTOSTORAGE=./data/photo +SESSIONTIMEOUT=1 \ No newline at end of file