Skip to content

Commit

Permalink
Usage of communication module to send sms using events published from…
Browse files Browse the repository at this point in the history
… bahmni-core.
  • Loading branch information
anubhavBeehyv committed Sep 29, 2023
1 parent 4ea8cf6 commit fc207f9
Show file tree
Hide file tree
Showing 12 changed files with 390 additions and 5 deletions.
4 changes: 4 additions & 0 deletions bahmnicore-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@
<artifactId>joda-time</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>communication-api</artifactId>
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>bahmni-emr-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.bahmni.module.bahmnicore.events;

import org.openmrs.api.context.UserContext;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class BahmniEvent {

private static final long version = 1L;
public UserContext userContext;
public String eventId;
public BahmniEventType eventType;
public String payloadId;
public LocalDateTime publishedDateTime;

public UserContext getUserContext() {
return userContext;
}
public String getEventId() {
return eventId;
}
public BahmniEventType getEventType() {
return eventType;
}
public String getPayloadId() {
return payloadId;
}

public LocalDateTime getPublishedDateTime() {
return publishedDateTime;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.bahmni.module.bahmnicore.events;

public enum BahmniEventType {
BAHMNI_PATIENT_CREATED("bahmni-patient"),
BAHMNI_PATIENT_UPDATED("bahmni-patient"),
BAHMNI_ENCOUNTER_CREATED("bahmni-encounter"),
BAHMNI_ENCOUNTER_UPDATED("bahmni-encounter");

private final String topic;
BahmniEventType(String topic) {
this.topic = topic;
}
public String topic() {
return topic;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.bahmni.module.bahmnicore.events;

import org.openmrs.Encounter;
import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.UUID;

@Component
public class EncounterEvent extends BahmniEvent {

private Encounter encounter;

public void createEncounterEvent(BahmniEventType eventType, Encounter encounter) {
this.eventType = eventType;
this.encounter = encounter;
this.eventId = UUID.randomUUID().toString();
this.payloadId = encounter.getUuid();
this.publishedDateTime = LocalDateTime.now();
this.userContext= Context.getUserContext();
}

public Encounter getEncounter() {
return encounter;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.bahmni.module.bahmnicore.events;

import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.UUID;

@Component
public class PatientEvent extends BahmniEvent {

private Patient patient;

public void createPatientEvent(BahmniEventType eventType, Patient patient) {
this.eventType = eventType;
this.patient = patient;
this.eventId = UUID.randomUUID().toString();
this.payloadId = patient.getUuid();
this.publishedDateTime = LocalDateTime.now();
this.userContext= Context.getUserContext();
}

public Patient getPatient() {
return patient;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.bahmni.module.bahmnicore.events.advice;

import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bahmni.module.bahmnicore.events.BahmniEventType;
import org.bahmni.module.bahmnicore.events.EncounterEvent;
import org.bahmni.module.bahmnicore.events.eventPublisher.BahmniEventPublisher;
import org.openmrs.Encounter;
import org.openmrs.api.context.Context;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_ENCOUNTER_CREATED;
import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_ENCOUNTER_UPDATED;


public class EncounterAdvice implements AfterReturningAdvice, MethodBeforeAdvice {

private final Logger log = LogManager.getLogger(this.getClass());
private final BahmniEventPublisher eventPublisher;
private final EncounterEvent encounterEvent;
private final ThreadLocal<Map<String,Integer>> threadLocal = new ThreadLocal<>();
private final String ENCOUNTER_ID_KEY = "encounterId";
private final Set<String> adviceMethodNames = Sets.newHashSet("saveEncounter");

public EncounterAdvice() {
this.eventPublisher = Context.getRegisteredComponent("bahmniEventPublisher", BahmniEventPublisher.class);
this.encounterEvent = Context.getRegisteredComponent("encounterEvent", EncounterEvent.class);
}

@Override
public void afterReturning(Object returnValue, Method method, Object[] arguments, Object target) {
if (adviceMethodNames.contains(method.getName())) {
Map<String, Integer> encounterInfo = threadLocal.get();
if (encounterInfo != null) {
BahmniEventType eventType = encounterInfo.get(ENCOUNTER_ID_KEY) == null ? BAHMNI_ENCOUNTER_CREATED : BAHMNI_ENCOUNTER_UPDATED;
threadLocal.remove();

Encounter encounter = (Encounter) returnValue;
encounterEvent.createEncounterEvent(eventType, encounter);
eventPublisher.publishEvent(encounterEvent);

log.info("Successfully published event with uuid : " + encounter.getUuid());
}
}
}
@Override
public void before(Method method, Object[] objects, Object o) {
if (adviceMethodNames.contains(method.getName())) {
Encounter encounter = (Encounter) objects[0];
Map<String, Integer> encounterInfo = new HashMap<>(1);
encounterInfo.put(ENCOUNTER_ID_KEY, encounter.getId());
threadLocal.set(encounterInfo);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.bahmni.module.bahmnicore.events.advice;

import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bahmni.module.bahmnicore.events.BahmniEventType;
import org.bahmni.module.bahmnicore.events.PatientEvent;
import org.bahmni.module.bahmnicore.events.eventPublisher.BahmniEventPublisher;
import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_PATIENT_CREATED;
import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_PATIENT_UPDATED;


public class PatientAdvice implements AfterReturningAdvice, MethodBeforeAdvice {

private final Logger log = LogManager.getLogger(PatientAdvice.class);
private final BahmniEventPublisher eventPublisher;
private final ThreadLocal<Map<String,Integer>> threadLocal = new ThreadLocal<>();
private final String PATIENT_ID_KEY = "patientId";
private final PatientEvent patientEvent;
private final Set<String> adviceMethodNames = Sets.newHashSet("savePatient");

public PatientAdvice() {
this.eventPublisher = Context.getRegisteredComponent("bahmniEventPublisher", BahmniEventPublisher.class);
this.patientEvent = Context.getRegisteredComponent("patientEvent", PatientEvent.class);
}

@Override
public void afterReturning(Object returnValue, Method method, Object[] arguments, Object target) {
if (adviceMethodNames.contains(method.getName())) {
Map<String, Integer> patientInfo = threadLocal.get();
if (patientInfo != null) {
BahmniEventType eventType = patientInfo.get(PATIENT_ID_KEY) == null ? BAHMNI_PATIENT_CREATED : BAHMNI_PATIENT_UPDATED;
threadLocal.remove();

Patient patient = (Patient) returnValue;
patientEvent.createPatientEvent(eventType, patient);
eventPublisher.publishEvent(patientEvent);

log.info("Successfully published event with uuid : " + patient.getUuid());
}
}
}
@Override
public void before(Method method, Object[] objects, Object o) {
if (adviceMethodNames.contains(method.getName())) {
Patient patient = (Patient) objects[0];

Map<String, Integer> patientInfo = new HashMap<>(1);
patientInfo.put(PATIENT_ID_KEY, patient.getId());
threadLocal.set(patientInfo);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.bahmni.module.bahmnicore.events.eventListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bahmni.module.bahmnicore.events.BahmniEventType;
import org.bahmni.module.bahmnicore.events.PatientEvent;
import org.bahmni.module.communication.service.CommunicationService;
import org.bahmni.module.communication.service.MessageBuilderService;
import org.openmrs.Patient;
import org.openmrs.PersonAttribute;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.context.Context;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class PatientSmsEventListener {

private final Log log = LogFactory.getLog(this.getClass());


@Async("BahmniAsyncThreadExecutor")
@EventListener
public void onApplicationEvent(PatientEvent event) {
try {
Context.openSession();
Context.setUserContext(event.getUserContext());
if (event.getEventType() == BahmniEventType.BAHMNI_PATIENT_CREATED) {
handlePatientCreatedEvent(event.getPatient());
}
} catch(Exception e){
log.error("Exception occurred during event processing", e);
} finally{
Context.closeSession();
}
}

private void handlePatientCreatedEvent(Patient patient) {
AdministrationService administrationService = Context.getService(AdministrationService.class);
boolean patientRegistrationSMSProperty = Boolean.parseBoolean(administrationService.getGlobalProperty("sms.enableRegistrationSMSAlert","false"));
if (!patientRegistrationSMSProperty)
return;
String phoneNumber = getPhoneNumber(patient);
if (phoneNumber != null) {
MessageBuilderService messageBuilderService = Context.getRegisteredComponent("messageBuilderService", MessageBuilderService.class);
CommunicationService communicationService = Context.getRegisteredComponent("communicationService", CommunicationService.class);
String message=messageBuilderService.getRegistrationMessage(createArgumentsMapForPatientRegistration(patient));
communicationService.sendSMS(phoneNumber, message);
}
}

public Map<String, String> createArgumentsMapForPatientRegistration(Patient patient) {
String helpdeskNumber = Context.getAdministrationService().getGlobalPropertyObject("clinic.helpDeskNumber").getPropertyValue();
String clinicTime = Context.getAdministrationService().getGlobalPropertyObject("clinic.clinicTimings").getPropertyValue();
Map<String, String> arguments = new HashMap<>();
arguments.put("location", Context.getUserContext().getLocation().getName());
arguments.put("identifier", patient.getPatientIdentifier().getIdentifier());
arguments.put("patientname", patient.getGivenName() + " " + patient.getFamilyName());
arguments.put("gender", patient.getGender());
arguments.put("age", patient.getAge().toString());
arguments.put("helpdesknumber", helpdeskNumber);
arguments.put("facilitytimings", clinicTime);
return arguments;
}

private String getPhoneNumber(Patient patient) {
PersonAttribute phoneNumber = patient.getAttribute("phoneNumber");
if (phoneNumber == null) {
log.info("No mobile number found for the patient. SMS not sent.");
return null;
}
return phoneNumber.getValue();
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.bahmni.module.bahmnicore.events.eventPublisher;

import org.bahmni.module.bahmnicore.events.BahmniEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

@Component
public class BahmniEventPublisher implements ApplicationEventPublisherAware {

private ApplicationEventPublisher eventPublisher;

@Override
public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
public void publishEvent(BahmniEvent event) {
this.eventPublisher.publishEvent(event);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.bahmni.module.bahmnicore.util;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class BahmniAsyncThreadExecutor {

@Bean(name = "BahmniAsyncThreadExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
return threadPoolTaskExecutor;
}
}
Loading

0 comments on commit fc207f9

Please sign in to comment.