AOP after advice to void Lab Tests when OpenMRS Order is voided

spring-aop
Tags: #<Tag:0x00007f23d5316ac8>

(Tahira Niazi) #1

Hi,

I need to implement after AOP advice to void module entities like Lab Tests when ever OpenMRS Order entity is voided. (Our module entity Lab Test has a one to one mapping to OpenMRS Orders entity.) In OpenMRS, whenever an encounter is voided, its all linked Orders are also voided and this will eventually trigger voidOrder(…) method. Therefore, I’m implementing After advice on “voidOrder” method. And this does not work.

<!--  APO Support -->
<advice>
	<point>org.openmrs.api.OrderService</point>
	<class>org.openmrs.module.commonlabtest.aop.AfterOrderVoidAdvice</class>
</advice>

I have written advice as below by implementing AfterReturningAdvice.

public class AfterOrderVoidAdvice implements AfterReturningAdvice {

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

/*
 * (non-Javadoc) * @see
 * org.springframework.aop.AfterReturningAdvice#afterReturning(java.lang.Object,
 * java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
 * 
 * depends on org.openmrs.api.impl.OrderServiceImpl
 */
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

	log.info("======== in After Advice " + method.getName() + "========");

	if (method.getName().equalsIgnoreCase("voidOrder")) {

		log.info("<<<<<<<  Method: " + method.getName() + ". After advice called. >>>>>>>>");

		if (returnValue != null)
			log.info(returnValue.toString());

	}
}

When I replace the point with EncounterService, it works but setting point to OrderService does not invoke advice.

Can anyone please suggest how to solve this problem?

@dkayiwa @darius


(Suthagar Kailayapathy) #2

Can you make sure that the encounters have unvoided orders while your are pointing to OrderService? OrderService.voidOrder() will be called if there are any unvoided orders for encounter - See here


(Tahira Niazi) #3

Yes, I have made this sure by searching for the encounters records in database which have unvoided Orders, but it does not work.


(Tahira Niazi) #4

@dkayiwa @darius @wyclif Please help me resolve this issue. Its quite weird that the same advice works for Encounter Service (method name: saveEncounter) but not for OrderService (method name: voidOrder)?


(Daniel Kayiwa) #5

Which version of the OpenMRS platform are you running?


(Tahira Niazi) #6

it’s 2.1.2


(Daniel Kayiwa) #7

Can you run in debug mode and tell us what happens at the point that @suthagar23 mentioned above?


(Tahira Niazi) #8

I’m actually unable to debug module api, I have set the configuration settings as localhost and port 1045 which I specified while setting up OpenMRS SDK server.

This Aspect class is added to module api project


(Tahira Niazi) #9

I’m now able to debug module api but it does not go in openmrs-api code although I have set a break point in EncounterService class.


(Daniel Kayiwa) #10

Do you have unit tests for this?


(Tahira Niazi) #11

@dkayiwa I have verified that it never executes the line which @suthagar23 had pointed earlier.

Now, my question at this point is how does Encounter object holds orders that have already voided properties set to true? Is there an AOP implemented? @dkayiwa can you please explain why it has all linked orders already voided?

I have also tried to set the advice to saveEncounter method, and then checking the orders on returned Encounter object that if they are voided or not. But in this scenario, the sequence is a problem. If I void encounter, it first fetches the already voided orders and then executes the advice which is obviously something which is not required.

@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

	log.info("======== in After Advice " + method.getName() + "========");

	if (method.getName().equalsIgnoreCase("saveEncounter")) {
		if (returnValue != null) {
			
			Encounter encounter = (Encounter) returnValue;
			Set<Order> orders = (Set<Order>) encounter.getOrders();

			for (Order o : orders) {
				if (!o.isVoided())
					log.info(" ==== > Order # " + o.getOrderId() + " is voided.");
				// void corresponding LabTest entity that has one to one mapping to this Order
			}
		}

	}
}

thanks for you support!


(Tahira Niazi) #12

No, I don’t have…


(Daniel Kayiwa) #13

Can you set up such a test? Here are examples of tests for AOP: https://github.com/openmrs/openmrs-module-locationbasedaccess/tree/master/api/src/test/java/org/openmrs/module/locationbasedaccess/aop


(Suthagar Kailayapathy) #14

@tahira Can you push your code to GitHub and share with us? It’s hard to find the issues with a short part of code.


(Tahira Niazi) #15

My problem is solved. I have implemented Advice on voidEncounter and unvoidEncounter methods. I am catching the returned encounter and fetching its orders and I’m then able to void/unvoid Lab Test objects that are mapped to those OpenMRS Order objects.

Thanks @dkayiwa and @suthagar23 for your continuous support.


(Tahira Niazi) #16

@dkayiwa Unit Tests can be found here: https://github.com/tahiraniazi/openmrs-module-commonlabtest/tree/CLM-1/api/src/test/java/org/openmrs/module/commonlabtest/aop