Skip navigation.

Primer

Preparation

Working on a project that uses the CometD API requires some preparation, especially regarding tools, that can save you a huge amount of time.
One tool that should not be missing is Firebug (if you're using Firefox for development), or the equivalent for Internet Explorer 8, called Developer Tools.

The CometD project is built using Maven, and using Maven to build also your application is a natural fit.
The Primer will use Maven as the basis for the setup, build and run of your application, but the same concepts can be applied by other build tools as well.

Warning
If you are working in the Windows OS, avoid at all costs to use a path that contains spaces, such as "C:\Document And Settings\", as your base path.
Use a base path such as "C:\CometD\" instead.

Project Setup

The project can be setup in 2 ways, using the Maven Way or the Non-Maven Way.
For both, you can follow the detailed explanation of how some of the files of the project have been setup.

The Maven Way


Setting up a project based on the CometD libraries using Maven is very simple, and leverages the Maven archetypes, which create the skeleton of the project, in a style very similar to Rails scaffolding.
Issue the following command from a directory that does not contain a pom.xml file (otherwise you will get a Maven error), for example an empty directory:

$ mvn archetype:generate -DarchetypeCatalog=http://cometd.org
...
Choose archetype:
1: local -> cometd-archetype-dojo-jetty6 (CometD :: Archetypes :: Dojo and Jetty6)
2: local -> cometd-archetype-jquery-jetty6 (CometD :: Archetypes :: jQuery and Jetty6)
3: local -> cometd-archetype-dojo-jetty7 (CometD :: Archetypes :: Dojo and Jetty7)
4: local -> cometd-archetype-jquery-jetty7 (CometD :: Archetypes :: jQuery and Jetty7)
Choose a number:  (1/2/3/4): 

As you can see, there are 4 archetypes available, that build a skeleton application using the Dojo or jQuery JavaScript toolkits, both with the choice of using Jetty6 or Jetty7.
Let's choose Dojo with Jetty7, so choice number 3.
The archetype generation will ask few more questions and generate the application skeleton for you, for example:

Choose a number:  (1/2/3/4): 3
Define value for groupId: : org.cometd.primers
Define value for artifactId: : dojo-jetty7-primer
Define value for version:  1.0-SNAPSHOT: : 
Define value for package:  org.cometd.primers: : 
Confirm properties configuration:
jettyVersion: 7.0.1.v20091125
cometdVersion: 1.0.0
groupId: org.cometd.primers
artifactId: dojo-jetty7-primer
version: 1.0-SNAPSHOT
package: org.cometd.primers
 Y: : 
[INFO] BUILD SUCCESSFUL

Then:

$ cd dojo-jetty7-primer/

The skeleton project has now been created as follows:

$ tree
.
|-- pom.xml
`-- src
    `-- main
        |-- java
        |   `-- org
        |       `-- cometd
        |           `-- primers
        |               |-- BayeuxInitializer.java
        |               `-- HelloService.java
        `-- webapp
            |-- WEB-INF
            |   `-- web.xml
            |-- application.js
            `-- index.jsp

The skeleton project is ready to be run with the following command:

$ mvn install jetty:run
...

Now point your browser at http://localhost:8080/dojo-jetty7-primer, and you should see this message:

CometD Connection Succeeded
Server Says: Hello, World

That's it. You have already written your first CometD application :-)


The Non-Maven Way

The first step is to configure your favorite JavaScript toolkit, in our example Dojo, that must be served by the web container.
Using the Maven Way, this is obtained automatically by overlaying the CometD Dojo bindings war file, cometd-javascript-dojo-[version].war, but here must be done manually.
The cometd-javascript-dojo-[version].war is located in the cometd-javascript/dojo/target directory of the CometD distribution.

  • Unpack the Dojo toolkit to a directory.
  • Delete the dojox/cometd directory provided by Dojo and replace it with the one contained in the cometd-javascript-dojo-[version].war.
    The content of the dojox/cometd directory should be the following:

    dojox/cometd
    |-- ack.js
    |-- reload.js
    |-- timestamp.js
    `-- timesync.js
    
  • Delete the file dojox/cometd.js provided by Dojo and replace it with the one at the same path in the cometd-javascript-dojo-[version].war.
  • Add the org directory from the cometd-javascript-dojo-[version].war, and all its content, at the same level of the dojox directory.

The final content, equivalent to that produced by the Maven way, should be like this, for CometD 1:

.
|-- dijit
|-- dojo
|-- dojox
|   |-- cometd
|   |   |-- ack.js
|   |   |-- reload.js
|   |   |-- timestamp.js
|   |   `-- timesync.js
|   `-- cometd.js
|-- org
|   |-- cometd
|   |   |-- AckExtension.js
|   |   |-- ReloadExtension.js
|   |   |-- TimeStampExtension.js
|   |   `-- TimeSyncExtension.js
|   `-- cometd.js
|-- WEB-INF
|   |-- classes
|   |   `-- org
|   |       `-- cometd
|   |           `-- primers
|   |               |-- BayeuxInitializer.class
|   |               `-- HelloService.class
|   |-- lib
|   |   |-- cometd-api-[version].jar
|   |   |-- cometd-java-server-[version].jar
|   |   |-- jetty-continuation-[version].jar
|   |   |-- jetty-servlets-[version].jar
|   |   `-- jetty-util-[version].jar
|   `-- web.xml
|-- application.js
`-- index.jsp

and like this for CometD 2:

.
├── dijit
├── dojo
├── dojox
│   ├── cometd
│   │   ├── ack.js
│   │   ├── reload.js
│   │   ├── timestamp.js
│   │   └── timesync.js
│   ├── cometd.js
├── org
│   ├── cometd
│   │   ├── AckExtension.js
│   │   ├── ReloadExtension.js
│   │   ├── TimeStampExtension.js
│   │   └── TimeSyncExtension.js
│   └── cometd.js
├── WEB-INF
│   ├── classes
│   │   └── org
│   │       └── cometd
│   │           └── primers
│   │               ├── BayeuxInitializer.class
│   │               └── HelloService.class
│   ├── lib
│   │   ├── bayeux-api-[version].jar
│   │   ├── cometd-java-common-[version].jar
│   │   ├── cometd-java-server-[version].jar
│   │   ├── jetty-continuation-[version].jar
│   │   ├── jetty-jmx-[version].jar
│   │   ├── jetty-servlets-[version].jar
│   │   └── jetty-util-[version].jar
│   └── web.xml
├── application.js
└── index.jsp

The org directory contains the new shared CometD implementation and the shared extensions, while the correspondent files in the dojox directory are the Dojo bindings. Other bindings exist for the jQuery toolkit, but the shared CometD implementation is the same.

The second step is to configure the server side. If you use Java, this means that you have to setup the CometD servlet that respond to the Bayeux messages.
The details of the server side configuration and service development are explained here for CometD 1 and here for CometD 2.

The last step is to write a JSP (or HTML) file that downloads the JavaScript dependencies and the JavaScript application, as explained in the following section.


Setup Details


The JSP file, index.jsp, contains the reference to the JavaScript toolkit dependencies and to the JavaScript application file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
    <script type="text/javascript" src="${pageContext.request.contextPath}/dojo/dojo.js.uncompressed.js"></script>
    <script type="text/javascript" src="application.js"></script>
    <script type="text/javascript">
        var config = {
            contextPath: '${pageContext.request.contextPath}'
        };
    </script>
</head>
<body>
    ...
</body>
</html>

It also configures a JavaScript configuration object, config, with variables that may be needed by the JavaScript application. This is totally optional.

The JavaScript application, contained in the application.js file, configures the cometd object and starts the application.
Here is a sketch of what the archetypes provide:

dojo.require("dojox.cometd");

dojo.addOnLoad(function()
{
    var _connected = false;

    function _connectionSucceeded()
    {
        dojo.byId('body').innerHTML = 'CometD Connection Succeeded';
    }

    function _connectionBroken()
    {
        dojo.byId('body').innerHTML = 'CometD Connection Broken';
    }

    function _metaConnect(message)
    {
        var wasConnected = _connected;
        _connected = message.successful === true;
        if (!wasConnected && _connected)
        {
            _connectionSucceeded();
        }
        else if (wasConnected && !_connected)
        {
            _connectionBroken();
        }
    }

    var cometd = dojox.cometd;

    // Disconnect when the page unloads
    dojo.addOnUnload(function()
    {
        cometd.disconnect();
    });

    var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
    cometd.configure({
        url: cometURL,
        logLevel: 'debug'
    });

    cometd.addListener('/meta/connect', _metaConnect);

    cometd.handshake();
});

Note the following:

  • The use of dojo.addOnLoad() to wait for the document to load up before executing the cometd object initialization.
  • The use of dojo.addOnUnload() to disconnect when the page is refreshed or closed.
  • The use of the function _metaConnect() to detect when the Bayeux communication has been successfully established (or re-established). This is totally optional, but highly recommended.
    Be warned that the use of the _metaConnect() along with the _connected status variable can result in your code (that in this simple example sets the innerHTML property) to be called more than once if, for example, you experience temporary network failures or if the server restarts.

    Therefore is it very important that the code that you put in the _connectionSucceeded() function must be idempotent.
    In other words, you have to make sure that if the _connectionSucceeded() function is called more than one time, it will behave exactly as if it is called exactly once.