The Source for Java Technology Collaboration
User: Password:



Jean-Francois Arcand

Jean-Francois Arcand's Blog

Extending the Grizzly HTTP Runtime

Posted by jfarcand on July 03, 2008 at 08:52 PM | Comments (3)

Project Grizzly provides developers with a simple and consistent mechanism for extending the functionality of the Grizzly HTTP Runtime and for bridging existing HTTP based technologies like JRuby-on-Rail, Grail, Servlet, the Bayeux Protocol or any http based protocol.

IMG_0320.JPG

There is three important classes to know when you want to extend (and embed):

  • GrizzlyAdapter: The GrizzlyAdapter is the main extensible point when you want to write an http based extension. This class is invoked by the Grizzly Http Runtime as soon as the http request has been parsed. It's main method is defined as service(GrizzlyRequest req, GrizzlyResponse res). You can get all the http information from the GrizzlyRequest and write the response using the GrizzlyResponse. Grizzly ships with several implementation of the GrizzlyAdapter: ServletAdapter, CometdAdapter, StaticResourceAdapter, etc. You can look at the details by browsing the code from here
  • AsyncFilter: AsyncFilter are helpful when you want to write an asynchronous request processing based web server. AsyncFilter allows you to suspend the processing of an http request, and resume it once you are ready. When suspending the request execution, an AsyncFilter doesn't block on a Thread so you don't waste a Thread until the execution is resumed. AsyncFilter always execute before any GrizzlyAdapter
  • GrizzlyWebServer: The main entry point. You always first create an instance of the GrizzlyWebServer, and then add GrizzlyAdapter(s) and AsyncFilter(s).

Sound complicated? Not at all! Let's describe some really simple examples.

First, let's create a WebServer that serve static resources:

        GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
        try{
            ws.start();
        } catch (IOException ex){
            // Something when wrong.
        }

Now let's write a very simple GrizzlyAdapter that return an html page when a static resource is not found.

        GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
        try{
            ws.addGrizzlyAdapter(new GrizzlyAdapter(){  
                
                public void service(GrizzlyRequest request, GrizzlyResponse response){
                    try {
                        response.getWriter().println("Grizzly is soo cool..but you request cannot be found!");
                    } catch (IOException ex) {                        
                    }
                }
            });
            ws.start();
        } catch (IOException ex){
            // Something when wrong.
        }

Now let's add Servlet support to our WebServer (note that the Grizzly's Servlet support is limited in term of functionalities..no deployment support, all done programatically)

   
        GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
        try{
            ServletAdapter sa = new ServletAdapter();
            sa.setRootFolder("/Path/To/Exploded/War/File");
            sa.setServlet(new MyServlet());
            ws.addGrizzlyAdapter(sa);
            ws.start();
        } catch (IOException ex){
            // Something when wrong.
        } 

Well, why not adding two Servlet support

        GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
        try{
            ServletAdapter sa = new ServletAdapter();
            sa.setRootFolder("/Path/To/Exploded/War/File");
            sa.setServlet(new MyServlet());
            ws.addGrizzlyAdapter(sa);
  
            ServletAdapter sa2 = new ServletAdapter();
            sa2.setRootFolder("/Path/To/Exploded/War2/File");
            sa2.setServlet(new MySecondServlet());
            ws.addGrizzlyAdapter(sa2);
  
            ws.start();
        } catch (IOException ex){
            // Something when wrong.
        }

Easy, it is (to speak like Yoda). Now let's go back to basic, which is to serve static resources. Let's assume we want to delay the request processing when we are under load, using an AsyncFilter. Let's assume for now that all requests will be suspended 10 seconds before they get executed by the GrizzlyAdapter.

        GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
        try{
            ws.addAsyncFilter(new AsyncFilter() {
                private final ScheduledThreadPoolExecutor scheduler = 
                        new ScheduledThreadPoolExecutor(1);
                public boolean doFilter(final AsyncExecutor asyncExecutor) {
                    //Throttle the request
                    scheduler.schedule(new Callable() {
                        public Object call() throws Exception {
                            asyncExecutor.execute();
                            asyncExecutor.postExecute();
                            return null;
                        }
                    }, 10, TimeUnit.SECONDS);
                    
                    // Call the next AsyncFilter
                    return true;
                }
            });
                                        
            ws.addGrizzlyAdapter(new GrizzlyAdapter(){                  
                public void service(GrizzlyRequest request, GrizzlyResponse response){
                    try {
                        response.getWriter().println("Grizzly is soon cool");
                    } catch (IOException ex) {                        
                    }
                }
            });
            ws.start();
        } catch (IOException ex){
            // Something when wrong.
        }

