Archive

Archive for February, 2008

Comet support in GlassFish

Want to learn how to write and deploy a web application based on GlassFish’s Comet? Four little steps to surf the Comet’s tail…

GlassFish AppServer - Get it Now

Download GlassFish

Download the latest v2 ur1 version here. Read then installation guide here. From now I will use ${glassfish.home} to reference your installation directory.

Enable Comet support in GlassFish

By default, Comet support in not enabled in GlassFish. Why? Because two years ago it was hard for me to convince my co-workers about the new Comet revolution. But things has changed now, and you can even spend days reading on Comet. To enable Comet in GlassFish, just do:

${glassfish.home}/bin/asadmin set server.http-service.http-listener \
.http-listener-1.property.cometSupport=true

or

$ vi ${glassfish.home}/domains/domain1/config/domain.xml 
add the following bold line under the http-listener port 8080
<http-listener acceptor-threads="1" address="0.0.0.0" 
           blocking-enabled="false" default-virtual-server="server"
           enabled="true" family="inet" id="http-listener-1" port="8080"
           security-enabled="false" server-name="" xpowered-by="true">
                <property name="cometSupport" value="true"/>
        </http-listener>

Comet in Action

You are now ready to see what Comet does. Just deploy one of the following war file (save the war under ${glasfish.home}/domains/domain/autodeploy):

  • JMaki little game: When you type a word, the word will be displayed using Flickr photos and shared amongst all browser. As soon as you move the words, all browsers will be updated with the word’s new position. You can even play chess by adding letters
  • Simple Chat application: A simple Chat application based on Comet
  • WebMc : WebMC is an ICEfaces demo application that lets you host a slide presentation over the internet.
  • DWR examples: DWR‘s Reverse Ajax demo running on top of GlassFish!

Start two browsers, hits the application url (ex: http://localhost:8080/jmaki-comet/) and see real time updates executed from one browser on the second one!

Wow, I want to write tons of Comet applications, where do I start

Take a look at the iFrame example or the javascript Prototype example as a start, and browse more documentation here. Ask questions using the users@glassfish.dev.java.net!

_uacct = “UA-3111670-1″;
urchinTracker();

technorati:

Categories: Uncategorized

Grizzlet reloaded: Bringing Ajax Push/Comet to the Masses?

Last September I’ve introduced Grizzlet, which is a simple but powerful enough way to write Ajax Push aka Comet applications. I came with the Grizzlet concept mostly after having collaborated to multiples Comet applications build on top of the Grizzly Comet ‘framework’. Although the Grizzly Comet framework can be simple to use, some of my collaborators wanted to have something more lightweight. Some of them were from the embedded devices space, where the size of the web server and the application is quite important. Even a database might want to have an embedded web server with comet inside. For those reasons, I’ve made the little monster small and easy to use.

Well, I was under the impression it was easy, but it wasn’t perfect. The first things users didn’t liked is the fact that the GrizzletContainer wasn’t supporting “traditional” web packaging bundle like a .jar or a .war, but instead needed an exploded folder “a la” JRuby. Message received: I’ve added support and now launching your Grizzlet is more simple. You just bundle your Comet application inside a war file like you usually do when using Servlet, and do:

java -jar grizzly-grizzlet-webserver-1.8.5.4.jar -a JMakiGrizzlet.war com.sun.grizzly.grizzlet.JMakiGrizzlet

You still have to specify the Grizzlet’s class name, but that’s something that can easily be done when the GrizzletContainer is embedded, or used inside GlassFish v3 where more powerful deployment capability are available. The next issue users where having was with the Grizzlet Request/Response API, which were kind of incomplete (kudo to Zaid for his contributions)…not anymore :-) You can take a look at the GrizzletRequest and GrizzletResponse API. Those API are really close to the HttpServletRequest/Response object.

