Demonstration Quick Link

In Part 1 of this series, we saw how event driven AJAX (a form of Comet) can be used to push data to the client without the need for periodic client side polling. However, we also observed that event driven AJAX broke as soon as the client had multiple views of the same page. Worse still, event driven AJAX in its current form also fails to support having more than one page open on an event driven AJAX site. This this article we will investigate how to solve this issue.

Overview

When I committed in part 1 of this series to demonstrating event driven AJAX working on multiple view of the same page, I did not realise the size of the commitment I was making. The problem that I was aware of was that there was one event queue for the session, rather than an event queue for each page. Not a very difficult problem to solve, but not necessarily a trivial problem either. In preparing the demonstration for this article, I discovered a far more serious problem that I had read about but never fully appreciated. The HTTP 1.1 protocol specifies that a client may only have two open connections to the one domain. This means that if the browser has two tabs (or windows) open to the same site, then no other connections can be made to that site; no images, no AJAX, no nothing. This can be observed by opening the demonstration from the previous article in multiple tabs (or windows) and clicking on the darken or lighten page link. The browser, already having two open connections the the site (in the form of getEvents XMLHttpRequests) queues the darken/lighten XMLHttpRequest until one of the getEvents requests closes. The getEvents request are waiting for a darken/lighten event to occur (along with other events), hence a deadlock ensues.

JAHA to the rescue

Unfortunately there is no trivial way to overcome this limitation, at least not in Javascript. Looking elsewhere for solutions for this problem, ActionScript from Macromedia seams to be a common solution, however not being familiar with ActionScript I decided to dig up an old, almost forgotten tool, Java appets. I'm sure the memories are already flooding back from the late 90's of ugly web pages full of ugly Java applets; A time when web designers didn't seam to care about the jarring disconnect between the page and the applet. But it needn't be so, using Javascript to communicate with hidden applets (JAHA) allows you to add client side functionality available in Java, without affecting the look and feel of your site. Using JAHA over ActionScript also adds the possibility of using other methods of communication besides HTTP, such as JMS and TIBCO Rendezvous.

Event Driven AJAX Event Flow Diagram

Figure 1 – Event Driven
AJAX Event Flow Diagram

In Figure 1, you can see how the applet is used to perform a "long poll" on the server, whereas in the previous demonstration a XMLHttpRequest was used for this purpose.

Page Sessions

Now that the browser can (via the applet) have more than two open connections to the server, we can address the next problem getting events published to every view of the page. In order to achieve this, the session is extended to support a concept of page sessions. A page session works by assigning a pages session ID to each view of a particular page. This ID is used to index and array within the session, which contains a page session.

In the previous demonstration, there was one event queue per session, this meant that a event would only go out to one of however many views a user had of the page. By moving the event queue to within the page session, we can now send events to each view of the page. In order to make sure the right events go to the right views, the applet performing the long poll must specify to the server script which event queue it is interested in. This is achieved by passing the page session ID as part of the query string in the get events request.

In order to prevent the session from becoming very large, the number of page sessions that can exist concurrently may be limited (in the demonstration there is a 5 page limit). When the limit is exceeded (and depending on where it is exceeded from), the page session creation function will either return an error or proceed without creating a new page session. In the case where an error is returned, javascript can be used to inform the user that they have two many windows open.

Demonstration

The demonstration for this article uses JAHA and page sessions to extend the previous demonstration to support multiple views of the same page. Details of how to use the example can be found in the previous article in this series.

How it Works

The demonstration pushes data to the client by:

  1. Using a hidden applet to send a HTTP Request with a page session ID to the server, which executes a PHP function called getEvents.
  2. The getEvents function checks the event queue for that page:
    1. If there are events on the queue, it removes the events from the queue and returns them in an array
    2. Otherwise the function waits till there is at least one event to return at which point it removes it/them from the queue and returns it/them in an array.
    3. If the script times out, a array is returned containing a timeout event.
  3. The applet received the response, passes it on to the javascript function gotEvents
  4. The applet sends off another HTTP Request (see step 1)
  5. gotEvents processes the events and updates the page accordingly
Source Code

The source code for the demonstration is available under the BSD license.

Scalability

This version of the demonstration has the same server side scalability problems as the previous example. However because we are now using an applet instead of javascript to perform the long polling, it is quite feasible to switch from using a long lived HTTP connection, to using JMS, TIBCO Rendezvous or similar, where long lived connections are the norm, rather than an exception.

Conclusion

Using JAHA and page session allows the event driven AJAX to scale to support user having multiple views of the same page, and correctly updates each page as events occur. Having addressed the scalability issues on the client, the next article in this series (I should learn not to make promises) will replace the long lived HTTP connections with a more scalable messaging system.