JRebel manages the updates while adding new changes to a simple RESTEasy application: adding new resource using the JAX-RS annotations and adding new Java code to the application. No re-deploy phase required.
Pages
Thursday, August 26, 2010
Tuesday, August 24, 2010
RESTEasy. rest, easy.
I've spent some days figuring out how does RESTEasy initializes itself. The goal, which came actually from a support case, was to hook into the framework and make it possible to add new resources with @Path annotation without re-deploying the application itself.
It turned out that as RESTEasy has 3 main options for bootstrapping: servlet (which actually has a plenty of configuration switches), listener, and filter. This is quite important as RESTEasy initializes itself a little bit differently depending on what kind of configuration is provided.
I've managed to patch the internals of RESTEasy in a way, so that in case of "servlet" bootstrapping, when adding a new resource to the application, the new context path appeared instantly, without re-deploying the application.
For a demo, I used the 'jaxb-json' example that is bundled with RESTEasy distribution. By default, the example uses listener bootstrapping configuration, thus web.xml has to be modified a little bit to use 'servlet' configuration instead:
Next, run the application, and see that localhost:8080/resteasy/library/books/badger responds as intended for the given example. Now, if we use JRebel to make the class re-loading possible, and patch some classes of RESTEasy framework, one will be able to add new methods to the resource class without having to re-deploy the application. Say, I've added a new method to the class, and marked it with the @Path annotation:
So now I could go to localhost:8080/resteasy/library/books/test and see the changes instantly! Hopefully we can add this feature to support all kinds of RESTEasy configurations. The feature will be available quite soon in one of the upcoming JRebel nightly builds.
It turned out that as RESTEasy has 3 main options for bootstrapping: servlet (which actually has a plenty of configuration switches), listener, and filter. This is quite important as RESTEasy initializes itself a little bit differently depending on what kind of configuration is provided.
I've managed to patch the internals of RESTEasy in a way, so that in case of "servlet" bootstrapping, when adding a new resource to the application, the new context path appeared instantly, without re-deploying the application.
For a demo, I used the 'jaxb-json' example that is bundled with RESTEasy distribution. By default, the example uses listener bootstrapping configuration, thus web.xml has to be modified a little bit to use 'servlet' configuration instead:
<?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>resteasy.servlet.mapping.prefix</param-name> <param-value>/resteasy</param-value> </context-param> <servlet> <servlet-name>Resteasy</servlet-name> <servlet-class> org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher </servlet-class> <init-param> <param-name>javax.ws.rs.Application> <param-value>org.jboss.resteasy.examples.service.LibraryApplication</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Resteasy</servlet-name> <url-pattern>/resteasy/*</url-pattern> </servlet-mapping> </web-app>
Next, run the application, and see that localhost:8080/resteasy/library/books/badger responds as intended for the given example. Now, if we use JRebel to make the class re-loading possible, and patch some classes of RESTEasy framework, one will be able to add new methods to the resource class without having to re-deploy the application. Say, I've added a new method to the class, and marked it with the @Path annotation:
@Path("library") public class Library { @GET @Path("books/test") @Produces("text/html") public String getTest() throws Exception { return "my test"; } }
So now I could go to localhost:8080/resteasy/library/books/test and see the changes instantly! Hopefully we can add this feature to support all kinds of RESTEasy configurations. The feature will be available quite soon in one of the upcoming JRebel nightly builds.
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))
}
}
ActionController.groovy
class DummyController {
def index = {
render(jr.util.Util.value())
}
}
public class Util {
public static String value(){
return "hello";
}
}
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! :)
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.
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! :)
Subscribe to:
Posts (Atom)