Next I’ve added a couple of new examples (download them here and here). My favorite one is the JMaki based. This demo is quite interesting (see a picture here) as it stress the server quite hard. You enter word and move the word on the screen, and your word will move in all browser. Nice little game. It was already simple to implement it using Grizzly Comet, it is more simple with Grizzlet:

     23     public void onRequest(AsyncConnection ac) throws IOException {
     24         GrizzletRequest req = ac.getRequest();
     25         GrizzletResponse res = ac.getResponse();
     26 
     27         String action = req.getParameterValues("action")[0];
     28         if (action != null) {
     29             if ("post".equals(action)) {
     30                 String message = req.getParameterValues("message")[0];
     31                 String callback = req.getParameterValues("callback")[0];
     32                 if (callback == null) {
     33                     callback = "alert";
     34                 }
     35 
     36                 // Notify other registered CometHandler.
     37                 ac.push("<script id='comet_" + counter++ + "'>" + "window.parent."
     38                         + callback + "(" + message + ");</script>");
     39                 res.write("ok");
     40                 res.flush();
     41                 return;
     42             } else if ("start".equals(action)) {
     43                 res.setContentType("text/html");
     44                 String callback = req.getParameterValues("callback")[0];
     45                 if (callback == null) {
     46                     callback = "alert";
     47                 }
     48 
     49                 String message = "{ message : 'Welcome'}";
     50                 res.write("<script id='comet_" + counter++ + "'>" + "window.parent."
     51                         + callback + "(" + message + ");");
     52                 res.write("<html><head><title>jMaki Grizzly Comet Words Sample</title></head><body bgcolor=\"#FFFFFF\">");
     53                 res.flush();
     54 
     55                 if (ac.isGet()) {
     56                     ac.suspend();
     57                 }
     58                 return;
     59             }
     60         }
     61     }
     62 
     63     public void onPush(AsyncConnection ac) throws IOException {
     64         GrizzletRequest req = ac.getRequest();
     65         GrizzletResponse res = ac.getResponse();
     66 
     67         if (ac.isResuming()) {
     68             res.write("jMaki Grizzlet Words Sample closed
"); 69 res.write("</body></html<"); 70 res.flush(); 71 res.finish(); 72 } else if (ac.hasPushEvent()) { 73 res.write(ac.getPushEvent().toString()); 74 res.flush(); 75 } 76 }

In less than 100 lines, we have a nice game :-).

Pierre 2006 033.jpg

What’s next? I think the Grizzlet concept can be easily extended and ported to Web Server like Tomcat and Jetty, by changing the AsynConnection interface to support generics:

     30 /**
     31  * This class represent a possible asynchronous connection. An asynchronous
     32  * connection can always be suspended or resumed, its associated request
     33  * and response objects be used to construct a response, etc.
     34  *
     35  * @author Jeanfrancois Arcand
     36  */
     37 public interface AsyncConnection<E,F> {
     38 
     39     /**
     40      * Return true is the current connection associated with
     41      * this event has been suspended.
     42      */
     43     public boolean isSuspended();
     44 
     45 
     46     /**
     47      * Suspend the current connection. Suspended connection are parked and
     48      * eventually used when the Grizzlet Container initiates pushes.
     49      */
     50     public void suspend() throws AlreadyPausedException;
     51 
     52 
     53     /**
     54      * Resume a suspended connection. The response will be completed and the
     55      * connection become synchronous (e.g. a normal http connection).
     56      */
     57     public void resume() throws NotYetPausedException;
     58 
     59 
     60     /**
     61      * Advises the Grizzlet Container to start intiating a push operation, using
     62      * the argument message. All asynchronous connection that has
     63      * been suspended will have a chance to push the data back to their
     64      * associated clients.
     65      *
     66      * @param message The data that will be pushed.
     67      */
     68     public void push(String message) throws IOException;
     69      
     70 
     71     /**
     72      * Return the Request associated with this AsynchConnection.
     73      */
     74     public E getRequest();
     75 
     76 
     77     /**
     78      * Return the Response associated with this AsynchConnection.
     79      */
     80     public F getResponse();
     81 
     82 
     83     /**
     84      * Is this AsyncConnection being in the process of being resumed?
     85      */
     86     public boolean isResuming();
     87 
     88 
     89     /**
     90      * Is this AsyncConnection has push events ready to push back data to
     91      * its associated client.
     92      */
     93     public boolean hasPushEvent();
     94 
     95 
     96     /**
     97      * Return the message that can be pushed back.
     98      */
     99     public String getPushEvent();
    100 
    101 
    102     /**
    103      * Is the current asynchronous connection defined as an HTTP Get.
    104      */
    105     public boolean isGet();
    106 
    107 
    108     /**
    109      * Is the current asynchronous connection defined as an HTTP Get.
    110      */
    111     public boolean isPost();
    112 
    113 }

I would also think than REST can take advantage of that API…something for Paul!

Now I was looking for a project’s name and came a name related to Comet: AtmoSpherE :-). The project is not yet started, but once started, it will be a good sandbox to extends the Grizzlet concept and make it work with the upcoming Servlet 3.0 Comet proposal, which is still too complex in my opinion. Being able to resume/suspend a connection is a good step in the right direction, but I think not having any support/strategies when the push operation happens is something missing. Comet applications build on top of Servlet 3.0 will have to spawn threads to avoid blocking when doing the push operations, will have to throttle the push to avoid flodding clients, etc…but that’s not the goal of this blog. I will soon start my adventure in CometDaily where I will talk about those issues. For now, The Grizzlet adventures are quite challenging, thanks to the community!

technorati:

_uacct = “UA-3111670-1″;
urchinTracker();

Categories: Uncategorized

Writing a TCP/UDP stack supporting the SIP protocol using the Grizzly Framework

February 12, 2008 2 comments

Over the last year, I’ve had the opportunity to work (and learn!) with Ericsson on a TCP/UDP stack for supporting the SIP protocol. SIP is an interesting protocol and implementing support for it with Grizzly was quite interesting. My goal over the next few weeks is to explain how I did it using the Grizzly framework.

First, if you are new with Grizzly, I recommend you take a look at the terminology we are using. You might also wants to read about what is the SIP protocol, although for this first entry, I will focus on the transport implementation, not on SIP yet.

The first step when writing an application using Grizzly is to create the com.sun.grizzly.Controller object. This object is THE object that allow you to control the framework.

Controller controller = new Controller();

Next, we need to configure which transport we want to support. For this blog purpose, I will only explain how to support UDP and TCP, and talk about TLS later. In Grizzly, a transport is represented using the SelectorHandler interface, and the framework support by default three implementation: TCPSelectorHandler, TLSSelectorHandler and UDPSelectorHandler. By default, the Controller support TCP, but to help understanding how it works, the code below will explicitly configure the Controller to support TCP and UDP:

        TCPSelectorHandler tcpSelector = new TCPSelectorHandler();
        tcpSelectorHandler.setPort(8080);
        controller.addSelectorHandler(tcpSelector);
        
        UDPSelectorHandler udpSelector = new UDPSelectorHandler();
        udpSelectorHandler.setPort(8080);           
        controller.addSelectorHandler(udpSelector);

So far so good :-) Next is to configure the thread pool we want our application to use. In Grizzly, it is possible to associate a thread pool per SelectorHandler or shared among SelectorHandler. By default, the Controller creates a shared thread pool. For this application, we gonna create a single thread pool (called Pipeline) shared between the TCPSelectorHandler and UDPSelectorHandler.

        Pipeline mySharedPipeline = new DefaultPipeline());
        pipeline.setMaxThreads(5);
        
        controller.setPipeline(mySharedPipeline);