This is cool, is it? Now let's add Servlet to the picture:

        GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
        try{
            ws.addAsyncFilter(new AsyncFilter() {
                private final ScheduledThreadPoolExecutor scheduler = 
                        new ScheduledThreadPoolExecutor(1);
                public boolean doFilter(final AsyncExecutor asyncExecutor) {
                    //Throttle the request
                    scheduler.schedule(new Callable() {
                        public Object call() throws Exception {
                            asyncExecutor.execute();
                            asyncExecutor.postExecute();
                            return null;
                        }
                    }, 10, TimeUnit.SECONDS);
                    
                    // Call the next AsyncFilter
                    return true;
                }
            });
  
            ServletAdapter sa = new ServletAdapter();
            sa.setRootFolder("/Path/To/Exploded/War/File");
            sa.setServlet(new MyServlet());
            ws.addGrizzlyAdapter(sa);
 
            ws.start();
        } catch (IOException ex){
            // Something when wrong.
        }

Miam Miam! OK now let do something really really complicated :-). Let's add Comet into the picture. Naa not enough complicated. Let's add the Bayeux Protocol (cometd) but also be able to serve static resources and Servlet.

        GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
        try{
            // Add Comet Support
            ws.addAsyncFilter(new CometAsyncFilter());
 
            //Add Bayeux support
            CometdAdapter cometdAdapter = new CometdAdapter();
            ws.addGrizzlyAdapter(cometdAdapter);
  
            ServletAdapter sa = new ServletAdapter();
            sa.setRootFolder("/Path/To/Exploded/War/File");
            sa.setContextPath("/servlets/");
            sa.setServlet(new MyServlet());
            ws.addGrizzlyAdapter(sa);
 
            ws.start();
        } catch (IOException ex){
            // Something when wrong.
        } 

Wow. With just a couple of line we were able to create a Web Server that supports the Bayeux Protocol, a single Servlet and static resources. Now you can do things much more complicated, like writing complex and powerful GrizzlyAdapter, and call it GlassFish v3 :-). v3 is a good example of how easy it is to build really powerful HTTP extension using the Grizzly extensible point like the GrizzlyAdapter.

Want to give it a try? Download the Grizzly HTTP extension, add it to your classpath, and look at the GrizzlyWebServer API. Now if you want to do things more complicated liked adding JMX support, monitoring, etc, then read that old blog serie and look at the now infamous SelectorThread documentation :-). If you have question, just stop by users@grizzly.dev.java.net...we have more and more peoples shaking the Grizzly those days!

technorati:


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hi Jean-Francois,

    I wanted to play around with your examples, but I was having issues. It seems that GrizzlyWebServer is in com.sun.grizzly.http.embed but the grizzly-servlet-webserver-1.8.1.jar has no com.sun.grizzly.http.embed package. Did I misunderstand and download the wrong jar?

    Thanks,

    Collin

    Posted by: aberrant on July 08, 2008 at 11:32 AM

  • Salut. I've just re-uploaded the 1.8.1 jars to see if that will make a difference. Wait 10 minutes and you should be able to use it. Let us know on users@grizzly.dev.java.net if that doesn't. Thanks for you interest! -- Jeanfrancois

    Posted by: jfarcand on July 08, 2008 at 11:36 AM

  • I found the embed package. It turns out it's in the 1.8.2-SNAPSHOT packages.

    Posted by: aberrant on July 08, 2008 at 01:31 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds