Pushlets - Cookbook

Author: Just van den Broecke
Organization: Just Objects B.V.
Email: just[AT]justobjects.nl

FileID: $Id: cookbook.xml,v 1.11 2007/12/04 13:55:54 justb Exp $
Date: $Date: 2007/12/04 13:55:54 $

This document provides a development guide. WORK IN PROGRESS....

1. Application Development

The Pushlet framework is basically a message exchange. One part of your application will be dealing with generating and sending messages (called Events) to the framework, the other part (usually the browser) will be receiving messages. The new (v2) protocol also allows clients to both publish and subscribe to events. The common two tasks for application development involve (1) creating the message sources and (2) developing the receivers. As we shall see the Pushlet framework has various possibilities in order to develop senders and receivers. Since interfacing may even be done entirely through HTTP (and XML) you may develop an application in any programming/scripting language that supports HTTP.

1.1. Events

The message should adhere to/src/nl/justobjects/pushlet/core/Event.java. Currently Event is a flat message with a topic identifier called thep_subject. Dependent on the client technology different encodings are applied to transfer Event, the main two being JavaScript and XML.

1.2. Developing Senders

There are three possibilities to send events to the Pushlet framework: remotely using the Pushlet protocol or locally, using EventSource or directly to the Dispatcher class. Each is discussed next.

1.2.1. Direct Publishing (local)

Your application may directly publish Events by using /src/nl/justobjects/pushlet/core/Dispatcher.getInstance().java. Since Dispatcher is (currently) a Singleton, sending the Event is a matter of callingDispatcher.getInstance().multicast()/unicast()/broadcast().

The other two methods (EventSource and Pushlet protocol) will eventually call Dispatcher.getInstance().multicast()/unicast()/broadcast().

Note that in order to call Dispatcher.getInstance().multicast()/unicast()/broadcast(), your class needs to be in the same classloader as the Dispatcher.getInstance(). This may be an issue when for example your sender is in another web application. You may use the Pushlet protocol in that case or put pushlet.jar on the system CLASSPATH. In Tomcat you can also make pushlet.jar a shared library.

1.2.2. Using EventSource

An EventSource is an object that is managed (activated/passivated) by the Pushlet framework. Developing your own EventSource involves creating a class that implements nl.justobjects.pushlet.core.EventSource (when your EventSource pushes Events to the framework) or that extends nl.justobjects.pushlet.core.EventPullSource (when the framework should pull your EventSource at dedicated intervals) and adding your EventSource to a properties file aptly namedsources.properties.

See /webapps/pushlet/WEB-INF/classes/sources.properties for an example. This file specifies which EventSource objects need to be created and managed. Note: since v2.0.3 sources.properties can also be placed under WEB-INF. See /src/nl/justobjects/pushlet/core/EventSourceManager.java how this is done. See examples in /src/nl/justobjects/pushlet/test/TestEventPullSources where several example sources are bundled.

During initialization the EventSourceManager will look for the file sources.properties in the CLASSPATH. Usually this file will be put under WEB-INF/classes.

1.2.3. Using the Pushlet protocol

The Chat and WebPresentation examples use the remote publication of events through the Pushlet (control) protocol. In a webapp the Pushlet JS API provides a p_publish() method through which your app may send events.

The /src/nl/justobjects/pushlet/test/PushletPingApplication.java provides a complete example illustrating sending and receiving Events and using/src/nl/justobjects/pushlet/client/PushletClient.java. DHTML clients may use the JavaScript pushlet library.

1.3. Developing Receivers

1.3.1. The Pushlet Request

Any client that wants to receive Events will make a HTTP request to the Pushlet servlet. This request requires at least two parameters: (1) the encoded Event format format=js|xml|ser|xml-strict where "js" is JavaScript, "xml" is XML, "ser" is Java serialized objects, "xml-strict" is like "xml" but events are contained in a complete document and (2) the subject (like a JMS topic). Note that subjects form a hierarchical tree naming space, i.e. specifying one level will subscribe to all subjects below. If you specify "/" all Events are received.

1.3.2. Using Pull Mode

The Pushlet servlet is the standard servlet used to receive Events. A Pushlet will basically send a stream of encoded Events as specified by the p_format parameter. In some cases (proxies, some servlet engines or browsers) the Pushlet may not be working properly. In that case the pull mode may be used. In pull mode the Pushlet servlet will send one or more Events and request the client to refresh the page. The client refreshes the page each time an event is received, but the request remains outstanding thus pull mode is more efficient than polling. For JavaScript clients it is transparent whether a "stream", "pull" or "poll" mode is active. Other clients (e.g. Java XML-based clients) should merely obey the protocol "refresh" event.

1.3.3. Using DHTML Clients

A DHTML client receives Events encoded as JavaScript callbacks. See most of the examples and the whitepaper how this is done. The simplest example is the temperature display. Seewebapps/pushlet/examples/weather/nl-temperature.html.

The JavaScript library webapps/pushlet/lib/js-pushlet-client.js provides an API that allows your app to access all services of the pushlet protocol. All API methods are named p_*().

1.3.4. Using AJAX Clients

Since version 2.0.2 AJAX clients can be developed using the library webapps/pushlet/lib/ajax-pushlet-client.js See for examplewebapps/pushlet/examples/chat. The first version of the AJAX library is forward compatible with webapps/pushlet/lib/js-pushlet-client.js so if you have existing apps you may simply replace this library and remove the p_embed()statement.