The next optional object to configure is the ProtocolChainInstanceHandler. The way Grizzly works is when a connection is made to one of its SelectorHandler, it accepts the connection (OP_ACCEPT) and then delegate the handling of the read/write/connect operations to what we call a ProtocolChain. A ProtocolChain implement the “Chain of Responsibility” pattern (for more info, take a look at the classic “Gang of Four” design patterns book). Towards that end, the Chain API models a computation as a series of “protocol filter” that can be combined into a “protocol chain”. The API for ProtocolFilter consists of a two methods (execute(Context) and postExecute(Context)) which is passed a “protocol context” parameter containing the dynamic state of the computation, and whose return value is a boolean that determines whether or not processing for the current chain has been completed (false), or whether processing should be delegated to the next ProtocolFilter in the chain (true).

ProtocolFilter can be stateless or stateful. By stateless, I mean an instance of ProtocolFilter can be executed by several threads simultaneously. By stateful, I means an instance of ProtocolFilter is not thread safe, so we usually need to create one instance per thread. Based on what your application does, you might want to configure the “state” of you ProtocolChain: stateful or stateless. This is what the ProtocolChainInstanceHandler is for. The Controller will invoke that object every time it needs to execute an operation. For our application, let’s assume we define a stateless ProtocolChain/ProtocolFilter:

        ProtocolChainInstanceHandler pciHandler =
                new ProtocolChainInstanceHandler() {

            final private ProtocolChain protocolChain = new DefaultProtocolChain();

            public ProtocolChain poll() {
                return protocolChain;
            }

            public boolean offer(ProtocolChain instance) {
                return true;
            }
        };
        controller.setProtocolChainInstanceHandler(pciHandler);

Next, we need to add our protocol specific implementation via ProtocolFilter. Grizzly ships with a ReadFilter than can be used to read bytes, independently of the transport used (UDP or TCP). Mainly, the ReadFilter reads the available bytes, and pass the control over the next ProtocolFilter. For the purpose of this blog, let’s add an echo ProtocolFilter (EchoFilter) that return the bytes sent by the client:

        ProtocolChain protocolChain = pciHandler.poll();
        protocolChain.addFilter(new ReadFilter());
        protocolChain.addFilter(new EchoFilter());

