Skip navigation.

CometD Extensions

CometD API: Extensions

The CometD implementation has the capability to add/remove extensions.
An extension is a function that is being called to give the chance to modify the message just before it is being sent (an outgoing extension) or just after it is being received (an incoming extension).

An extension normally adds fields to the message being sent or received in the ext object defined by the Bayeux specification (see here).

An extension is not a way to add business fields to a message, but rather a way to process all messages, including the meta messages used by the Bayeux protocol.

Extensions are normally setup on both the client and the server, since fields added by the client normally needs a special processing by the server; it may be possible that an extension is only client-side or only server-side, though.
Most of the times, however, they are needed in both client and server, and when the extension does not behave as expected, it's normally because the extension on one of the two sides is missing.

The JavaScript CometD Extensions are described in the next sections, and follow the same pattern used by the portable JavaScript CometD implementation: a portable implementation of the extension with bindings for the specific JavaScript toolkit, currently Dojo and jQuery.

Writing the Extension

An extension is a JavaScript object with 4 optional methods:

  • outgoing(message), called just before a message is being sent
  • incoming(message), called just after a message is received
  • registered(name, cometd), called when the extension is registered
  • unregistered(), called when the extension is unregistered

All 4 methods are optional, or there can be only one, or maybe two, three or all of them. If they are present, they will be invoked at the proper time.

Writing an extension that logs and counts the long polls is quite easy: we need a reference to the cometd object, that has the logging methods, and we need only the outgoing extension method:

var LoggerExt = function()
{
    var _cometd;
    var _counter;

    this.registered = function(name, cometd)
    {
        // Store the cometd object reference
        _cometd = cometd;
    };

    this.outgoing(message)
    {
        if (message.channel == '/meta/connect')
        {
            // Log the long poll
            _cometd._info('bayeux connect');

            // Count the long polls
            if (!message.ext) message.ext = {};
            if (!message.ext.logger) message.ext.logger = {};
            if (!message.ext.logger.counter) message.ext.logger.counter = 0;
            message.ext.logger.counter = ++_counter;
        }
    };
};

Note that also meta messages are passed to the extension methods; you normally have to filter the messages that the extension method receives by looking at the channel or at some other message value.
Note that the message can be modified by adding fields, normally in the ext field.

Note
Be careful to not overwrite the ext field that it may have been set by other extensions: check if it's present first.
It is also a good practice to group your extension fields so that there is no clash with other extensions (in the example above the only field - counter - is "grouped" in the message.ext.logger object).

The outgoing() and incoming() methods can avoid to return something, or return the message itself (or another message object). This means that the message has been processed by the extension and can therefore be processed by other extensions, if present, or processed by the implementation (either be sent to the server - for outgoing extensions - or be notified to listeners - for incoming extensions).
If null is returned by the extension method, this means that the processing should stop: the message will not be processed by other extensions and will not be further processed (therefore it will neither be sent to the server nor be notified to listeners).

Registering the Extension

The JavaScript CometD API defines 3 methods to manage extensions:

  • registerExtension(name, extension), to register an extension with the given name
  • unregisterExtension(name), to unregister the extension previously registered with the given name
  • getExtension(name), to obtain a reference to the extension previously registered with the given name

Following the example above, we can register the extension like this:

cometd.registerExtension('loggerExt', new LoggerExt());

From now on, the meta connect messages will be modified to carry the counter from the example extension above.

Unregistering the extension is similar:

cometd.unregisterExtension('loggerExt');

It is not possible to register 2 extensions under the same name.

You can register more than one extension, and they will be applied following the registration order: outgoing extensions methods will be called in registration order and, by default, incoming registration methods will be called in reverse registration order. See also the reverseIncomingExtensions configuration parameter in the configuration section.
For example, if you register extA and extB, then for outgoing messages the methods called are: extA.outgoing() and then extB.outgoing(), while for incoming messages the methods called are extB.incoming() and then extA.incoming().

Extension Exception Handling

While it is normally good practice to catch exceptions within extension functions, sometimes this is tedious to code, or there is no control about the quality of the extension (e.g. it's a third party extension).
The JavaScript CometD API provides a way to define the global extension exception handler that is invoked every time an extension throws an exception (for example, calling a method on an undefined object, etc.):

cometd.onExtensionException = function(exception, extensionName, outgoing, message)
{
    // Uh-oh, something went wrong, disable this extension
    // Object "this" points to the CometD object
    this.unregisterExtension(extensionName);

    // If the message is going to the server, add the error to the message
    if (outgoing)
    {
        // Assume we have created the message structure below
        var badExtension = message.ext.badExtensions[extensionName];
        badExtension.exception = exception;
    }
}

Be very careful to use the CometD object to publish messages within the extension exception handler, or you may end up in an infinite loop (the publish message is processed by the extensions, which may fail and call again the extension exception handler).
If the extension exception handler itself throws an exception, this exception is logged at level "info" and the CometD implementation will not break.
Note that a similar mechanism exists for listeners and subscribers, see here.

The following sections will explain in detail the usage of the provided extensions.