views:

378

answers:

2

Hi,

I have a several Grails services that are invoked from Flex code using Spring BlazeDS integration. I wanted to add some general debug logging using the groovy metaClass. I have the following in a bootstrap class:

class MyBootStrap {

def grailsApplication

def init = { servletContext ->
        initServiceCallLogging()
}

def destroy = {
}

private def initServiceCallLogging() {
    grailsApplication.serviceClasses.each { serviceClass ->
        serviceClass.metaClass.invokeMethod = { name, args ->
            log.debug "Method $name invoked"
            def metaMethod = delegate.metaClass.getMetaMethod(name, args)
            def result = metaMethod.invoke(delegate, args)
            return result

        }
    }
}
}

This works fine as long as the Service method is called from e.g. a Grails Controller or Service but when directly called from Flex (via BlazeDS), the method calls are not intercepted.

Anyone an idea how this can be solved or is this not possible via metaprogramming and should Spring AOP be used?

Thx

+1  A: 

I have no idea why the interception you're attempting is only being called in some cases, the code looks fine to me. It might be worth trying one or both of the following

Suggestion 1

Move the meta-programming out of Bootstrap and into a plugin. I've heard it said that meta-programming like this should always be done in the doWithDynaicMethods closure of a plugin, rather than Bootstrap, because the Bootstrap is not (always) executed when the application is reloaded at runtime.

Suggestion 2

Instead of intercepting the methods by implementing invokeMethod on each service's metaClass, you can instead implement invokeMethod on each class directly and make the service implement GroovyInterceptable. For example, replace:

class MyService {
// implementation
}

With:

class MyService implements GroovyInterceptable {

  def invokeMethod(String name, args) {
    log.debug "Method $name invoked"

    def originalMethod = Car.metaClass.getMetaMethod(name, args)
    originalMethod.invoke(this, args)
  }
}

An obvious problem with this is that it will require you to add the above boilerplate too all your services. But if it works, maybe you can use it as a starting point towards a DRYer solution.

Don
Suggestion 2 is not really a solution for me. I mentioned logging as an example but I want to be able to add/remove other functionality dynamically. Anyways, I gave it a try by creating a BaseService class and letting all services inherit but problem remains. Works fine when services are called from Grails but not when invoked directly from Flex via Spring integration. Problem probably lies in the ClassLoading mechanism as Chris Dail mentioned but I have to further investigate...
Nicolas Devos
A: 

The solution to another problem I faced, also solved this issue. Use explicit definition of your services in flex-servlet.xml instead of @RemotingDestination annotation and metaprogramming also works for services called from BlazeDS.

Nicolas Devos