Technically, the EchoFilter just do:

    public boolean execute(Context ctx) throws IOException {
        final WorkerThread workerThread = ((WorkerThread)Thread.currentThread());
        ByteBuffer buffer = workerThread.getByteBuffer();
        buffer.flip();
        if (buffer.hasRemaining()) {
            // Depending on protocol perform echo
            SelectableChannel channel = ctx.getSelectionKey().channel();
            try {
                if (ctx.getProtocol() == Controller.Protocol.TCP) { // TCP case
                    OutputWriter.flushChannel(channel, buffer);
                } else if (ctx.getProtocol() == Controller.Protocol.UDP) {  // UDP case
                    DatagramChannel datagramChannel = (DatagramChannel) channel;
                    SocketAddress address = (SocketAddress) 
                            ctx.getAttribute(ReadFilter.UDP_SOCKETADDRESS);
                    OutputWriter.flushChannel(datagramChannel, address, buffer);
                }
            } catch (IOException ex) {
                // Store incoming data in byte[]
                byte[] data = new byte[buffer.remaining()];
                int position = buffer.position();
                buffer.get(data);
                buffer.position(position);
                
                Controller.logger().log(Level.WARNING, 
                        "Exception. Echo \"" + new String(data) + "\"");
                throw ex;
            }
        }
        
        buffer.clear();
        return false;
    }

Without going into too much details, this ProtocolFilter just take the ByteBuffer that contains the client’s bytes, and write it back using a temporary Selector trick (kind of a blocking write operation). Finally, we are ready to start our application:

controller.start();

There is other configurable interfaces with Grizzly (like how idles connections are closed using a SelectionKeyHandler), but for now we gonna just use the default. That’s it, we have now a server that listen for UDP and TCP requests :-). To recap, here is complete source code:

package com.sun.grizzly.utils;
      1 package com.sun.grizzly.utils;
      2 
      3 import com.sun.grizzly.Controller;
      4 import com.sun.grizzly.DefaultPipeline;
      5 import com.sun.grizzly.Pipeline;
      6 import com.sun.grizzly.ProtocolChain;
      7 import com.sun.grizzly.ProtocolChainInstanceHandler;
      8 import com.sun.grizzly.TCPSelectorHandler;
      9 import com.sun.grizzly.UDPSelectorHandler;
     10 import com.sun.grizzly.filter.EchoFilter;
     11 import com.sun.grizzly.filter.ReadFilter;
     12 
     13 public class SipServerDemo {
     14 
     15     public void startSIPServerDemo(){
     16 
     17         Controller controller = new Controller();
     18 
     19         TCPSelectorHandler tcpSelector = new TCPSelectorHandler();
     20         tcpSelectorHandler.setPort(8080);
     21         controller.addSelectorHandler(tcpSelector);
     22 
     23         UDPSelectorHandler udpSelector = new UDPSelectorHandler();
     24         udpSelectorHandler.setPort(8080);
     25         controller.addSelectorHandler(udpSelector);
     26 
     27         Pipeline mySharedPipeline = new DefaultPipeline());
     28         pipeline.setMaxThreads(5);
     29 
     30         controller.setPipeline(mySharedPipeline);
     31 
     32         ProtocolChainInstanceHandler pciHandler =
     33                 new ProtocolChainInstanceHandler() {
     34 
     35             final private ProtocolChain protocolChain = new DefaultProtocolChain();
     36 
     37             public ProtocolChain poll() {
     38                 return protocolChain;
     39             }
     40 
     41             public boolean offer(ProtocolChain instance) {
     42                 return true;
     43             }
     44         };
     45         controller.setProtocolChainInstanceHandler(pciHandler);
     46 
     47         ProtocolChain protocolChain = pciHandler.poll();
     48         protocolChain.addFilter(new ReadFilter());
     49         protocolChain.addFilter(new EchoFilter());
     50 
     51         controller.start();
     52     }
     53 
     54 }

Wow, that not that complicated :-) You can browse the Grizzly code online if you are interested about Grizzly’s internal here. My next blog will describe how to implement a client side TCP/UDP connector using the ConnectorHandler (needed by the SIP protocol), and discuss the details of how the SIP protocol can be implemented via a ProtocolFilter. A+

Part II can be read here.

_uacct = “UA-3111670-1″;
urchinTracker();

technorati:

Categories: Uncategorized
Follow

Get every new post delivered to your Inbox.

Join 51 other followers