diff --git a/README.md b/README.md index c348ce5..8f7727c 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ The Lab on FHir Module only generates the Lab WorkFlow Fhir Bundle When an order see more about the [EMR-LIS FHIR Workflow](https://wiki.openmrs.org/display/projects/Lab+Integration+Workflow) Configure the Following Global Properties Required By the Lab on Fhir Module -* `labonfhir.openElisUrl` ,The URL for the OpenELIS system to communicate with -* `labonfhir.openElisUserUuid` ,UUID for the service user that represents OpenELIS +* `labonfhir.lisUrl` ,The URL for the OpenELIS system to communicate with +* `labonfhir.lisUserUuid` ,UUID for the service user that represents OpenELIS * `labonfhir.truststorePath` , Path to truststore for HttpClient * `labonfhir.truststorePass` , Truststore password * `labonfhir.keystorePath` , Path to keystore for HttpClient @@ -44,4 +44,3 @@ Configure the Following Global Properties Required By the Lab on Fhir Module * `labonfhir.password` ,Password for HTTP Basic Auth with the LIS - \ No newline at end of file diff --git a/api/src/main/java/org/openmrs/module/labonfhir/FhirConfig.java b/api/src/main/java/org/openmrs/module/labonfhir/FhirConfig.java index 2debeb0..58cc5d5 100644 --- a/api/src/main/java/org/openmrs/module/labonfhir/FhirConfig.java +++ b/api/src/main/java/org/openmrs/module/labonfhir/FhirConfig.java @@ -37,10 +37,10 @@ public IGenericClient getFhirClient() throws Exception { configureFhirHttpClient(client); } - IGenericClient fhirClient = fhirContext.newRestfulGenericClient(config.getOpenElisUrl()); + IGenericClient fhirClient = fhirContext.newRestfulGenericClient(config.getLisUrl()); if (config.getAuthType().equals(AuthType.BASIC)) { - BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor(config.getOpenElisUserName(), - config.getOpenElisPassword()); + BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor(config.getLisUserName(), + config.getLisPassword()); fhirClient.registerInterceptor(authInterceptor); } return fhirClient; diff --git a/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirActivator.java b/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirActivator.java index cf58839..d5d9c31 100644 --- a/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirActivator.java +++ b/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirActivator.java @@ -13,7 +13,6 @@ import java.util.Optional; -import org.openmrs.PatientIdentifier; import org.openmrs.PatientIdentifierType; import org.openmrs.api.PatientService; import org.openmrs.module.BaseModuleActivator; @@ -21,7 +20,7 @@ import org.openmrs.module.DaemonTokenAware; import org.openmrs.module.fhir2.api.FhirPatientIdentifierSystemService; import org.openmrs.module.fhir2.model.FhirPatientIdentifierSystem; -import org.openmrs.module.labonfhir.api.OpenElisManager; +import org.openmrs.module.labonfhir.api.LabOrderManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -43,7 +42,7 @@ public class LabOnFhirActivator extends BaseModuleActivator implements Applicati private LabOnFhirConfig config; @Autowired - private OpenElisManager openElisManager; + private LabOrderManager lisManager; @Autowired PatientService patientService; @@ -56,11 +55,11 @@ public class LabOnFhirActivator extends BaseModuleActivator implements Applicati public void started() { applicationContext.getAutowireCapableBeanFactory().autowireBean(this); - openElisManager.setDaemonToken(daemonToken); + lisManager.setDaemonToken(daemonToken); // subscribe to encounter creation events - if (config.isOpenElisEnabled()) { - openElisManager.enableOpenElisConnector(); + if (config.isLisEnabled()) { + lisManager.enableLisConnector(); } createFhirPatientIdentierSystem(); @@ -70,8 +69,8 @@ public void started() { @Override public void stopped() { - if (openElisManager != null) { - openElisManager.disableOpenElisConnector(); + if (lisManager != null) { + lisManager.disableLisConnector(); } log.info("Lab on FHIR Module Shut Down!"); @@ -89,19 +88,19 @@ public void setDaemonToken(DaemonToken token) { private void createFhirPatientIdentierSystem() { PatientIdentifierType pidType = patientService - .getPatientIdentifierTypeByUuid(config.getPatientIentifierUuid().trim()); + .getPatientIdentifierTypeByUuid(config.getPatientIdentifierUuid().trim()); Optional existingIdSystem = fhirPatientIdentifierSystemService .getFhirPatientIdentifierSystem(pidType); if (existingIdSystem.isPresent()) { existingIdSystem.get().setPatientIdentifierType(pidType); - existingIdSystem.get().setUrl(config.getLisIentifierSystemUrl().trim()); + existingIdSystem.get().setUrl(config.getLisIdentifierSystemUrl().trim()); fhirPatientIdentifierSystemService.saveFhirPatientIdentifierSystem(existingIdSystem.get()); } else { FhirPatientIdentifierSystem idSystem = new FhirPatientIdentifierSystem(); idSystem.setName("OpenLIS ID System"); idSystem.setPatientIdentifierType(pidType); - idSystem.setUrl(config.getLisIentifierSystemUrl().trim()); + idSystem.setUrl(config.getLisIdentifierSystemUrl().trim()); fhirPatientIdentifierSystemService.saveFhirPatientIdentifierSystem(idSystem); } } diff --git a/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirConfig.java b/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirConfig.java index 9cc5571..fce3b3b 100644 --- a/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirConfig.java +++ b/api/src/main/java/org/openmrs/module/labonfhir/LabOnFhirConfig.java @@ -34,9 +34,9 @@ @Configuration public class LabOnFhirConfig implements ApplicationContextAware { - public static final String GP_OPENELIS_URL = "labonfhir.openElisUrl"; + public static final String GP_LIS_URL = "labonfhir.lisUrl"; - public static final String GP_OPENELIS_USER_UUID = "labonfhir.openelisUserUuid"; + public static final String GP_LIS_USER_UUID = "labonfhir.lisUserUuid"; public static final String GP_KEYSTORE_PATH = "labonfhir.keystorePath"; @@ -48,7 +48,7 @@ public class LabOnFhirConfig implements ApplicationContextAware { public static final String GP_ACTIVATE_FHIR_PUSH = "labonfhir.activateFhirPush"; - private static final String TEMP_DEFAULT_OPENELIS_URL = "https://testapi.openelisci.org:8444/hapi-fhir-jpaserver/fhir"; + private static final String TEMP_DEFAULT_LIS_URL = "https://testapi.openelisci.org:8444/hapi-fhir-jpaserver/fhir"; public static final String GP_AUTH_TYPE = "labonfhir.authType"; @@ -58,8 +58,11 @@ public class LabOnFhirConfig implements ApplicationContextAware { public static final String GP_PATIENT_IDENTIFIER_UUID = "labonfhir.openmrsPatientIdentifier.uuid"; - public static final String GP_LIS_IDENTIFIER_SYSTEM_URL = "labonfhir.openElisIdentifierSystem.url"; + public static final String GP_LIS_IDENTIFIER_SYSTEM_URL = "labonfhir.lisIdentifierSystem.url"; + public static final String GP_ORDER_TEST_UUIDS = "labonfhir.orderTestUuids"; + + public static final String GP_LAB_UPDATE_TRIGGER_OBJECT = "labonfhir.labUpdateTriggerObject"; public enum AuthType{ SSL, BASIC @@ -100,12 +103,12 @@ public SSLContext sslContext() throws Exception { return sslContextBuilder.build(); } - public String getOpenElisUrl() { + public String getLisUrl() { //return GP_OPENELIS_URL - String url = administrationService.getGlobalProperty(GP_OPENELIS_URL); + String url = administrationService.getGlobalProperty(GP_LIS_URL); if(StringUtils.isBlank(url)) { - url = TEMP_DEFAULT_OPENELIS_URL; + url = TEMP_DEFAULT_LIS_URL; } return url; @@ -116,26 +119,33 @@ public Boolean getActivateFhirPush() { return Boolean.valueOf(activatePush); } - public String getOpenElisUserUuid() { - return administrationService.getGlobalProperty(GP_OPENELIS_USER_UUID); + public String getLisUserUuid() { + return administrationService.getGlobalProperty(GP_LIS_USER_UUID); } - public String getOpenElisUserName() { + public String getLisUserName() { return administrationService.getGlobalProperty(GP_USER_NAME); } - public String getOpenElisPassword() { + public String getLisPassword() { return administrationService.getGlobalProperty(GP_PASSWORD); } - public String getPatientIentifierUuid() { + public String getPatientIdentifierUuid() { return administrationService.getGlobalProperty(GP_PATIENT_IDENTIFIER_UUID ,"05a29f94-c0ed-11e2-94be-8c13b969e334"); } - public String getLisIentifierSystemUrl() { + public String getLisIdentifierSystemUrl() { return administrationService.getGlobalProperty(GP_LIS_IDENTIFIER_SYSTEM_URL ,"http://openelis-global.org/pat_nationalId"); } + public String getOrderTestUuids() { + return administrationService.getGlobalProperty(GP_ORDER_TEST_UUIDS, "160046AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,165254AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + } + + public String getLabUpdateTriggerObject() { + return administrationService.getGlobalProperty(GP_LAB_UPDATE_TRIGGER_OBJECT, "Encounter"); + } public AuthType getAuthType() { String authTypeGp = administrationService.getGlobalProperty(GP_AUTH_TYPE); switch (authTypeGp.toUpperCase()) { @@ -148,12 +158,12 @@ public AuthType getAuthType() { } } - public boolean isOpenElisEnabled() { - return StringUtils.isNotBlank(getOpenElisUrl()); + public boolean isLisEnabled() { + return StringUtils.isNotBlank(getLisUrl()); } - public Practitioner getOpenElisPractitioner() { - return practitionerService.get(getOpenElisUserUuid()); + public Practitioner getLisPractitioner() { + return practitionerService.get(getLisUserUuid()); } private KeyStore loadKeystore(String filePath) { diff --git a/api/src/main/java/org/openmrs/module/labonfhir/api/OpenElisFhirOrderHandler.java b/api/src/main/java/org/openmrs/module/labonfhir/api/LabOrderHandler.java similarity index 50% rename from api/src/main/java/org/openmrs/module/labonfhir/api/OpenElisFhirOrderHandler.java rename to api/src/main/java/org/openmrs/module/labonfhir/api/LabOrderHandler.java index 265d3cc..b3283bd 100644 --- a/api/src/main/java/org/openmrs/module/labonfhir/api/OpenElisFhirOrderHandler.java +++ b/api/src/main/java/org/openmrs/module/labonfhir/api/LabOrderHandler.java @@ -1,15 +1,17 @@ package org.openmrs.module.labonfhir.api; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import org.hl7.fhir.r4.model.Practitioner; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Task; import org.openmrs.Encounter; import org.openmrs.EncounterProvider; +import org.openmrs.Obs; import org.openmrs.Order; import org.openmrs.api.db.DAOException; import org.openmrs.module.fhir2.FhirConstants; @@ -20,14 +22,74 @@ import org.springframework.stereotype.Component; @Component -public class OpenElisFhirOrderHandler { - +public class LabOrderHandler { + @Autowired private LabOnFhirConfig config; - + @Autowired private FhirTaskService taskService; - + + public Task createOrder(Order order) throws OrderCreationException { + //TDO: MAKE THIS A GLOBAL CONFIG + final String REQUIRED_TESTS_UUIDS = config.getOrderTestUuids(); // GeneXpert + // Exit if Test Order doesn't contain required tests + boolean mappedTestsExist = false; + for (Obs obs : order.getEncounter().getObs()) { + if (Arrays.stream(REQUIRED_TESTS_UUIDS.split(",")).anyMatch(s -> s.equals(obs.getConcept().getUuid()) + || (obs.getValueCoded() != null && s.equals(obs.getValueCoded().getUuid())))) { + mappedTestsExist = true; + } + } + + if (!mappedTestsExist) { + return null; + } + // Create References + List basedOnRefs = Collections.singletonList( + newReference(order.getUuid(), FhirConstants.SERVICE_REQUEST)); + + Reference forReference = newReference(order.getPatient().getUuid(), FhirConstants.PATIENT); + + Reference ownerRef = newReference(config.getLisUserUuid(), FhirConstants.PRACTITIONER); + + Reference encounterRef = newReference(order.getEncounter().getUuid(), FhirConstants.ENCOUNTER); + + Optional requesterProvider = order.getEncounter().getActiveEncounterProviders().stream() + .findFirst(); + + Reference requesterRef = requesterProvider.map( + encounterProvider -> newReference(encounterProvider.getUuid(), FhirConstants.PRACTITIONER)).orElse(null); + + // Create Task Resource for given Order + Task newTask = createTask(basedOnRefs, forReference, ownerRef, encounterRef); + + if (order.getEncounter().getActiveEncounterProviders().isEmpty()) { + newTask.setRequester(requesterRef); + } + + // Save the new Task Resource + try { + newTask = taskService.create(newTask); + } + catch (DAOException e) { + throw new OrderCreationException("Exception occurred while creating task for order " + order.getId()); + } + return newTask; + } + + private Task createTask(List basedOnRefs, Reference forReference, Reference ownerRef, + Reference encounterRef) { + Task newTask = new Task(); + newTask.setStatus(Task.TaskStatus.REQUESTED); + newTask.setIntent(Task.TaskIntent.ORDER); + newTask.setBasedOn(basedOnRefs); + newTask.setFor(forReference); + newTask.setOwner(ownerRef); + newTask.setEncounter(encounterRef); + return newTask; + } + public Task createOrder(Encounter encounter) throws OrderCreationException { if (encounter.getOrders().isEmpty()) { return null; @@ -36,37 +98,33 @@ public Task createOrder(Encounter encounter) throws OrderCreationException { List basedOnRefs = encounter.getOrders().stream().map(order -> { AtomicReference orders = new AtomicReference<>(); orders.set(order); - + if (orders.get() != null) { return newReference(orders.get().getUuid(), FhirConstants.SERVICE_REQUEST); } else { return null; } }).collect(Collectors.toList()); - + Reference forReference = newReference(encounter.getPatient().getUuid(), FhirConstants.PATIENT); - - Reference ownerRef = newReference(config.getOpenElisUserUuid(), FhirConstants.PRACTITIONER); - + + Reference ownerRef = newReference(config.getLisUserUuid(), FhirConstants.PRACTITIONER); + Reference encounterRef = newReference(encounter.getUuid(), FhirConstants.ENCOUNTER); Reference locationRef = newReference(encounter.getLocation().getUuid(), FhirConstants.LOCATION); Optional requesterProvider = encounter.getActiveEncounterProviders().stream().findFirst(); - Reference requesterRef = requesterProvider.isPresent() ? newReference(requesterProvider.get().getUuid(), FhirConstants.PRACTITIONER) : null; - + Reference requesterRef = requesterProvider.isPresent() ? + newReference(requesterProvider.get().getUuid(), FhirConstants.PRACTITIONER) : + null; + // Create Task Resource for given Order - Task newTask = new Task(); - newTask.setStatus(Task.TaskStatus.REQUESTED); - newTask.setIntent(Task.TaskIntent.ORDER); - newTask.setBasedOn(basedOnRefs); - newTask.setFor(forReference); - newTask.setOwner(ownerRef); - newTask.setEncounter(encounterRef); + Task newTask = createTask(basedOnRefs, forReference, ownerRef, encounterRef); newTask.setLocation(locationRef); - if(!encounter.getActiveEncounterProviders().isEmpty()){ + if (!encounter.getActiveEncounterProviders().isEmpty()) { newTask.setRequester(requesterRef); } @@ -79,9 +137,9 @@ public Task createOrder(Encounter encounter) throws OrderCreationException { } return newTask; } - + private Reference newReference(String uuid, String type) { return new Reference().setReference(type + "/" + uuid).setType(type); } - + } diff --git a/api/src/main/java/org/openmrs/module/labonfhir/api/LabOrderManager.java b/api/src/main/java/org/openmrs/module/labonfhir/api/LabOrderManager.java new file mode 100644 index 0000000..ea94b03 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/labonfhir/api/LabOrderManager.java @@ -0,0 +1,94 @@ +package org.openmrs.module.labonfhir.api; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.commons.lang.StringUtils; +import org.openmrs.Encounter; +import org.openmrs.GlobalProperty; +import org.openmrs.Order; +import org.openmrs.api.GlobalPropertyListener; +import org.openmrs.event.Event; +import org.openmrs.module.DaemonToken; +import org.openmrs.module.labonfhir.LabOnFhirConfig; +import org.openmrs.module.labonfhir.api.event.EncounterCreationListener; +import org.openmrs.module.labonfhir.api.event.OrderCreationListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class LabOrderManager implements GlobalPropertyListener { + + private static final Logger log = LoggerFactory.getLogger(LabOrderManager.class); + + public void setDaemonToken(DaemonToken daemonToken) { + this.daemonToken = daemonToken; + } + + private DaemonToken daemonToken; + + @Autowired + private LabOnFhirConfig config; + + @Autowired + private EncounterCreationListener encounterListener; + + @Autowired + private OrderCreationListener orderListener; + + private final AtomicBoolean isRunning = new AtomicBoolean(false); + + @Override + public boolean supportsPropertyName(String propertyName) { + return LabOnFhirConfig.GP_LIS_URL.equals(propertyName); + } + + @Override + public void globalPropertyChanged(GlobalProperty newValue) { + log.trace("Notified of change to property {}", LabOnFhirConfig.GP_LIS_URL); + + if (StringUtils.isNotBlank((String) newValue.getValue())) { + enableLisConnector(); + } else { + disableLisConnector(); + } + } + + @Override + public void globalPropertyDeleted(String propertyName) { + disableLisConnector(); + } + + public void enableLisConnector() { + log.info("Enabling LIS FHIR Connector for "+config.getLabUpdateTriggerObject()); + if(config.getLabUpdateTriggerObject().equals("Encounter")) { + encounterListener.setDaemonToken(daemonToken); + + if (!isRunning.get()) { + Event.subscribe(Encounter.class, Event.Action.CREATED.toString(), encounterListener); + } + } else if(config.getLabUpdateTriggerObject().equals("Order")) { + orderListener.setDaemonToken(daemonToken); + + if (!isRunning.get()) { + Event.subscribe(Order.class, Event.Action.CREATED.toString(), orderListener); + } + } else { + log.error("Could not enable LIS connection, invalid trigger object: " + config.getLabUpdateTriggerObject()); + return; + } + + isRunning.set(true); + } + + public void disableLisConnector() { + log.info("Disabling LIS FHIR Connector"); + if (isRunning.get() && config.getLabUpdateTriggerObject().equals("Order")) { + Event.unsubscribe(Order.class, Event.Action.CREATED, orderListener); + } else if (isRunning.get() && config.getLabUpdateTriggerObject().equals("Encounter")) { + Event.unsubscribe(Encounter.class, Event.Action.CREATED, encounterListener); + } + isRunning.set(false); + } +} diff --git a/api/src/main/java/org/openmrs/module/labonfhir/api/OpenElisManager.java b/api/src/main/java/org/openmrs/module/labonfhir/api/OpenElisManager.java deleted file mode 100644 index 09ddbf2..0000000 --- a/api/src/main/java/org/openmrs/module/labonfhir/api/OpenElisManager.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.openmrs.module.labonfhir.api; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.commons.lang.StringUtils; -import org.openmrs.Encounter; -import org.openmrs.GlobalProperty; -import org.openmrs.api.GlobalPropertyListener; -import org.openmrs.event.Event; -import org.openmrs.module.DaemonToken; -import org.openmrs.module.labonfhir.LabOnFhirConfig; -import org.openmrs.module.labonfhir.api.event.EncounterCreationListener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class OpenElisManager implements GlobalPropertyListener { - - private static final Logger log = LoggerFactory.getLogger(OpenElisManager.class); - - public void setDaemonToken(DaemonToken daemonToken) { - this.daemonToken = daemonToken; - } - - private DaemonToken daemonToken; - - @Autowired - private EncounterCreationListener encounterListener; - - private final AtomicBoolean isRunning = new AtomicBoolean(false); - - @Override - public boolean supportsPropertyName(String propertyName) { - return LabOnFhirConfig.GP_OPENELIS_URL.equals(propertyName); - } - - @Override - public void globalPropertyChanged(GlobalProperty newValue) { - log.trace("Notified of change to property {}", LabOnFhirConfig.GP_OPENELIS_URL); - - if (StringUtils.isNotBlank((String) newValue.getValue())) { - enableOpenElisConnector(); - } else { - disableOpenElisConnector(); - } - } - - @Override - public void globalPropertyDeleted(String propertyName) { - disableOpenElisConnector(); - } - - public void enableOpenElisConnector() { - log.info("Enabling OpenElis FHIR Connector"); - - encounterListener.setDaemonToken(daemonToken); - - if (!isRunning.get()) { - Event.subscribe(Encounter.class, Event.Action.CREATED.toString(), encounterListener); - } - isRunning.set(true); - } - - public void disableOpenElisConnector() { - log.info("Disabling OpenElis FHIR Connector"); - if (isRunning.get()) { - Event.unsubscribe(Encounter.class, Event.Action.CREATED, encounterListener); - } - isRunning.set(false); - } -} diff --git a/api/src/main/java/org/openmrs/module/labonfhir/api/event/EncounterCreationListener.java b/api/src/main/java/org/openmrs/module/labonfhir/api/event/EncounterCreationListener.java index 09c911e..afb7348 100644 --- a/api/src/main/java/org/openmrs/module/labonfhir/api/event/EncounterCreationListener.java +++ b/api/src/main/java/org/openmrs/module/labonfhir/api/event/EncounterCreationListener.java @@ -25,7 +25,7 @@ import org.openmrs.event.EventListener; import org.openmrs.module.DaemonToken; import org.openmrs.module.labonfhir.LabOnFhirConfig; -import org.openmrs.module.labonfhir.api.OpenElisFhirOrderHandler; +import org.openmrs.module.labonfhir.api.LabOrderHandler; import org.openmrs.module.labonfhir.api.fhir.OrderCreationException; import ca.uhn.fhir.rest.api.server.IBundleProvider; @@ -39,56 +39,14 @@ import org.springframework.stereotype.Component; @Component("labEncounterListener") -public class EncounterCreationListener implements EventListener { - - private static final Logger log = LoggerFactory.getLogger(EncounterCreationListener.class); - - public DaemonToken getDaemonToken() { - return daemonToken; - } - - public void setDaemonToken(DaemonToken daemonToken) { - this.daemonToken = daemonToken; - } - - private DaemonToken daemonToken; - - @Autowired - private IGenericClient client; - - @Autowired - private LabOnFhirConfig config; - +public class EncounterCreationListener extends LabCreationListener { + private static final Logger log = LoggerFactory.getLogger(OrderCreationListener.class); @Autowired private EncounterService encounterService; - - @Autowired - private OpenElisFhirOrderHandler handler; - - @Autowired - private FhirTaskService fhirTaskService; @Autowired - FhirLocationService fhirLocationService ; - - @Autowired - @Qualifier("fhirR4") - private FhirContext ctx; - - @Override - public void onMessage(Message message) { - log.trace("Received message {}", message); - - Daemon.runInDaemonThread(() -> { - try { - processMessage(message); - } - catch (Exception e) { - log.error("Failed to update the user's last viewed patients property", e); - } - }, daemonToken); - } - + private LabOrderHandler handler; + public void processMessage(Message message) { if (message instanceof MapMessage) { MapMessage mapMessage = (MapMessage) message; @@ -117,20 +75,14 @@ public void processMessage(Message message) { // this is written this way so we can solve whether we can handle this encounter // in one pass through the Obs - boolean openElisOrder = true; + boolean lisOrder = true; boolean testOrder = true; - if (openElisOrder && testOrder) { + if (lisOrder && testOrder) { log.trace("Found order(s) for encounter {}", encounter); try { Task task = handler.createOrder(encounter); - if (task != null) { - if (config.getActivateFhirPush()) { - Bundle labBundle = createLabBundle(task); - client.transaction().withBundle(labBundle).execute(); - log.debug(ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(labBundle)); - } - } + sendTask(task); } catch (OrderCreationException e) { log.error("An exception occurred while trying to create the order for encounter {}", encounter, e); } @@ -139,31 +91,4 @@ public void processMessage(Message message) { } } } - - private Bundle createLabBundle(Task task) { - TokenAndListParam uuid = new TokenAndListParam().addAnd(new TokenParam(task.getIdElement().getIdPart())); - HashSet includes = new HashSet<>(); - includes.add(new Include("Task:patient")); - includes.add(new Include("Task:owner")); - includes.add(new Include("Task:encounter")); - includes.add(new Include("Task:based-on")); - - IBundleProvider labBundle = fhirTaskService.searchForTasks(null, null, null, uuid, null, null, includes); - - Bundle transactionBundle = new Bundle(); - transactionBundle.setType(Bundle.BundleType.TRANSACTION); - List labResources = labBundle.getAllResources(); - if (!task.getLocation().isEmpty()) { - labResources.add(fhirLocationService.get(FhirUtils.referenceToId(task.getLocation().getReference()).get())); - } - for (IBaseResource r : labResources) { - Resource resource = (Resource) r; - Bundle.BundleEntryComponent component = transactionBundle.addEntry(); - component.setResource(resource); - component.getRequest().setUrl(resource.fhirType() + "/" + resource.getIdElement().getIdPart()) - .setMethod(Bundle.HTTPVerb.PUT); - - } - return transactionBundle; - } } diff --git a/api/src/main/java/org/openmrs/module/labonfhir/api/event/LabCreationListener.java b/api/src/main/java/org/openmrs/module/labonfhir/api/event/LabCreationListener.java new file mode 100644 index 0000000..77ca939 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/labonfhir/api/event/LabCreationListener.java @@ -0,0 +1,119 @@ +package org.openmrs.module.labonfhir.api.event; + +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; +import java.util.HashSet; +import java.util.List; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.param.TokenParam; +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.Task; +import org.openmrs.Encounter; +import org.openmrs.api.APIException; +import org.openmrs.api.EncounterService; +import org.openmrs.api.context.Daemon; +import org.openmrs.event.EventListener; +import org.openmrs.module.DaemonToken; +import org.openmrs.module.fhir2.api.FhirLocationService; +import org.openmrs.module.fhir2.api.FhirTaskService; +import org.openmrs.module.fhir2.api.util.FhirUtils; +import org.openmrs.module.labonfhir.LabOnFhirConfig; +import org.openmrs.module.labonfhir.api.LabOrderHandler; +import org.openmrs.module.labonfhir.api.fhir.OrderCreationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +public abstract class LabCreationListener implements EventListener { + + private static final Logger log = LoggerFactory.getLogger(EncounterCreationListener.class); + + private DaemonToken daemonToken; + + @Autowired + private IGenericClient client; + + @Autowired + private LabOnFhirConfig config; + + @Autowired + @Qualifier("fhirR4") + private FhirContext ctx; + + @Autowired + FhirLocationService fhirLocationService ; + + @Autowired + private FhirTaskService fhirTaskService; + + public DaemonToken getDaemonToken() { + return daemonToken; + } + + public void setDaemonToken(DaemonToken daemonToken) { + this.daemonToken = daemonToken; + } + + @Override + public void onMessage(Message message) { + log.trace("Received message {}", message); + + Daemon.runInDaemonThread(() -> { + try { + processMessage(message); + } + catch (Exception e) { + log.error("Failed to update the user's last viewed patients property", e); + } + }, daemonToken); + } + + public abstract void processMessage(Message message); + + private Bundle createLabBundle(Task task) { + TokenAndListParam uuid = new TokenAndListParam().addAnd(new TokenParam(task.getIdElement().getIdPart())); + HashSet includes = new HashSet<>(); + includes.add(new Include("Task:patient")); + includes.add(new Include("Task:owner")); + includes.add(new Include("Task:encounter")); + includes.add(new Include("Task:based-on")); + + IBundleProvider labBundle = fhirTaskService.searchForTasks(null, null, null, uuid, null, null, includes); + + Bundle transactionBundle = new Bundle(); + transactionBundle.setType(Bundle.BundleType.TRANSACTION); + List labResources = labBundle.getAllResources(); + if (!task.getLocation().isEmpty() && config.getLabUpdateTriggerObject().equals("Encounter")) { + labResources.add(fhirLocationService.get(FhirUtils.referenceToId(task.getLocation().getReference()).get())); + } + for (IBaseResource r : labResources) { + Resource resource = (Resource) r; + Bundle.BundleEntryComponent component = transactionBundle.addEntry(); + component.setResource(resource); + component.getRequest().setUrl(resource.fhirType() + "/" + resource.getIdElement().getIdPart()) + .setMethod(Bundle.HTTPVerb.PUT); + + } + return transactionBundle; + } + + protected void sendTask(Task task) { + if (task != null) { + if (config.getActivateFhirPush()) { + Bundle labBundle = createLabBundle(task); + client.transaction().withBundle(labBundle).execute(); + log.debug(ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(labBundle)); + } + } + } +} diff --git a/api/src/main/java/org/openmrs/module/labonfhir/api/event/OrderCreationListener.java b/api/src/main/java/org/openmrs/module/labonfhir/api/event/OrderCreationListener.java new file mode 100644 index 0000000..4aa1916 --- /dev/null +++ b/api/src/main/java/org/openmrs/module/labonfhir/api/event/OrderCreationListener.java @@ -0,0 +1,89 @@ +package org.openmrs.module.labonfhir.api.event; + +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; +import java.util.HashSet; +import java.util.List; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.param.TokenAndListParam; +import ca.uhn.fhir.rest.param.TokenParam; +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.Task; +import org.openmrs.Order; +import org.openmrs.TestOrder; +import org.openmrs.api.APIException; +import org.openmrs.api.OrderService; +import org.openmrs.api.context.Daemon; +import org.openmrs.event.EventListener; +import org.openmrs.module.DaemonToken; +import org.openmrs.module.fhir2.api.FhirTaskService; +import org.openmrs.module.labonfhir.LabOnFhirConfig; +import org.openmrs.module.labonfhir.api.LabOrderHandler; +import org.openmrs.module.labonfhir.api.fhir.OrderCreationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Component("labOrderListener") +public class OrderCreationListener extends LabCreationListener { + + private static final Logger log = LoggerFactory.getLogger(OrderCreationListener.class); + + @Autowired + private OrderService orderService; + + @Autowired + private LabOrderHandler handler; + + @Override + public void processMessage(Message message) { + if (message instanceof MapMessage) { + MapMessage mapMessage = (MapMessage) message; + + String uuid; + try { + uuid = mapMessage.getString("uuid"); + log.debug("Handling order {}", uuid); + } catch (JMSException e) { + log.error("Exception caught while trying to get order uuid for event", e); + return; + } + + if (uuid == null || StringUtils.isBlank(uuid)) { + return; + } + + Order order; + try { + order = orderService.getOrderByUuid(uuid); + log.trace("Fetched order {}", order); + } catch (APIException e) { + log.error("Exception caught while trying to load order {}", uuid, e); + return; + } + + // this is written this way so we can solve whether we can handle this order + // in one pass through the Obs + + log.trace("Found order(s) for order {}", order); + try { + if (order instanceof TestOrder) { + Task task = handler.createOrder(order); + sendTask(task); + } + } catch (OrderCreationException e) { + log.error("An exception occurred while trying to create the order for order {}", order, e); + } + } + } +} diff --git a/api/src/main/java/org/openmrs/module/labonfhir/api/scheduler/FetchTaskUpdates.java b/api/src/main/java/org/openmrs/module/labonfhir/api/scheduler/FetchTaskUpdates.java index b79cde3..b9fc53e 100644 --- a/api/src/main/java/org/openmrs/module/labonfhir/api/scheduler/FetchTaskUpdates.java +++ b/api/src/main/java/org/openmrs/module/labonfhir/api/scheduler/FetchTaskUpdates.java @@ -80,7 +80,7 @@ public void execute() { // return; } - if (!config.isOpenElisEnabled()) { + if (!config.isLisEnabled()) { return; } @@ -110,7 +110,7 @@ private void updateTasksInBundle(Bundle taskBundle) { String openmrsTaskUuid = null; try { - // Read incoming OpenElis task + // Read incoming LIS Task Task openelisTask = (Task) ((Bundle.BundleEntryComponent) tasks.next()).getResource(); openmrsTaskUuid = openelisTask.getIdentifierFirstRep().getValue(); diff --git a/api/src/main/resources/moduleApplicationContext.xml b/api/src/main/resources/moduleApplicationContext.xml index db76d93..fcff32e 100644 --- a/api/src/main/resources/moduleApplicationContext.xml +++ b/api/src/main/resources/moduleApplicationContext.xml @@ -15,7 +15,7 @@ - + diff --git a/api/src/test/java/org/openmrs/module/labonfhir/api/OpenElisFhirOrderHandlerTest.java b/api/src/test/java/org/openmrs/module/labonfhir/api/LabOrderHandlerTest.java similarity index 73% rename from api/src/test/java/org/openmrs/module/labonfhir/api/OpenElisFhirOrderHandlerTest.java rename to api/src/test/java/org/openmrs/module/labonfhir/api/LabOrderHandlerTest.java index f4adbd6..942ea9d 100644 --- a/api/src/test/java/org/openmrs/module/labonfhir/api/OpenElisFhirOrderHandlerTest.java +++ b/api/src/test/java/org/openmrs/module/labonfhir/api/LabOrderHandlerTest.java @@ -1,11 +1,9 @@ package org.openmrs.module.labonfhir.api; -import static org.junit.Assert.*; - import org.junit.Before; import org.junit.Test; -public class OpenElisFhirOrderHandlerTest { +public class LabOrderHandlerTest { @Before public void setUp() throws Exception { diff --git a/omod/src/main/resources/config.xml b/omod/src/main/resources/config.xml index 5c8a073..877cb91 100644 --- a/omod/src/main/resources/config.xml +++ b/omod/src/main/resources/config.xml @@ -51,13 +51,13 @@ - @MODULE_ID@.openElisUrl - The URL for the OpenELIS system to communicate with + @MODULE_ID@.lisUrl + The URL for an LIS system like OpenELIS system to communicate with http://172.17.0.1:8081/fhir - @MODULE_ID@.openElisUserUuid - UUID for the service user that represents OpenELIS + @MODULE_ID@.lisUserUuid + UUID for the service user that represents a LIS like OpenELIS f9badd80-ab76-11e2-9e96-0800200c9a66 @@ -107,8 +107,20 @@ - @MODULE_ID@.openElisIdentifierSystem.url - OpenElis Identifier System url + @MODULE_ID@.lisIdentifierSystem.url + LIS Identifier System url http://openelis-global.org/pat_nationalId - \ No newline at end of file + + + @MODULE_ID@.orderTestUuids + Concept UUIDs to filter by for Test Orders that get sent to the LIS + 160046AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,165254AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + + + + @MODULE_ID@.labUpdateTriggerObject + The OpenMRS object type that should trigger LIS synchronization - either Encounter or Order. + Encounter + + diff --git a/pom.xml b/pom.xml index 7467da5..da9de80 100644 --- a/pom.xml +++ b/pom.xml @@ -225,7 +225,7 @@ - 1.2.1 + 1.3.0-SNAPSHOT 1.6.0 1.8 1.8