users@jersey.java.net

Container reloading

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 11 Apr 2008 13:58:02 +0200

Hi,

I have just put back a container independent feature in the trunk for
containers to listen and act on requests to reload. For servlet you
still currently need to override the ServletContainer and register a
ContainerNotifier instance in the configure or initiate method.


I have managed to get things working with JavaRebel [1, 2], see code at
end of email. JavaRebel picks up changes to Java class files so i can
keep the LW HTTP server running and it will be informed by JavaRebel
when to reload i.e. when i rebuild. This works for resource classes and
providers.

It is not perfect. JavaRebel informs for each class that is modified and
thus a reload may happen multiple times if multiple classes are
modified. Because of the way things are wired up it would be easier if
Jersey could be informed in a transactional manner, e.g.
start/inform/end, but that may not be the way JavaRebel works. Working
from a per-class basis requires some work to identify the class then
update the appropriate cached information. This is relatively easy for
resource classes, but not so easy for providers.

I will blog about this next week.

Paul.

[1] http://www.zeroturnaround.com/javarebel/
[2] http://code.google.com/p/zt-oss/

import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.ws.rest.api.container.ContainerFactory;
import com.sun.ws.rest.api.container.httpserver.HttpServerFactory;
import com.sun.ws.rest.api.core.ClasspathResourceConfig;
import com.sun.ws.rest.api.core.ResourceConfig;
import com.sun.ws.rest.spi.container.ContainerListener;
import com.sun.ws.rest.spi.container.ContainerNotifier;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.zeroturnaround.javarebel.ReloadListener;
import org.zeroturnaround.javarebel.ReloaderFactory;

public class Main {
     @Path("/{id}")
     public static class NameValuePair {
         @GET
         public String getOne(@PathParam("id") int id) {
             return Integer.toString(id) + "x";
         }

         @GET
         @Path("sub")
         public String getSub(@PathParam("id") int id) {
             return "----";
         }
     }

     @Path("/XXX")
     public static class XXX {
         @GET public String get() { return "YYY"; }
     }

     private static class Reloader implements ContainerNotifier,
             ReloadListener {
         private final List<ContainerListener> ls;

         private final ClasspathResourceConfig rc;

         public Reloader(ClasspathResourceConfig rc) {
             ls = new ArrayList<ContainerListener>();
             this.rc = rc;
         }

         public void addListener(ContainerListener l) {
             ls.add(l);
         }

         public void reloaded(Class arg0) {
             rc.reload();
             for (ContainerListener l : ls) {
                 l.onReload();
             }
         }
     }

     public static void main(String[] args) throws Exception {
         ClasspathResourceConfig rc = new ClasspathResourceConfig();
         Reloader r = new Reloader(rc);

 
rc.getProperties().put(ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, r);
         ReloaderFactory.getInstance().addReloadListener(r);

         HttpServer s = HttpServerFactory.create("http://localhost:9999/",
                 ContainerFactory.createContainer(HttpHandler.class, rc));
         s.start();

         try {
             System.in.read();
         } finally {
             s.stop(0);
         }
     }
}
-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109