views:

71

answers:

2

I have a webapp running that has a bug. I know how to fix it in the sources. However I cannot redeploy the app as I would have to take it offline to do so. (At least not right now).

I now want to fix the code "at runtime". Surgery on the living object, so to speak.

The app is implemented in Java and is build on top of Seam. I have added a Groovy Console to the app previous to the last release. (A way to run arbitrary code at runtime)

The normal way of adding behaviour to a class with Groovy would be similar to this:

String.metaClass.foo= { x -> x * x }
println "anything".foo(3)

This code added the method foo to java.lang.String and prints 9. I can do the same thing with classes running inside my webapp container. New instances will thereafter show the same behaviour:

com.my.package.SomeService.metaClass.foo= { x -> x * x }
def someService = new com.my.package.SomeService()
println someService.foo(3)

Works as excpected. All good so far.

My problem is now that the container, the web framework, Seam in this case, has already instantiated and cached the classes that I would like to manipulate (that is change their behaviour to reflect my bug fix).

Ideally this code would work:

com.my.package.SomeService.metaClass.foo= { x -> x * x }
def x = org.jboss.seam.Component.getInstance(com.my.package.SomeService)
println x.foo(3)

However the instantiation of SomeService has already happened and there is no effect.

Thus I need a way to make my changes "sticky". Has the groovy magic gone after my script has been run? Well, after logging out and in again, I can run this piece of code and get the expected result:

def someService = new com.my.package.SomeService()
println someService.foo(3)

So the foo method is still around and it looks like my change has been permanent...

So I guess the question that remains is how to force Seam to re-instantiate all its components and/or how to permanently make the change on all living instances...?

+1  A: 

The hotfix is not persistent because the calling code is pure Java, not Groovy.

The Groovy magic in fact stays. But only when called from the groovy environment, that is through other groovy code.

Turns out that in a Java environment, the "Keyhole Surgery Pattern", as coined by Dierk König is only usable to change data at runtime, not code. The full power of the pattern is only accessible in a pure Groovy environment.

raoulsson
A: 

Not Groovy, but an alternative approach that works - as long as you don't change / add / remove and method signatures - is to set the Server in debug mode and use Java Hot Code Replacement functionality. Most IDE's support this. The changes are permanent and applied to instantiated components as well. Requires of course that the app server is already configured with the a debug console or allows to enable it after the start.

Elmar Weber