Grizzlet reloaded: Bringing Ajax Push/Comet to the Masses?
Posted by jfarcand on February 14, 2008 at 06:02 PM | Comments (2)
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.0.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 :-).
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: grizzly jersey
grizzlet
jmaki comet ajax glassfish
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
You make me sick ! How many new things to try ? I'll never have the time to try all of your tricks in one life ...
Thanks for all what you do about Grizzly :)
Posted by: dun4n on February 22, 2008 at 04:54 AM
-
Pretty cool!
When will grizzlet be available for jetty ?
Thanks,
Posted by: kboufelliga on May 28, 2008 at 04:32 PM
|