Skip to content

Commit

Permalink
Bindu | Add advice to send event for visit create/update (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
binduak authored Nov 28, 2023
1 parent 8b30205 commit 1bd9b03
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.bahmni.module.events.api.listener;

import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bahmni.module.events.api.model.BahmniEventType;
import org.bahmni.module.events.api.model.Event;
import org.bahmni.module.events.api.publisher.BahmniEventPublisher;
import org.openmrs.Encounter;
import org.openmrs.Visit;
import org.openmrs.api.context.Context;
import org.openmrs.module.webservices.rest.web.ConversionUtil;
import org.openmrs.module.webservices.rest.web.representation.Representation;
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.events.api.model.BahmniEventType.BAHMNI_VISIT_CREATED;
import static org.bahmni.module.events.api.model.BahmniEventType.BAHMNI_VISIT_UPDATED;


public class VisitAdvice implements AfterReturningAdvice, MethodBeforeAdvice {
private final Logger log = LogManager.getLogger(EncounterAdvice.class);

private final BahmniEventPublisher eventPublisher;
private final ThreadLocal<Map<String,Integer>> threadLocal = new ThreadLocal<>();
private final String VISIT_ID_KEY = "visitId";
private final Set<String> adviceMethodNames = Sets.newHashSet("saveVisit");

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

@Override
public void afterReturning(Object returnValue, Method method, Object[] arguments, Object target) {
if (adviceMethodNames.contains(method.getName())) {
Map<String, Integer> visitInfo = threadLocal.get();
// TODO: This is a workaround to avoid publishing duplicate events because currently the event is getting called twice. Need to find out the reason and resolve it.
if (visitInfo != null) {
BahmniEventType eventType = visitInfo.get(VISIT_ID_KEY) == null ? BAHMNI_VISIT_CREATED : BAHMNI_VISIT_UPDATED;
threadLocal.remove();
Visit visit = (Visit) returnValue;

Object representation = ConversionUtil.convertToRepresentation(visit, Representation.FULL);
Event event = new Event(eventType, representation, visit.getUuid());
eventPublisher.publishEvent(event);

System.out.println("Successfully published event with uuid : " + visit.getUuid());
}
}
}

@Override
public void before(Method method, Object[] objects, Object o) {
if (adviceMethodNames.contains(method.getName())) {
Visit visit = (Visit) objects[0];
Map<String, Integer> visitInfo = new HashMap<>(1);
visitInfo.put(VISIT_ID_KEY, visit.getId());
threadLocal.set(visitInfo);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ public enum BahmniEventType {
BAHMNI_PATIENT_CREATED("bahmni-patient"),
BAHMNI_PATIENT_UPDATED("bahmni-patient"),
BAHMNI_APPOINTMENT_CREATED("bahmni-appointment"),
BAHMNI_APPOINTMENT_UPDATED("bahmni-appointment"),
BAHMNI_ENCOUNTER_CREATED("bahmni-encounter"),
BAHMNI_ENCOUNTER_UPDATED("bahmni-encounter");
BAHMNI_APPOINTMENT_UPDATED("bahmni-appointment"),
BAHMNI_ENCOUNTER_UPDATED("bahmni-encounter"),
BAHMNI_VISIT_CREATED("bahmni-visit"),
BAHMNI_VISIT_UPDATED("bahmni-visit");


private final String topic;
BahmniEventType(String topic) {
Expand All @@ -16,4 +19,4 @@ public enum BahmniEventType {
public String topic() {
return topic;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.bahmni.module.events.api.listener;

import org.bahmni.module.events.api.model.BahmniEventType;
import org.bahmni.module.events.api.model.Event;
import org.bahmni.module.events.api.publisher.BahmniEventPublisher;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.openmrs.Encounter;
import org.openmrs.Visit;
import org.openmrs.api.EncounterService;
import org.openmrs.api.VisitService;
import org.openmrs.module.webservices.rest.web.ConversionUtil;
import org.openmrs.module.webservices.rest.web.representation.Representation;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.lang.reflect.Method;
import java.util.UUID;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@PowerMockIgnore("javax.management.*")
@PrepareForTest({ ConversionUtil.class })
@RunWith(PowerMockRunner.class)
public class VisitAdviceTest {
private VisitAdvice visitAdvice;
private BahmniEventPublisher bahmniEventPublisher;

private final String VISIT_SAVE_METHOD_NAME = "saveVisit";

@Before
public void setUp() {
bahmniEventPublisher = mock(BahmniEventPublisher.class);
visitAdvice = new VisitAdvice(bahmniEventPublisher);
}

@Test
public void shouldVerifyBahmniEventPublishIsCalledGivenVisitIsCreated() throws NoSuchMethodException {
Method saveVisitMethod = VisitService.class.getMethod(VISIT_SAVE_METHOD_NAME, Visit.class);
Visit newVisit = getVisit();
PowerMockito.mockStatic(ConversionUtil.class);
Object[] args = {newVisit};
newVisit.setId(null);
visitAdvice.before(saveVisitMethod, args, null);
PowerMockito.when(ConversionUtil.convertToRepresentation(getVisit(), Representation.FULL)).thenReturn(newVisit);

visitAdvice.afterReturning(getVisit(), saveVisitMethod, null, null);

verify(bahmniEventPublisher, times(1)).publishEvent(any(Event.class));
}

@Test
public void shouldPublishCreateEventGivenVisitIsCreated() throws NoSuchMethodException {
Method saveVisitMethod = VisitService.class.getMethod(VISIT_SAVE_METHOD_NAME, Visit.class);
Visit newVisit = getVisit();

PowerMockito.mockStatic(ConversionUtil.class);
PowerMockito.when(ConversionUtil.convertToRepresentation(getVisit(), Representation.FULL)).thenReturn(newVisit);

Object[] args = {newVisit};
newVisit.setId(null);
visitAdvice.before(saveVisitMethod, args, null);
visitAdvice.afterReturning(newVisit, saveVisitMethod, null, null);

ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
verify(bahmniEventPublisher, times(1)).publishEvent(eventArgumentCaptor.capture());

Event event = eventArgumentCaptor.getValue();
assertEquals(BahmniEventType.BAHMNI_VISIT_CREATED, event.eventType);
}

@Test
public void shouldPublishUpdateEventGivenVisitIsUpdated() throws NoSuchMethodException {
Method saveVisitMethod = VisitService.class.getMethod(VISIT_SAVE_METHOD_NAME, Visit.class);
Visit newVisit = getVisit();

PowerMockito.mockStatic(ConversionUtil.class);

PowerMockito.when(ConversionUtil.convertToRepresentation(getVisit(), Representation.FULL)).thenReturn(newVisit);

Object[] args = {newVisit};
visitAdvice.before(saveVisitMethod, args, null);
visitAdvice.afterReturning(newVisit, saveVisitMethod, null, null);

ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
verify(bahmniEventPublisher, times(1)).publishEvent(eventArgumentCaptor.capture());

Event event = eventArgumentCaptor.getValue();
assertEquals(BahmniEventType.BAHMNI_VISIT_UPDATED, event.eventType);
}

@Test
public void shouldVerifyPublishedContentForAVisit() throws NoSuchMethodException {
Method saveVisitMethod = VisitService.class.getMethod(VISIT_SAVE_METHOD_NAME, Visit.class);
Visit newVisit = getVisit();

PowerMockito.mockStatic(ConversionUtil.class);
PowerMockito.when(ConversionUtil.convertToRepresentation(getVisit(), Representation.FULL)).thenReturn(newVisit);

Object[] args = {newVisit};
visitAdvice.before(saveVisitMethod, args, null);
visitAdvice.afterReturning(newVisit, saveVisitMethod, null, null);

ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
verify(bahmniEventPublisher, times(1)).publishEvent(eventArgumentCaptor.capture());

Event event = eventArgumentCaptor.getValue();
assertEquals(BahmniEventType.BAHMNI_VISIT_UPDATED, event.eventType);
assertEquals(newVisit.getUuid(), event.payloadId);
}

private Visit getVisit() {
Visit visit = new Visit();
visit.setUuid(UUID.randomUUID().toString());
visit.setId(123);
return visit;
}
}
5 changes: 5 additions & 0 deletions omod/src/main/resources/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
<class>org.bahmni.module.events.api.listener.EncounterAdvice</class>
</advice>

<advice>
<point>org.openmrs.api.VisitService</point>
<class>org.bahmni.module.events.api.listener.VisitAdvice</class>
</advice>

<activator>org.bahmni.module.events.api.EventsActivator</activator>
</module>

0 comments on commit 1bd9b03

Please sign in to comment.