Saturday, March 13, 2010

Grails: Intercepting Service class methods

It took me a little while to fully understand how to add some kind of interceptor to a Grails Service class and I wanted to add a blog post incase others have a similar question. After doing some research, and piecing together information from various sites I ended up with the information here. I hope it is helpful to you.

What problem am I trying to solve?
Adding interceptors to Controllers is really easy and I wanted to add some interceptors to my Service classes in a similar fashion. But it appears that you cannot do this for Service classes - just Controller classes. If I am wrong, please someone show me how best to do this.

Why am I trying to do this?
I use Flex in many of my application implementations and I use BlazeDS/AMF in many of the cases. I needed to add a security check on every exposed Flex service.

How did I do this?
In my service class I added a custom property that I called 'secureService'. But as you will see you can use anything.

 class TeslaService {  
boolean transactional = true
// secureService is a custom property that is looked for in the BootStrap.groovy file and if
// found in a ServiceClass, then it modifies the invokeMethod to add some code before and
// after the call.
boolean secureService = true
def serviceMethod() {
println 'Tesla Service Method called'
}
}


Next I updated my BootStrap.groovy file and for each ServiceClass, checked for the 'secureService' property being set to true. If it was, I then used the MetaClass InvokeMethod and assigned a new closure that could add a security check.

The updated bootstrap file looked like the following:
 class BootStrap {  
def grailsApplication
def init = { servletContext ->
grailsApplication.serviceClasses.each {
def isSecured = it.getPropertyValue('secureService')
if( isSecured ) {
// example of how to 'intercept' service classes.
it.metaClass.invokeMethod = { name, args ->
println '''SECURE before $name'''
def res = delegate.metaClass.getMetaMethod(name,args).invoke( delegate, args)
println '''SECURE after $name. res=$res'''
res
}
}
}
}
def destroy = {
}
}


To test this I created an Integration test. This test looked like the following:

 class TeslaServiceIntegrationTests extends GrailsUnitTestCase {  
def teslaService
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testServiceMethod() {
teslaService.serviceMethod()
}
}


The output of this was the following:
SECURE before serviceMethod
Tesla Service Method called
SECURE after serviceMethod. res=null

Some of the links that I used are below as the information from these posts might also be helpful to you.

http://www.pubbs.net/grails/201001/9868/
http://mrhaki.blogspot.com/2010/01/grails-goodness-access-grails.html
http://www.grails.org/doc/latest/api/org/codehaus/groovy/grails/commons/ClassPropertyFetcher.html

2 comments:

Unknown said...

Does that work when called from Flex? Because I'm trying to get exactly the same thing but it doesn't seem to work.

Patrick Ryan said...

NO - I found that this does not work for flex services either. see the part3 post on intercepting flex services which I did get to work