Aspect Oriented Programming is meant to aid programmers with cross-cutting programming concerns. Typically, you'll find AOP being used for logging, authorization, and authentication. See Wikipedia's AOP entry Aspect-oriented programming
Imagine we want to log the start and end of every method and optionally record the time it took to execute every method.
The bold lines below are extraneous and can be pulled out into an AOP method.
...(setup of AOP in external xml file)...
There are two requirements for AOP to work: 1) Your code must be operating off of an Interface instead of an actual concrete implementation class 2) You must be retrieving your objects from a central place ("no calls to 'new', aka new PersonServiceImpl());
OpenMRS uses AOP mainly for the module system to allow the core API (Services) to be extended in an infinite number of ways. Instead of only providing hooks at certain points in the code for specific uses, every service method within the API can be wrapped by a method in a module. Module services can be extended via AOP as well.
There are three ways to wrap an API method:
AOP advice is added on a class basis. Lets say we want our method to be called after the PatientService.getPatient(Integer) method. We need to first create an advice class.
This class will be wrapped around the entire PatientService class. Every API call in PatientService will now pass through our class after returning. The afterReturning method distinguishes between different method calls using the java.lang.reflect.Method class.
In order to wrap this advice class around the PatientService, we add an entry in the module's /metadata/config.xml file:
Before advice works in a very similar way. The only difference is that the org.springframework.aop.MethodBeforeAdvice interface is implemented instead of org.springframework.aop.AfterReturningAdvice.
Around advice is the most powerful type of AOP that you can do. The around advice classes need to implement org.springframework.aop.Advisor. An example of the most basic type:
Note that in this example, invocation.proceed() passes all arguments to the original service class. If you don't want the original service class methods to be called (methods starting with "get" in this example), simply omit invocation.proceed(), and return a dummy object, or you can call invocation.proceed() conditionally.
Around advice uses the same metadata in config.xml as after and before advice -- the point tag specifies which service api to wrap around, and the class tag allows you to specify your advice class (PrintingAroundAdvisor, in this case).
Also, since the spring 2.5 upgrade, make sure that your moduleApplicationContext file's basicUrlMapping has the "order" property set to a value lower than 99 (if this property ever disappears from openMRS's core basicUrlMapping, disregard this). If this is not set, advice may not be loaded properly.
Core OpenMRS code can add AOP methods around the services as well. There are methods on `Context` that add either Advice or an Advisor. (An advisor is used for 'around' AOP, and an advice object is for 'before'/'after' AOP.)
There is no existing API in the OpenMRS framework for an event bus. Therefore, to be able to publish and subscribe to events among our modules we used AOP as an event mechanism for Chica implementation. Chica implementation relies on "real time" events such as a file created in a folder or a new patient being created from a HL7 checkin.
In our use case we found soon that methods invoked using AOP are:
1. Not thread safe automatically by virtue of being called from Spring. There is no queuing mechanism at Spring level and therefore one needs to be cautious and protect with synchronized blocks to prevent data corruption from successive AOP calls.
2.If you start new worker thread(s) in the invoked AOP method, do not return from the method call after starting the threads. You need to wait for the thread(s) to finish, otherwise your spawned threads will not live.