1.3.5. Using XML Clients

Any client that can receive XML over HTTP can be used. The Java Pushlet client (see/src/nl/justobjects/pushlet/client/PushletClient.java) uses the XML format, decoding incoming XML into Event objects.

If format is "xml" then Events are streamed as <event> elements. If format is "xml-strict" then <event> elements are contained in a <pushlet> element. The latter is applicable for "pull-mode" in AJAX clients (that require to receive a complete XML document).

1.3.6. J2ME Clients


1.4. Integrating Pushlets in your WebApp

Although you can develop with Pushlets by using and or modifying the standard web applicationpushlet.war, there may be cases where you want to integrate Pushlets in your own web application. Below are the steps for doing just that. We'll see which files are needed, where to place them and what minor modifications need to be done.

1.4.1. Required Files

Very few files from the standard Pushlet distribution are required to get up and running. These are listed below with their path relative to the top directory of your unpacked distribution i.e. pushlet-x.y.z/webapps/pushlet

  1. jar file: WEB-INF/lib/pushlet.jar
  2. config files: WEB-INF/classes/pushlet.properties and optionally (if you develop event sources) WEB-INF/classes/sources.properties
  3. client libraries: lib/js-pushlet-client.js and lib/js-pushlet-net.html for JavaScript clients. Only if you use applet or WebStart Java clients you 'll need lib/pushletclient.jar
  4. web config file: WEB-INF/web.xml in order to embed the pushlet servlet in your webapp

That's it. You may use (parts of) the examples and assets directories for testing or as a starting point for your application but only the above four categories are required. A bare minimum thus are 5 files (pushlet.jar,pushlet.properties, js-pushlet-client.js, js-pushlet-net.html and web.xml

Note: since v2.0.3 pushlet.properties can also be placed under WEB-INF. At startup the CLASSPATH is searched first followed by WEB-INF/pushlet.properties.

1.4.2. Placing the Files

You need to place the files listed above in exactly the same directories in your webapp. The exception is web.xml as your webapp will also need your ownweb.xml. See next.

1.4.3. Modifications

Assuming your webapp has its own WEB-INF/web.xml you will need to copy/paste the entire Pushlet <servlet> and <servlet-mapping> XML elements from the Pushlet web.xml.

The next step is to decide whether your application is going to use Event sources. If not you won't need sources.properties but you will need to disable Event sources inpushlet.properties. The line to change is


In order to verify test I usually take one of the example files like examples/raw/raw.html to test if connectivity is working.

That's it ! If you integrate Pushlets in your webapp you may next also extend core classes, so read on.

1.5. Advanced: Extending Pushlets

Your application may have specific requirements that may not be covered by the basic Pushlet framework. You may extend core classes (v2.0.3+) of the framework without modifying the core classes. This can be achieved by extending (through inheritance) the main core classes and declaring your extended classes inpushlet.properties. For example, if you need to extend SessionManager for authorization purposes you may declare your com.mine.ExtSessionManager class in pushlet.properties throughsessionmanager.class=com.mine.ExtSessionManager. At runtime the main core classes are created (factory method pattern) using the classes declared inpushlet.properties. Note that you should be maintaining the semantics of the framework. In many cases you can intercept method calls by calling super.method() before/after your specific code. The following classes may be extended:

nl.justobjects.pushlet.core.Controller nl.justobjects.pushlet.core.Dispatcher nl.justobjects.pushlet.core.SessionManager nl.justobjects.pushlet.core.Session nl.justobjects.pushlet.core.Subscriber nl.justobjects.pushlet.core.Subscription nl.justobjects.pushlet.util.DefaultLogger

Some examples are presented next. First the problem/issue is presented, then a hint at a possible solution through extension.

1.5.1. Caching Events

Problem: when a client subscribes to a subject you may want to send the current state first and then send updates. For example, a table of stock rates need to be filled first before receiving rate changes.

Solution: override the classes Dispatcher and Subscriber. Your Dispatcher.multicast() may store Events in a HashMap keyed by stock name before callingsuper.multicast(). Your Subscriber.addSubscription() may send the content of the HashMap of stock rates to the subscribing client before calling super.addSubscription()

Caching is often application-specific. In other cases, e.g. a chat you may want to cache the last N events using a List.

1.5.2. Notify on Subscribe/Unsubscribe

Problem: Your application needs notification when clients subscribe or unsubscribe to/from subjects.

Solution: override the class Subscriber and override all methods dealing with subscription: Subscriber.add/removeSubscription(s) Call super. first and then publish a custom Event through the Dispatcher.

1.5.3. Only Publish Events When There Are Active Subscribers

Problem: Your application only needs to send events when there are listeners for the topic.

Solution: override the class Subscriber and keep a map of "active topics" by intercepting all Subscriber.add/removeSubscription(s) methods. Then locally or remotely your app may fetch the list (or even a boolean) to determine if the Event needs to be published.

1.5.4. Custom Logging

Problem: You want to use a specific logging library likelog4j.

Solution: override the class nl.justobjects.pushlet.util.DefaultLogger using the property logger.class providing a custom logger class that calls your specific logging library.

1.5.5. Event Throttling

Problem: You don't want to push all events to each subscriber. Some subscribers may have a paid account.

Solution: override the class Subscriber and determine there if a Subscriber needs to receive all events. You may authorize clients by using a custom SessionManager (see above).