In a string of recent articles, I have discussed downloading, installing and running demos for a number of different tools, frameworks and libraries that support push-style (web) applications in one way or another. I have looked into ‘classic’ comet with Grizzly, Atmosphere and CometD as well as ADF Active Data Service and WebLogic Pub/Sub (Bayeux) Channels. I have also looked to WebSockets with jWebSocket, again Atmosphere and CometD and also with Kaazing. I am now working on a series of articles in which I use each of these frameworks and push infrastructures to implement the same simple push-style application – to see how that goes and to compare the various implementations. The functionality I will be implementing is simple:
- through the web client (HTML 5/javaScript), a user can select an image from a list of ’slides’
- the selection of the image is communicated to the server (background WebSocket based or alternatively regular AJAX)Comet (Bayeux)/Long Poll style)
- the server informs all connected clients about the selected image through a pushed message (background WebSocket based or alternatively Comet (Bayeux)/Long Poll style); these clients all synchronize that slide selection
- a Java (server side) component can also connect to the server and listen in to image selection events as well as publish image selection messages of its own
The first article discussed the implementation using WebSockets and Kaazing Gateway (https://technology.amis.nl/blog/14777/push-based-synchronized-slideshow-web-application-implemented-using-websockets-and-kaazing-websocket-gateway). In this article, I will present an implementation using the CometD framework.
I will use NetBeans as my IDE, Tomcat as the Servlet Container to run the application on and a combination of browsers (Chrome, Firefox and IE) to try it out.
Earlier articles described how to set up NetBeans (https://technology.amis.nl/blog/14661/first-experiences-and-getting-started-with-glassfish-3-1-and-netbeans-7-x-its-a-breeze) and Tomcat (https://technology.amis.nl/blog/14688/installing-tomcat-7-and-configuring-as-server-in-netbeans) – these may be helpful to get started. Another discusses getting the CometD demos running (https://technology.amis.nl/blog/14709/running-cometd-2-examples-locally-on-tomcat-using-maven-and-netbeans and https://technology.amis.nl/blog/14720/cometd-2-java-client-sample-open-project-in-netbeans-based-on-maven-pom-file-modify-sources-and-run-java-based-comet-client).
Create NetBeans project from Maven Archetype
Getting started with a new CometD project in NetBeans is very simple. From the Maven Archetype, NetBeans can create a project that not only has the dependencies set up correctly but also provides us with a simple starter application – including JavaScript library and JSP file – that is ready to run.
First, I needed to locate the proper archetype deatils for CometD with JQuery and Jetty 7 libraries:
http://mvnrepository.com/artifact/org.cometd.archetypes/cometd-archetype-jquery-jetty7/2.3.1
Using this information, I continue in NetBeans.
New project
Select the option to create the new project as Maven style project from an Archetype:
Press Next.
Press the Add button to create a new archetype. Enter the details for the archetype as found on the MVNRepository website:
Press OK.
Select the newly created archetype and press Next.
Enter some project details – such as the name and the location on the file system. Then press Finish.
A brief interlude follows in which NetBeans downloads the required resources.
:
Then, the new project is presented:
Note that the web application consists of a jsp file (index.jsp) that loads the required CometD jQuery JavaScript resources as well as the application specific JavaScript library application.js.
The project is ready to run as is
after associating it with a pre-configured servlet container:
and the browser is launched.
The application is functional – even though the functionality is somewhat limited at this point.
Note: it turns out useful to assign a proper context path the application – in the Project Properties dialog on the Run tab:
Implementing the Slideshow web application (HTML and JavaScript)
The HTML (in the file index.jsp) is simple and straightforward:
The real work in the web client is done in JavaScript. Partially in the setSlide() function called when a slide is selected by the user through clicking on the link and partially in the function that through jQuery is added to the body to be executed when the document has loaded.
The page includes various JavaScript resources (note: that was set up when the project was initially created from the Maven Archetype):
The last one – application.js – is application specific but initially contains only generic code. It contains the code required to get communication going with the back end CometD Servlet. I have made a only a few changes to this file – creating most application specific JavaScript in the index.jsp itself.
The variable cometd is now a global variable – in order to provide access to it from my own functions in index.jsp:
I have removed the generated code that leverages the CometD Echo Service to print out a demo message. Near the end of the application.js file, I have added a call to function setup().
This function is defined in index.jsp
It initializes the slide variable – referring to the IMG element holding the current slide. It subscribes the function slideListener to the /slide/show channel.
Note: no client or server side configuration of channels is required in order to start using them. The channel is ‘instantiated’ when the first subscription takes place.
The slideListener callback handler is invoked whenever a message is received on the /slide/show channel:
It is almost exactly the same as used in the example for Kaazing – it has no CometD or WebSocket dependencies. There is one difference: the slideEvent itself is a JavaScript object – not a JSON string that first needs to be evaluated (CometD handles this for us I presume). The data property of this object contains the application specific functional payload. Below is an example for Firebug where a breakpoint in the slideListener reveals the data in the slideEvent.data property:
The slideEvent object itself contains some meta-data as well:
The function adjustSlide with some helper functions was also used for the Kaazing example:
Based on the slideNumber parameter, adjustSlide will set the src of the slide variable (or the IMG element) to the url for the selected image. It then also highlights (in blue) the corresponding link.
When the user clicks a link, the corresponding image is also displayed and now an event is published to the /slide/show channel. This happens from the setSlide() function:
The message that is published is a Java object – that will be transported in some JSON serialized format.
This completes the implementation of the client. We can now run the Slideshow client in multiple browsers and see how they synchronize:
You need to see this in action – as pictures cannot really demonstrate what happens.
Compared to the implementation of the Slideshow with the WebSocket Kaazing Gateway (https://technology.amis.nl/blog/14777/push-based-synchronized-slideshow-web-application-implemented-using-websockets-and-kaazing-websocket-gateway), the HTML is exactly the same and the JavaScript code has a lot of overlap as well. Only where the publication of events is concerned or the reception of messages, there is an (obvious) difference.
Implementing the Slideshow Java client application
In addition to the HTML Web Client for the Slideshow, I want to implement a Java (possibly server side) component as well. This will be a Java Class that can connect to the CometD servlet, subscribe on channels and publish to channels. In this case the class would subscribe to /slide/show and listen in on the message exchanged by the web clients. It can also publish slide selection events of its own to that channel, forcing slide selection for all connected web clients from within the Java code.
As my starting point for this Java client, I have used the class ConsoleChatClient (package org.cometd.examples) in the CometD release 2.3.1 Java Examples set. This class contains the generic code for setting up a BayeuxClient that liaises with the CometD Servlet that also handles the interaction with the WebClients. Once the generic handshake is done, my own Slideshow specific code kicks in to subscribe to the /slide/show channel, handle messages and even send messages of its own in a way that very similar to what happens in JavaScript.
My class is called SlideShowClient. It imports a number of classes from the CometD distribution. For the moment I have created the class inside the CometD Java Examples project that was created in NetBeans from the pom.xml file in COMET_HOME\cometd-java\cometd-java-examples. This means that all library dependencies are already configured:
The class has a main method that invokes the run() method.
The run method contains some generic code for making contact with the CometD servlet – on the address corresponding with the deployment of the Web Application discussed in the previous section. In this case this is “http://localhost:8085/slideshow/cometd“.
This code connects to the CometD server and prepares the application for what is next. For example: publishing events to the /slide/show channel:
using the BayeuxClient object, publishing onto any channel through the CometD server (Servlet) is extremely simple. See how in Java we create a Map – that arrives at the Web client through JSON as a JavaScript object.
The InitializerListener that is configured on the “Meta Channel” is shown below. It is activated when the Meta Channel Handshake is complete and the connection to CometD is established. Its onMessage method invokes – when the connection was successfully created – the initialize() method.
This method hands the client (BayuexClient) a batch of instructions to perform as one batch. The instructions are simple: get hold of /slide/show channel (either retrieve existing channel reference or create a new one) and subscribe the slideshowListener on this channel (and just to be safe and prevent duplicate subscriptions, first remove an existing subscription; this unsubscribe call does nothing if not subscriptions exists).
The slideshowListener is an inner class that implements the interface ClientSessionChannel.MessageListener. The onMessage method is invoked whenever the subscription on the slideshowChannel results in a message (that is: whenever an image selection event is published on /slide/show, for example by the web clients – or by this Java class itself.
When an image selection event is received – its custom payload is retrieved as a map. From the map, the properties uniqueId and slideNumber can be retrieved in more or less the same way as happens in the JavaScript function slideListener() used in the Web client discussed above.
Running the Java Client application produces the following output, with some slide selections taking place in the client and one pushed from the server:
Resources
Download sources as described in this article: SlideShowCometd.zip.
No Responses