Pages

Wednesday, August 11, 2010

Having fun with Grails and JRebel

Gails is a fun framework to work with. Recently, I had to figure out how "dynamic" the framework is.

BTW, IntelliJ IDEA Grails support just rocks!

One thing that is definitely useful - to tell Grails not to re-deploy the application after a new change has been introduced. You can do that by adding -Ddisable.auto.recompile=true to VM parameters of your application start script.


By default, controllers and service classes are initialized dynamically by Grails, but with the option above enabled it lets you to skip the re-deploy phase. Re-deploy of the application is required once you change Java classes, which may be included in your Grails application - this will be solved using JRebel as you will see below. Let's see a small example for that.

1) Create a new controller, called ActionController (grails create-controller action), which will delegate its calls to a service, HelloService (grails create-service hello), which will just return a string:



ActionController.groovy


class ActionController {
   def helloService

  def helloAction = {
    render(helloService.serviceMethod(params.name))
  }
}

HelloService.groovy

class HelloService {
  def String serviceMethod(String name) {
    return "hello ${name}!"
  }
}

HelloService is injected to the ActionController by convention. Run the Grails app with grails -Ddisable.auto.recompile=true run-app or from IDE as shown above. ActionController.helloAction is the entry point for our application: 


It tells now "hello Anton!"

Let's add another service to the application. Say, it will be GoodbyeService (grails create-service goodbye):

GoodbyeService.groovy

class GoodbyeService {
  def String serviceMethod(String name) {
    return "bye ${name}!"
  }
}

... and change the ActionController accordingly:

ActionController.groovy

class ActionController {
  def helloService
  def goodbyeService

  def helloAction = {
    render(helloService.serviceMethod(params.name))
  }

  def goodbyeAction = {
    render(goodbyeService.serviceMethod(params.name))
  }
}

So without any restart/redeploy phase, http://localhost:8080/jr-grails/action/goodbyeAction?name=Anton tells me "bye Anton!"

Perfect! I'm productive! :)

Now try another example, including some Java sources from within the application. For instance, we have a DummyController which delegates the calls to Util class instead of a Grails service.


DummyController.groovy


class DummyController {
  def index = {
    render(jr.util.Util.value())
  }
}

Util.java


public class Util {
  public static String value(){
    return "hello";
  }
}

http://localhost:8080/jr-grails/dummy now gives "hello" in response.

The problem is that if you make some changes in the Util class and recompile it, the change will not be visible in the application. To see the changes, you would need to redeploy the application which may require some time once you have a more sophisticated application.

JRebel to the rescue!

JRebel will help you with the issue above. Once you download and install the software, it is possible to start the application from your favorite IDE (via dedicated plug-in) or by adding special parameters to the application start script: -javaagent:"jrebel.jar"

Now if you run the example (see above), and after it is started, try making some changes to the Util class (for instance, change "hello" to "goodbye"). Hit F5 and the corresponding change will be visible now. The console will also display a message - JRebel: Reloading class 'jr.util.Util' - meaning that JRebel has noticed that the class has been altered and you want to use it in your application.

Unfortunately this trick doesn't work for all cases in Grails. For instance, for CRUD functionality in Grails application, if a change is made on a domain class, JRebel will reload the classes, but the change is not propagated further to the view because of some magic that Grails does behind the scenes.  The good news is that JRebel support for Grails is still in progress. Stay tuned! :)

2 comments:

Gregg Bolinger said...

Controllers and Services are dynamically reloaded without a re-deploy by default. No switch on startup required. What that switch does is turn off re-deploys for domain classes and anything under the src folder.

You're post is still valid. But the first half of it is inaccurate.

Anton Arhipov said...

Thx Gregg! Actually that is what I wanted to say :) Probably I should be more specific on that. Of course, the property is required just to disable the re-deploy phase.

I'll try to change the text.

Disqus for Code Impossible