Monday, August 16, 2010

Implementing AOP in Grails Services via Groovy's GroovyInterceptable interface

Groovy provides Aspect Oriented Programming construct via GroovyInterceptable interface. The concept is as simple as implementing GroovyInterceptable interface and providing a definition for Object invokeMethod(String name, Object args) method as shown below.
class GenericService implements GroovyInterceptable {

boolean transactional = true

//Logging aspect
def invokeMethod(String name, Object args){
log.info("Starting $metaClass.theClass $name $args")
def metaClass = InvokerHelper.getMetaClass(this)
def result = metaClass.invokeMethod(this, name, args)
log.info("Ending $metaClass.theClass $name")
return result
}
}
Now invokeMethod will be called when executing any function defined in GenericService class. Also, if any class extends GenericService the AOP functionality will be extended to all methods defined in it. For example:

class CarService extends GenericService {

boolean transactional = true

def getCar(String make, String model) {
if (make && !model) {
return Car.findByMake(make)
} else if (!make && model) {
return Car.findByModel(model)
} else {
return Car.findByMakeAndModel(make, model);
}
}
}
Notice that CarService extends GenericService. Now all methods in CarService have the logging aspect applied to it.

Also, if A.foo() calls B.bar() and both A and B extend GenericService then the invoke method is executed for both A.foo and B.bar.

For example:
class AnotherService extends GenericService {

boolean transactional = true

def carService

def demo() {
carService.getCar("Toyota", "Camry")
}
}

Below is the output:
INFO  [main]: ---------Test: testAnotherService start.---------
INFO [main]: Starting class com.mayabansi.demo.AnotherService demo []
INFO [main]: Starting class com.mayabansi.demo.CarService getCar [Toyota, Camry]
INFO [main]: Ending class com.mayabansi.demo.CarService getCar
INFO [main]: Ending class com.mayabansi.demo.AnotherService demo
INFO [main]: ---------Test: testAnotherService end.---------
The example code is available in GitHub: http://github.com/RaviH/GroovyAOPDemoInGrails

Comments, feedback? Let me know...