atmosphear: building asynchronous collaborative web applications

60
<Insert Picture Here> Comet Everywhere: Building Asynchronous Collaborative Web Applications Lee Chuk Munn Staff Engineer [email protected]

Upload: others

Post on 03-Feb-2022

2 views

Category:

Documents


0 download

TRANSCRIPT

<Insert Picture Here>

Comet Everywhere: Building Asynchronous Collaborative Web ApplicationsLee Chuk MunnStaff [email protected]

Agenda• Introduction to Comet• Build Asynchronous Applications using

– Bayeux/Cometd• Demo: Slideshow Application using Cometd

– Grizzly Comet Framework• Demo: Tic-Tac-Toe game

• Future, Summary and Resources

Web 2.0 – Driven by Participation• Documents on the web are generated by users

• “Information age” → “Participation age”• Browser is becoming the platform to program to

Asynchronous Web Revolution• Ajax (as we know!) allows user to send requests

asynchronously without waiting for response– User Initiated– Ajax Poll

• However, the first-generation Ajax is not “asynchronous” enough– It handles a single user client-side asynchronicity

• Full asynchronicity includes “updates pushed from server to the clients” any time – Send users notifications– Allow users to communicate and collaborate within the web

application• Called “Comet”, “Server-side Push”, “Ajax Push”, or

“Reverse Ajax”

Demo:Demo:Running SlideshowRunning SlideshowCometd ApplicationCometd Application

Server-mediated Collaboration

Server

Client 1 Client 2, 3, ..n

External Application

UserAction

Push

User initiated

Server-mediated Collaboration

Server

Client 1 Client 2, 3, ..n

External Application

Push Push

Application initiated

What is Comet (Ajax Push)?• A programming technique that enables web servers to

send data to the client without having any need for the client to request for it

• Allows creation of highly responsive, event-driven web applications – Keep clients up-to-date with data arriving or changing on the

server, without frequent polling• Advantages

– Lower latency, not dependent on polling frequency– Server and network do not have to deal with frequent polling

requests to check for updates

Comet Examples• GMail and GTalk • Meebo• 4homemedia.com

