Author: Simone Bordet

  • CometD Introduction

    The CometD project provides tools to write server-side event-driven web applications.
    This kind of web application is becoming more popular, thanks to the fact that browsers have become truly powerful (JavaScript performance problems are now a relic of the past) and are widely deployed, so they are a very good platform for no-install applications.
    Point to the URL, done.
    Server-side event-driven web applications are those web application that receive events from third party systems on server side, and need to delivery those events with a very low latency to clients (mostly browsers).
    Examples of such applications are chat applications, monitoring consoles, financial applications that provide stock quotes, online collaboration tools (e.g. document writing, code review), online games (e.g. chess, poker), social network applications, latest news information, mail applications, messaging applications, etc.
    The key point of these applications is low latency: you cannot play a one-minute chess game if your application polls the chess server every 5-10 seconds to download your opponent’s moves.
    These applications can be written using Comet techniques, but the moment you think it’s simple using those techniques, you’ll be faced with browsers glitches, nasty race conditions, scalability issues and in general with the complexity of asynchronous, multi-threaded programming.
    For example, Comet techniques do not specify how to identify a specific client. How can browserA tell the server to send a message to browserB ?
    It soon turns out that you need some sort of client identifier, and perhaps you want to support multiple clients in the same browser (so no, the HTTP session is not enough).
    Add to that connection heartbeats, error detection, authentication and disconnection and other features, and you realize you are building a protocol on top of HTTP.
    And this is where the CometD project comes to a rescue, providing that protocol on top of HTTP (the Bayeux protocol), and easy-to-use libraries that shield developers from said complexities.
    In a nutshell, CometD enables publish/subscribe web messaging: it makes possible to send a message from a browser to another browser (or to several other browsers), or to send a message to the server only, or have the server send messages to a browser (or to several other browsers).
    Below you can find an example of the JavaScript API, used in conjunction with the Dojo Toolkit:

    
      
        
        
      
    

    You can subscribe to a channel, that represents the topic for which you want to receive messages.
    For example, a stock quote web application may publish quote updates for Google to channel /stock/GOOG on server-side, and all browsers that subscribed to that channel will receive the message with the updated stock quote (and whatever other information the application puts in the message):

    dojox.cometd.subscribe("/stock/GOOG", function(message)
    {
      // Update the DOM with the content from the message
    });

    Equally easy is to publish messages to the server on a particular channel:

    dojox.cometd.publish("/game/chess/12345", {
      move: "e4"
    });

    And at the end, you can disconnect:

    dojox.cometd.disconnect();

    You can have more information on the CometD site, and on the documentation section.
    You can have a skeleton CometD project setup in seconds using Maven archetypes, as explained in the CometD primer. The Maven archetypes support Dojo, jQuery and (optionally) integrate with Spring.
    Download and try out the latest CometD 2.1.1 release.

  • CometD 2.1.1 Released

    CometD 2.1.1 has been released.
    This is a minor bug fix release that updates the JavaScript toolkits to Dojo 1.6.0 and jQuery 1.5.1, and Jetty to 7.3.1 and 6.1.26.
    Enjoy !

  • CometD 1.1.4 Released

    CometD 1.1.4 has been released.
    This is a minor release that updates the JavaScript toolkits to Dojo 1.6.0 and jQuery 1.5.1, and Jetty to 7.3.1 and 6.1.26.
    Enjoy !

  • Jetty @ Eclipse Summit Europe

    I have presented the advanced features of Jetty at the Eclipse Summit Europe 2010.

    Highlights of the features that I presented are:

    • Jetty & OSGi, showing the full integration of Jetty with the OSGi world
    • Jetty’s asynchronous HTTP client
    • Jetty’s WebSocket protocol support
    • Jetty’s WTP integration
    • Jetty’s Cloudtide, for multi-tenanted deployments of web applications

    Here you can download the slides of the presentation.

  • Comet Panel Video

    In July I participated in London to the Comet Panel, organized by the London Ajax User Group.

    Me and a bunch of other Comet experts talked about our own Comet projects, and I talked about CometD.

    Here you can watch the video of the meeting (English, 1hr 38m).

  • CometD 2 Annotated Services

    A new feature that has been recently added to the upcoming CometD 2.1.0 release is
    the support for annotated services, both on server side and on client side.

    Services are the heart of a CometD application, because allow to write business logic that is executed when a message
    arrives on a particular channel.
    For example, in chat applications when a new member joins a chat room, the chat room’s members list is broadcasted to all
    existing chat room members.

    This is how an annotated service looks like:

    @Service("echoService")
    public class EchoService
    {
    @Inject
    private BayeuxServer bayeux;
    @Session
    private ServerSession serverSession;

    @PostConstruct
    public void init()
    {
    System.out.println("Echo Service Initialized");
    }

    @Listener("/echo")
    public void echo(ServerSession remote, ServerMessage.Mutable message)
    {
    String channel = message.getChannel();
    Object data = message.getData();
    remote.deliver(serverSession, channel, data, null);
    }
    }

    Annotations are great because they carry a semantic meaning to their annotation target.
    Even if you have not written a CometD service before, the code above is pretty straightforward, and it is easy
    to understand that the echo() method is invoked when a message arrives on the "/echo" channel.

    Annotated services also reduce the amount of boilerplate code, especially on client side, where it is typical
    to add listeners and subscribers as anonymous inner classes.

    Compare:

    bayeuxClient.getChannel(Channel.META_CONNECT).addListener(new ClientSessionChannel.MessageListener()
    {
    public void onMessage(ClientSessionChannel channel, Message message)
    {
    // Connect handling...
    }
    });

    with:

    @Listener(Channel.META_CONNECT)
    public void metaConnect(Message connect)
    {
    // Connect handling...
    }

    I find the second version much more readable, and since code is much more read than written, this is a fine improvement.

    Lastly, CometD annotated services leverage the standard annotations for dependency injection and lifecycle management,
    and therefore integrate nicely with Spring 3.x.

    Take a look at the annotated services documentation
    and to the CometD 2 Spring integration for details.

    Enjoy !

  • CometD 1.0 Released

    The CometD project has finally released its 1.0 version !

    I have already posted here about new features of the CometD project, but the 1.0 release is a further step forward in usability, stability and documentation.

    For those of you that did not hear about the CometD project, it is a project that implements the Bayeux protocol to provide two-way seamless HTTP communication, from clients to server and from server to clients.

    Any application that receives server-side events such as online games, online chats, online stock information, online sport results, online bet results, online content sharing, online social networking and so on is a potential perfect application that can use the libraries provided by the CometD project to greatly simplify development.

    An event arrives on the server, and it is communicated to the clients with minimal latency via HTTP (and of course through firewalls, proxies, and more generally "through the web").

    Such applications are generally dubbed as comet web applications (and you can read here who and when the term was coined).

    The CometD project ships the following libraries to develop comet web applications:

    • A JavaScript library, with bindings for the well known Dojo and jQuery toolkits
    • A Java client library, to be used, for example, in rich Java clients such as Swing applications
    • A Java server library, to be used to implement the logic behind you application

    There are also alpha version of Perl and Python libraries, and you can find more implementations at this page.

    Greg already blogged about the cool features of the CometD project, but I would like to emphasize how simple is to create your first comet web application with CometD, using Maven:

    $ mvn archetype:generate -DarchetypeCatalog=http://cometd.org
    ...
    $ mvn install jetty:run

    Two lines, that’s it, and the detailed guidance of the CometD primer.
    You don’t need to download and install anything, you can just start with the CometD primer, and you are ready.
    After that, you can import the Maven project into your favorite IDE, and use the Jetty Plugin to develop-deploy instantaneously.

    The documentation has much improved, and now covers the 3 major libraries shipped, in details.
    Add to that How-Tos and FAQs, and a completely searchable website, so that you can enter your query (try "howtos") and have the documentation page that refers to your search.

    Do you use Spring for your server side plumbing ?
    There are detailed instructions of how to integrate with Spring.

    The CometD project is a 1.0 release, but has already been deployed in many applications that range from few users to a potential of million of users, and proved to scale really well. No worries on this side, <shameless-plug>especially when you can have a company that backs you up</shameless-plug>.

    Enjoy !

  • Jetty supports Cross-Domain XMLHttpRequests

    The release of Firefox 3.5 included several new features for developers.

    One of the most interesting new features is the support for cross-domain HTTP requests made with XMLHttpRequest objects (see here for details) or, by using Mozilla’s terminology, cross-origin requests.

    It is well known that browsers enforce restrictions on the scripts that they execute, and one such restriction is the same-origin policy, which prevents a document or script loaded from one origin from getting or setting properties of a document from another origin.
    Here “origin” means the scheme, host and port of the URL, so for example a script downloaded from http://foo.com could not make a request – via XMLHttpRequest – to http://bar.com (different host) or even http://foo.com:8080 (different port).

    This is troublesome, especially for certain kind of applications heavily based on JavaScript like Cometd applications, that often need to interact with different domains.

    This same-origin restriction is so troublesome, that bright people figured out different ways of working around it.
    For example, in Cometd applications, the JavaScript client can use a transport that allows the Bayeux communication with a server on a different origin; such transport is based on JSONP, a technique that uses the injection of script elements in the DOM to connect to a server on a different domain.
    It works, but way less reliably than the standard, same-origin, transport that it is used by default in Cometd applications.

    Fortunately this troublesome restriction, which dates back to Netscape Navigator 2.0, has been addressed by a new W3C specification (the Cross-Origin Resource Sharing Specification), that however requires changes in how a client (such as the XMLHttpRequest object) and a server interact.

    Firefox 3.5 already implements this specification (and I guess we can expect most if not all other browsers to do the same in short time), so the client part is taken care of.

    For the server side, Jetty 7.0.0.RC2 now ships a servlet filter that implements the cross-origin specification allowing, for example, Cometd applications running on Firefox 3.5 to perform Bayeux communication with a server on a different origin using XMLHttpRequest instead of using the JSONP workaround.
    Needless to say, this makes the Cometd application more robust and reliable, and it is totally transparent for the application: just use a compliant browser, the latest Cometd JavaScript client and configure Jetty with the cross-origin filter. That’s it.

    You can find detailed information regarding Jetty’s cross-origin filter here, and regarding Cometd configuration for cross-origin Bayeux communication here.

  • JavaScript Cometd Implementation Refactored

    The Dojo project has pioneered the implementation of the Bayeux specification, but for example the jQuery project lacked a robust client-side Cometd implementation.
    This gap has been filled now, with a shared pure-JavaScript implementation and bindings for both Dojo and jQuery.
    This means that the bulk of the Cometd implementation is now in a single, pure-JavaScript file, and that users of either toolkit have a binding (a very small adapter code) that allows developers to use the JavaScript Cometd API as a first class citizen in the either toolkit.
    As a small example, this is how you use it in Dojo:

    dojox.cometd.publish('/mychannel', { mydata: 'foobar' });

    and this is how you use it in jQuery:

    $.cometd.publish('/mychannel', { mydata: 'foobar' });

     
    A good side effect of all this is that every bug or new feature is fixed or added to the shared pure-JavaScript file, and immediately both toolkits will benefit of that.
    The implementation has been totally rewritten since the one historically present in Dojo, and the following are the most interesting features:

    • better support for tweaking the configuration
    • split configuration and initialization steps to allow more flexibility in case of programmatic disconnects
    • extended and clarified the Cometd APIs
    • better notifications for failures due to server or network failures
    • automatic and configurable connection retries
    • incoming message and outgoing message interception
    • automatic bayeux transport negotiation, supporting long-polling and callback-polling transports
    • extensions such as timesync, message acknowledgement and transparent page reload

    Downloads, documentation and code is available at the Cometd website.

  • Property substitution in web.xml and the Jetty Plugin

    Many web applications are configured via web.xml.

    Primary examples of this are Comet web application, which are configured via a ServletContextAttributeListener: you may want different listener classes depending on the enviroment you’re working in.

    Another example is where Spring configuration files are provided via the contextConfigLocation context parameter.

    Here I want to show how to do property substitution in web.xml based on Maven2 profiles.

    Let’s start from the case where you don’t need property substitution.
    These are your web.xml and pom.xml files:

    // web.xml
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <listener>
    <listener-class>com.acme.CometInitializer</listener-class>
    </listener>
    </webapp>
    // pom.xml
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <build>
    <plugins>
    <plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
    <version>6.1.15</version>
    <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <connectors>
    <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
    <port>8080</port>
    </connector>
    </connectors>
    <webAppConfig>
    <contextPath>/</contextPath>
    </webAppConfig>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </project>
    

    As you can see, the pom.xml file specifies the Jetty plugin configuration, with no particular configuration needed: default values are good.
    The web.xml file specifies a listener class that initializes your Comet web application.

    Often times, however, you want your initializer to configure the application differently, for example by stubbing some functionality; as the initializer is complex, you write a different class.

    At this point, you want to be able to specify a Maven2 profile that modifies the web.xml with the suitable class (default or stubbed).
    Here’s how you do it:

    // web.xml
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <listener>
    <listener-class>${initializer.class}</listener-class> (1)
    </listener>
    </webapp>
    // pom.xml
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <build>
    <resources> (2)
    <resource>
    <directory>${basedir}/src/main/resources</directory>
    </resource>
    <resource>
    <directory>${basedir}/src/main/webapp/WEB-INF</directory>
    <includes>
    <include>web.xml</include>
    </includes>
    <filtering>true</filtering>
    <targetPath>${project.build.directory}</targetPath>
    </resource>
    </resources>
    <plugins>
    <plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
    <version>6.1.15</version>
    <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <connectors>
    <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
    <port>8080</port>
    </connector>
    </connectors>
    <webXml>${project.build.directory}/web.xml</webXml> (3)
    <webAppConfig>
    <contextPath>/</contextPath>
    </webAppConfig>
    </configuration>
    </plugin>
    <plugin> (4)
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
    <webXml>${project.build.directory}/web.xml</webXml>
    </configuration>
    </plugin>
    </plugins>
    </build>
    <profiles> (5)
    <profile>
    <id>default</id>
    <activation>
    <activeByDefault>true</activeByDefault>
    </activation>
    <build>
    <filters>
    <filter>${basedir}/src/main/filters/default.properties</filter>
    </filters>
    </build>
    </profile>
    <profile>
    <id>stubs</id>
    <build>
    <filters>
    <filter>${basedir}/src/main/filters/stubbed.properties</filter>
    </filters>
    </build>
    </profile>
    </profiles>
    </project>
    // default.properties
    initializer.class=com.acme.CometInitializer
    // stubbed.properties
    initializer.class=com.acme.CometStubbedInitializer
    

    Let’s review the changes step by step.

    1. We replaced the listener class with a property in the web.xml file.
    2. We added a resources section in the pom.xml file to reference both the standard resource location and the web.xml file.
      For the web.xml file we specified that the property-substituted version of the file must go in the standard maven output directory (by default ${basedir}/target, referenced as ${project.build.directory}).
    3. We added the <webXml> element in the Jetty plugin configuration, referencing the property-substituted version of web.xml.
    4. We added the configuration for the war plugin, so that building the war will reference the property-substituted version of web.xml.
    5. We created two profiles that reference different filter files, which will contain the property values to be substituted. The standard Maven2 location for filter files is src/main/filters.

    Now you can build your project as before by specifying the profile if you need the stubbed version, like this:

    // Normal build
    $ mvn clean install
    // Stubbed build
    $ mvn -Pstubbed clean install
    // Stubbed build with Jetty plugin
    $ mvn -Pstubbed jetty:run
    

    Enjoy !