Pushlets - Cookbook
Author: Just van den Broecke
Date: $Date: 2007/12/04 13:55:54 $
This document provides a development guide. WORK IN PROGRESS....
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.
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.
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.
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.
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.
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.TO BE FINALIZED...
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).
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.
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
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.
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.
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.
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:
Some examples are presented next. First the problem/issue is presented, then a hint at a possible solution through extension.
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.
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.
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.
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.
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).