(using GlassFish project's Comet)• JotLive• KnowNow• Many more …

Ajax Poll vs Ajax Push• Ajax Poll:

– Send a request to the server every X seconds – The response is “empty” if there is no update

• Ajax Push– Long Poll: (most popular)

• Client sends a request to the server, server waits for an event to happen, then sends the response

• The response is never empty– Http Streaming:

• Client sends a request, server waits for events, stream multi-part/chunked responses, and then wait for the events

• The response is continually appended to

Ajax: Poll vs Push

• Comet refers to both long polling and streaming methods of web programming

How Push works• Always “keep a connection open”

– do not respond to the initiating request until event occurs• Deliver data over a previously opened connection• Streaming is an option

– send response in multiple parts without closing the connection in between

Server Side: Servlet Thread Catastrophe

• For each client connection, a thread is assigned and it remains blocked till response is sent

• Using blocking, synchronous technology will result in a blocked thread for each open connection that is “waiting”– Every blocked thread will consume memory– This lowers scalability and can affect performance

• Servlet 2.5 are an example of blocking, synchronous technology

Technology Solution• Use technology that supports Asynchronous Request

Processing (ARP)– Release the original request thread while waiting for an event– May process the event/response on another thread than the

original request• Use new I/O (NIO) non-blocking sockets to avoid

blocking a thread per connection• Advantages

– Number of clients is primarily limited by the number of open sockets a platform can support

– Could have all clients (e.g. 10’000) “waiting” without any threads processing or blocked

Grizzly • A generic NIO framework for building scalable server

application.– Supports blocking and non blocking socket operations, over

plain or ssl connection using Java NIO API.– Enables greater performance and scalability – Uses a thread pool system and keeps the state of requests

• so that it can keep requests alive without holding a single thread for each of them.

• The GlassFish server includes the Grizzly HTTP Engine– which enables asynchronous request processing (ARP) by

avoiding blocking connections.

GlassFish• Supports 2 different implementations of Comet

– Bayeux Protocol — Often referred to as Cometd.

• Uses a publish/subscribe model for server/client communication.

• The Grizzly implementation of Cometd consists of a servlet that you reference from your web application.

– Grizzly Comet — Based on ARP, • includes a set of APIs that you use from a web component

to enable Comet functionality in your web application. • Grizzly Comet is specific to the GlassFish Server.

Grizzly Comet Components

Grizzly Comet FrameworkGrizzly Comet Framework

Grizzly HTTP Grizzly HTTP

Grizzly NIO FrameworkGrizzly NIO Framework

GrizzletGrizzlet BayeuxBayeux Messages BusMessages BusContinuationContinuation

Agenda• Web 2.0• Introduction to Comet• Asynchronous Applications using

– Bayeux/Cometd• Demo: Slideshow Application using Cometd

– Grizzly Comet Framework• Demo: Tic-Tac-Toe game

• Future, Summary and Resources

What Is Bayeux Protocol?• JSON-based protocol

– Allows clients to register interest in events and– Servers to deliver them to all the registered clients

• Based on publish/subscribe model– You subscribe a channel to receive messages– You publish a message onto a channel

• Message router (event router on the server) routes the message to anybody who subscribed the channel

• Supports multiple “channels” on a single HTTP connection– Each channel represents a separate conversation – Each channel has a unique name

• /my/channel-name– Solves the two HTTP connection limit on the browser

Message Format in Bayeux Protocol• Message format is in the format of JSON

{ "channel": "/some/name", "clientId": "83js73jsh29sjd92", "data": { "myapp" : "specific data", value: 100 } }

• JSON Messages are published on specified channels• The "/meta/*" channel is reserved for communications

with the event router itself– Channel operations:

• connect, subscribe, unsubscribe, etc.

What Is Cometd?• Bayeux protocol implementation (from Dojo toolkit)• Easy programming model

– Client • consists of JavaScript technology (DOJO toolkit) or • Java libraries that implement Bayeux

– Server • event router on the server side• The Server uses async techniques to “park” the request

without blocked threads• No server-side applications need to be created

– The server acts as a message reflector– Mediates the messages to the right channel

Demo:Demo:Disecting SlideshowDisecting SlideshowCometd ApplicationCometd Application

Software and Configuration• Glassfish Application Server (V2 or V3)

– Enable Comet Support• Configure using GlassFish V2 admin console• Configure in NetBeans 6.1+ for GlassFish V3• or Command line

– asadmin set server.http-service.http-listener.http-listener-1.property.cometSupport=true

• or Edit domain.xml in GlasFish– <http-listener id="http-listener-1" port="8080"><property

name="cometSupport" value="true" />– Grizzly Comet APIs

• A browser Client, running Javascript, with Ajax support

GlassFish V3 Comet Enable (in NetBeans)

Enable Comet in GlassFish V2 Admin Console

Configure Cometd Servlet in web.xml• The Grizzly implementation of Cometd server consists

of a servlet that you reference from your web application.

• Configure web.xml

<servlet> <servlet-name>Grizzly Cometd Servlet</servlet-name> <servlet-class> com.sun.grizzly.cometd.servlet.CometdServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>Grizzly Cometd Servlet</servlet-name> <url-pattern>/cometd/*</url-pattern> </servlet-mapping>

Step 1 : Initialize (Connect to Cometd Server)

dojo.require("dojox.cometd");

// Initialize a connection to the given Cometd server:// the GlassFish Grizzly Bayeux servletdojox.cometd.init("cometd");

Makes a call to http://myapplication/cometd

Note: /cometd/* is the url-pattern for the Grizzly Cometd Servlet configured in the web.xml for the application

Handshaking• /meta/handshake channel - request message

[{"version":"1.0","minimumVersion":"0.9","channel":"/meta/handshake","id":"0","supportedConnectionTypes":["long-polling","long-polling-json-encoded","callback-polling"]}]

• /meta/handshake channel - response message

[{"channel":"/meta/handshake","version":"1.0","supportedConnectionTypes":["long-polling","callback-polling"],"minimumVersion":"0.9","id":"0","clientId":"tgjWhMBIg5U2dPTwZBmlgw==","successful":true,"advice":{"reconnect":"retry","interval":0,"multiple-clients":false},"authSuccessful":true}]

Connect• /meta/connect channel - request message

[{"channel":"/meta/connect","clientId":"tgjWhMBIg5U2dPTwZBmlgw==","connectionType":"long-polling","id":"1"}]

• /meta/connect channel - response message

[{"channel":"/meta/connect","clientId":"tgjWhMBIg5U2dPTwZBmlgw==","successful":true,"id":"1","advice":{"reconnect":"retry","interval":0,"multiple-clients":false},"timestamp":"Tue, 01 Dec 2009 14:59:01 GMT"}]

Step 2 : Subscribe a Channel// Subscribe a channel with callback function.// Every time a message is published, // the callback function (of all clients who subscribed // the channel) gets invoked.dojox.cometd.subscribe(“channel”

, "remote topic", "callbackFunction");

Subscribe• /meta/subscribe channel - request message

[{"channel":"/meta/subscribe","subscription":"/chat/slideshow","clientId":"tgjWhMBIg5U2dPTwZBmlgw==","id":"2"},{"data":{"user":"Abhi","text":" has joined"},"channel":"/chat/slideshow","clientId":"tgjWhMBIg5U2dPTwZBmlgw==","id":"3"}]

• /meta/subscribe channel - response message

[{"channel":"/meta/subscribe","successful":true,"clientId":"tgjWhMBIg5U2dPTwZBmlgw==","subscription":"/chat/slideshow","id":"2"}, {"channel":"/chat/slideshow","successful":true,"clientId":"tgjWhMBIg5U2dPTwZBmlgw==","id":"3"}, {"channel":"/chat/slideshow","data":{"text":" has joined","user":"Abhi"},"id":"3","clientId":"tgjWhMBIg5U2dPTwZBmlgw=="}]

Step 3 : Publish data onto the channel

// Publish data (in JSON format) onto the channel.dojox.cometd.publish("channel",

{jsonname: jsonvalue});Comet Server

publish datae.g. new slide url

dojox.cometd.publish("channel", {slide: url});

Data• data channel - request message

[{"data":{"slide":"images/image0.jpg"}, "channel":"/chat/slideshow","clientId":"tgjWhMBIg5U2dPTwZBmlgw==","id":"5"}]

• data channel - response message

[{"channel":"/chat/slideshow","successful":true,"clientId":"tgjWhMBIg5U2dPTwZBmlgw==","id":"5"}]

Step 4 : Write callback function

Client 2 Client 3

// The callback function gets invoked when the client // receives a “published” message from a Cometd // server. Typically you update the page contents.callbackHandler: function(msg) { alert("msg.data.testMessage = "

+ msg.data.testMessage)}

Update BrowsercallBackFunction(slideUrl){ slide.innerHTML ="<img src='" + slideUrl + "'/>"; ...}

Step 5 : Unsubscribe, Disconnect

// Unsubscribe the channeldojox.cometd.unsubscribe(“channel”, myObject,

"callbackHandler");

// Disconnect from the Cometd serverdojox.cometd.disconnect();

Agenda• Web 2.0• Introduction to Comet• Truly Asynchronous Applications using

– Bayeux/Cometd• Demo: Slideshow Application using Cometd

– Grizzly Comet Framework• Demo: Tic-Tac-Toe game

• Future, Summary and Resources

Demo:Demo:Tic-Tac-ToeTic-Tac-Toe

(http://weblogs.java.net/blog/driscoll/archive/2008/05/comet_tictactoe_1.html)(http://weblogs.java.net/blog/driscoll/archive/2008/05/comet_tictactoe_1.html)

Grizzly Comet Framework• The Framework contains the classes required to add

support for Comet in a Web Application– Servlets, JSP, JSF etc.

• CometEngine– Main class that allows Comet support on top of Grizzly

Asynchronous Request Processing mechanism. – This class is the entry point to any component interested to

execute Comet request style.• Components can be Servlets, JSP, JSF or pure Java

class.

Grizzly Comet Framework• CometContext

– A shareable “space” applications can subscribe and get updated when the context is updated.

• A distribution mechanism for pushing messages that are delivered to multiple subscribers called CometHandler

• A la JMS Queue/Topic where CometHandlers register for information

– All http response registered to a CometContext automatically become suspended, waiting for an event (a push) to happen

• Contains references to all suspended connections (encapsulated inside a CometHandler)

– A browser receives only those messages published after the client suspends its response via CometContext

Grizzly Comet Framework (cont.)• CometHandler

– represents/encapsulates a suspended connection (or response)

– can be resumed later when an event happens– has methods that are invoked by the Container:

• When a push operation happens• When I/O operations are ready to be processed

(asynchronous read or write)• When the browser closes the connection

• CometEvent– An object containing the state of the Comet Context

• content updated, client connected/disconnected, etc.

Steps for Implementing Comet • Step 1: Initialize Comet

– Register a CometContext• Step 2: Define your CometHandler

– To handle various events• Step 3: Connect to Comet Servlet

– Add CometHandler to CometContext– Connection gets suspended as response not committed

• Step 4: Advertise changes– Client - Sends a message– Server - Notify all other clients

• Step 5: More details on Client– Update Client

Step 1: Initialize CometCreate or Register a CometContext

Step 1: Initialize CometRegister a CometContext

//In TTTComet Servlet class...public void init(ServletConfig config) { ServletContext context = config.getServletContext();

contextPath = context.getContextPath() + "/TTTComet1";

// Comet Entry Point CometEngine engine = CometEngine.getEngine(); CometContext cometContext = engine.register(contextPath); cometContext.setExpirationDelay(120 * 1000);

Step 2: Define a CometHandler• The CometHandler<E> interface methods

//Invoked when CometContext.notify() is calledpublic void onEvent(CometEvent ce);

// Invoked when the browser closes a suspended// connection or when the suspend timeout expire

public void onInterrupt(CometEvent ce);

// Invoked when the request is suspendedpublic void onInitialize(CometEvent ce);

// Attach an object.. most probably the HttpServletResponsepublic void attach(E e);

CometHandler: TTTHandler//Inside the TTTComet Servlet class...private class TTTHandler implements

CometHandler<HttpServletResponse> {private HttpServletResponse response;

//When push operation happens, //onEvent is invoked after CometContext.notify() is called public void onEvent(CometEvent event) throws IOException {

if (CometEvent.NOTIFY == event.getType()) {//Add your business logic here

…// resume all suspended connections event.getCometContext().resumeCometHandler(this);

}}...

Step 3: Connect Comet Servlet: Add CometHandler to CometContext The Servlet Get (called by iframe)

Step 3: Add CometHandler to CometContext• Connect to server with GET, GET is now suspended

– Instead of POST, recommended by Comet

protected void doGet(HttpServletRequest request,, HttpServletResponse response)

throws ServletException, IOException {

TTTHandler handler = new TTTHandler();handler.attach(response);CometEngine engine = CometEngine.getEngine();CometContext context =

engine.getCometContext(contextPath);context.addCometHandler(handler);

}

Step 4: Advertise ChangesPost is called (client)

Step 4: Advertise ChangesPost is called (client)<table><tr><td id="cell0"><img id="img0" src="resources/0.gif"

onclick=postMe("0")></td>...</table>

var url = "TTTComet1";function postMe(arg) {

var xhReq = createXMLHttpRequest();xhReq.open("POST", url, true);xhReq.setRequestHeader("Content-Type",

"application/x-www-form-urlencoded");xhReq.send("cell="+arg);

};

Step 4: Advertise ChangesDatabase Update (server)

Step 4: Advertise ChangesPost is called (server)

protected void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

String cellStr = request.getParameter("cell");PrintWriter writer = response.getWriter();…game.turn(cell);… CometEngine engine = CometEngine.getEngine();CometContext<?> context =

engine.getCometContext(contextPath);context.notify(null); //Notify all Handlers

CometHandler: TTTHandler (revisit)//Inside the TTTComet Servlet class...private class TTTHandler implements CometHandler<HttpServletResponse> {

private HttpServletResponse response;

//When push operation happens, //onEvent is invoked after CometContext.notify() is called

public void onEvent(CometEvent event) throws IOException {if (CometEvent.NOTIFY == event.getType()) {

PrintWriter writer = response.getWriter();writer.write("<script type='text/javascript'>parent.chImg("

+ game.getJSON() + ")</script>\n"); writer.flush();event.getCometContext().resumeCometHandler(this);

}}…

Sample JSON output

{ “win”: “-1”, “board”: [“0”, “1”, “10”,

“0”, “1”, “10”,“1”, “10, “0” ],

“turn”: “10” }

Step 5: Client Side update (called from Server Side onEvent() in CometHandler)

function chImg(args) {var data = eval(args);// redraw the boardfor (i = 0; i < 9; i++) {

document.getElementById("img"+i).src ="resources/"+data.board[i]+".gif";

} // -1 is unfinished, 0 is tie, 1 is X win, 2 is O winvar statusMsg; if (data.win == 0) {

statusMsg = "It's a tie!";} else if (data.win == 1) {

… document.getElementById("gstatus").innerHTML = statusMsg;// restart the pollhidden.location = url; //GET request that gets suspended

Comet Implementations in other servers• Tomcat 6

– CometProcessor• event(CometEvent event)• event.close()

• Jetty– Continuation

• continuation.suspend();• continuation.resume()

• Weblogic– AbstractAsyncServlet

• doRequest(..) and doResponse(..)• notify(..)

● Suspend..● Event.. wake .. ● Resume

Servlet 3.0• Defined by JSR-315 Expert Group

– DWR, Jetty, Tomcat, GlassFish project, and ICEfaces participants

• Standard asynchronous processing API being defined– Asynchronous I/O– Suspendible requests

• Suspend a response: HttpServletRequest.startAsync()• Resume a response: AsyncContext.complete()

• Will improve portability – of DWR, Cometd, ICEfaces etc

• Servlet 3.0 will supports only a subset of Comet

Project Atmosphere• Comet techniques aren't standardized among Web

Container– Grizzly Comet applications aren't portable (cannot run on

Tomcat nor Jetty)• Servlet 3.0 supports only subset of Comet• Project Atmosphere – portable Comet framework

– a POJO based framework using Inversion of Control (IoC) to bring Comet to the masses

• Suspend: @Suspend• Resume: @Resume

– A framework which can run on any Java based Web Server – can run on Servlet 2.5 compliant Web Server

– Can detect Servlet 3.0 too

Summary• The Asynchronous Web will revolutionize human

interaction• Push can scale with Asynchronous Request

Processing• Writing Games is not that complicated• With GlassFish project and Project Grizzly, the

revolution begins with your application today!• Try Atmosphere and Servlet 3.0

<Insert Picture Here>

Comet Everywhere: Building Asynchronous Collaborative Web ApplicationsLee Chuk MunnStaff [email protected]