Skip to main content

Track Conversation State on the Client using Applets

May 29, 2007

{cs.r.title}



This article proposes a new approach to maintaining session
state at the client side using an applet. In scenarios where
conversation state requires a lot of information to be persisted in
between requests, HTTP session maintenance becomes a scalability and performance bottleneck. The new approach alleviates the server
load, as the server spends energy on actual request
processing, rather than bothering about each client's state.

We will start with how conversational state is stored in today's
web applications, and specifically question the use of HTTP
sessions to store state. Next, we will introduce an interesting
characteristic of the applet. We will look at the new approach of
using the applet to maintain state at the client side, and how it can
be implemented in an e-book shop scenario. We will wrap up with some
limitations and extensions to the idea.

The Problem

Web applications often require a large amount of data to be
stored to maintain the session state of the clients, spanning
multiple requests. There are multiple options to store session
state, including hidden form fields, cookies, the web layer (the
HTTPSession), the EJB layer (rarely, if you are a fan of
stateful session beans), and finally the database. (The last thing
you want to do is use your database as a "scratch pad" for each
client!) Experience says that storing state information at the
database or EJB layer has limitations and performance
concerns.

For a browser-based web application, whose architecture is
realized through a servlet on the server side, it is typical that
we store the client's session state at the server end. This means
that we dump the aggregation of the data of all clients into HTTP
sessions. As a result, our architectures have inherently given way
to overloaded servers that spend more of their energy and potential
in maintaining clients' HTTP session state rather than actually
serving requests. Yes, we do have the option of scaling the servers
to meet the concurrency needs beyond these constraints through
clustering or other methods. However, the fact remains that the
much of the effort spent by servers in maintaining HTTP state
information for each client (in terms of space complexity) is very
high compared to the actual servicing of the client requests.

Let's plug in values to see the order of magnitude. Suppose that
for a typical web application, an application server stores 300K of
data per client HTTP session and is expected to serve 1000
concurrent users. Straight away, 300MB of memory is eaten up by
the server's function of maintaining clients' HTTP session states,
leaving the rest for actual request processing.

The real problem, the reason that the server is made to store
all the HTTP session states of the clients, is that the HTTP
protocol is stateless. That means that between two requests, a
client communicating through HTTP to a server will lose track of
the data stored in the current session or conversation. So, we
decided to dump states of all clients on the server. That is
exactly the point. Now, let us see an alternative to work
around this problem.

A New Approach

Here, I propose an applet-based approach to persist HTTP state
information on the client end that can replace some of the
techniques discussed above. The idea is to distribute an applet to
each client on the first HTTP request. This applet would be
persisted as long as the conversation with the server, or according
to the business logic. Each client's state information will be
tracked using the applet at its own end. Between multiple pages of
navigation, the applet would serve as a "session tracker." The
applet will be disposed when the conversation is over with the
server according to the business logic (for example, the checkout
option on an e-shopping site) or when the user closes the
browser.

To visualize how it would work for an e-shopping application, we
will look at a simple e-book shop that sells different types of
books. The application consists of multiple web pages containing
books classified just as they are on Amazon.com. As the user navigates the
pages in the website, he can keep adding books that he intends to
buy to his "shopping cart."

In the traditional method of storing client session state in the
server's HTTP session, the browser would post HTTP requests to the
server and the server would maintain the shopping cart. Instead,
what we are going to do is to update the session state stored in
the applet residing the client side. One plus is that we don't
communicate over the network here to update session state. Another
advantage is that the server is going to bother about a client
only when it actually requires server-side processing and
validation, not when the user does trivial actions like
deleting or modifying his shopping cart.

On login, the server would send back an applet to the user,
which acts as the shopping cart for the user throughout the current
session. One way to do this is to embed an applet tag
in the returned HTML/JSP page, so that the applet is loaded and
initialized in the client's browser. This effectively bootstraps
the applet as the shopping cart for the user.

Each time the user modifies his shopping cart by adding or
removing books or changing the quantity of books purchased, a
JavaScript would be invoked, which in turn delegates the call to
the applet. But how? The concept here is that when we embedded the
applet inside the returned web page, we made it a part of the
Document instance in the browser, as per the DOM
specification. For a more details on how JavaScript can communicate
with an applet, see the Resources
section.

Remember, to use the applet as a session tracker, the session
state data need to be persisted across pages until the user decides
to check out. But we have a problem: when the user clicks to move
on to another page, the browser simply moves the existing Document
instance to History and creates a new Document. Consequently, our
applet--part of the Document--along with the session state data
is lost. To overcome this problem, we use a simple yet interesting
characteristic of applets:

Applets share classloaders if and only if applets have the
same codebase, cache_archive,
java_archive, and archive.

Actually, this is the crux of the entire article, so let's
understand this better. An Applet runs on a client's
JVM. When we embed an Applet in a web page, the
browser downloads the code for the Applet from the
specified codebase on the server. The Java plugin
mediates between the browser and the JVM to run the applets (see
Figure 1 below). The JVM runs through the stipulated security
checks and verification before loading it on the
AppletClassloader. Once it is loaded, we can use JavaScript
to talk to the Applet. Next, when the user moves to a
new web page (by clicking a link, for example), if the next page
contains an Applet with the same
codebase, then the Applet on the new page
also will be loaded on the same classloader. Here is how we use
this characteristic for our shopping cart application.

  • Embed the shopping cart Applet (with the same
    codebase) across all the pages in the book shop.

  • Keep posting data to the Applet through JavaScript.
    The Java plugin establishes a connection between the browser and
    the JVM under the covers.

  • During the Applet.destroy() (when the user moves
    away from the page), dump the state to a static member in the
    Applet.

  • State data will be retained when the Applet is
    reloaded in the next web page. During the
    Applet.init(), this static member can give back the
    retained state.

Figure 1 show an illustration of the concept.

<br "How conversation state is maintained at the client side" width="446" height="601" />
Figure 1. How conversation state is maintained at the client
side

The applet tracks and stores the local changes made by the
client until the final billing is requested. Finally, at checkout,
it is time for the server to bill the cart up and revert with the
confirmation of the transaction. At this point, the data in the
static session state holder is collected and sent across as a
consolidated list to the server, which does the validation and
business logic on it before completing the transaction.

Understanding the Code

Let's briefly run through the code. The class diagram for the
code is shown in Figure 2.

Class Diagram
Figure 2. Class diagram

The PersistentClientDelegate is our
Applet that we embed in every page of our e-book shop.
The important methods here are the lifecycle methods
init() and destroy() and
addToCart() and getCart(). During the
init() method, when the applet is initialized and
loaded, we set up the shopping cart. If there is an existing model
that was persisted, that would be used to set it up. In this case
you can see the books purchased so far in the view. Otherwise, a
new model is created, which logically demarcates the start of a new
conversation. Again, this can be customized per requirements.

                [prettify]
import java.applet.Applet;

public class PersistentClientDelegate extends Applet {

  ShoppingCartController shoppingCart;
  static ShoppingCartModel holder;

  public void init() {
                
    shoppingCart = new ShoppingCartController();
    if (holder == null) {
        //This means we are starting a new conversation --
        //An new empty shopping cart is created ...
        holder = new ShoppingCartModel();
    } else {
        //This means we are reading the shopping cart 
        //that has been persisted ...
    }

    //Ask the Shopping Cart Controller to initialize
    shoppingCart.setUpShoppingCart(holder);
  }

  public void start() {
  }

  public void stop() {
  }

  public void destroy() {
    //This is the key -- Persist the model to a static member 
    //You can get it back later when Applet is reinitialized 
    //Refer init method above 
    holder = shoppingCart.getModel();
  }

  public void addToCart(String bookName, 
                        String cost, String bookID) {
    //Ask shopping cart to add a new book ...
    shoppingCart.updateCart(ShoppingCartView.ADD_BOOK, 
                new Book(bookID, bookName, 
                        Integer.parseInt(cost)));
  }

  public String getCart() {
    //Ask shopping cart for the latest list of books for
    // final processing ...
        return shoppingCart.getModel().toString();
  }
}
                
[/prettify]

As for the onscreen shopping cart as seen by the user (see the
Resources section), we have a Java
Frame as the view component to display the current
state. Our sample application is an MVC design, with a
ShoppingCartView for displaying the cart, a
ShoppingCartModel to store and persist data across
pages, and a ShoppingCartController. When the user
adds a book to the cart, the book is added to the
ShoppingCartModel and the controller ensures that the
view (frame) also gets updated accordingly. Similarly, the user is
allowed to remove purchased books from the shopping cart by
clicking the Delete button. This is again reflected on the
ShoppingCartModel. The applet and the contained MVC
components basically reside on the browser's JVM. You can watch
this while trying out the application, as you click on the first
link on the home page to browse books, the Task Manager (or
ps on Linux) would report a slight increase in memory
usage and the spawning of a new Java process. Finally, the
JavaScript is the easiest part: simply invoke the applet
methods.

                [prettify]        

function doSelectBook(applet)   {
    //The user has clicked on Add to Cart 
    //Delegate the call to the applet
    applet.addToCart( parameters );
} 

function completeTransaction(document)  {
    var cart=document.myApplet.getCart();
    document.writeln("Books Purchased :");
    document.writeln(cart);
    //Typically, call middle tier here ...
}
                
[/prettify]

Limitations

Of course, this approach has all the limitations that any applet-based client has. Applet-flavored user interfaces require a basic
Java runtime at the client side. Especially when the application is
accessed over the internet, this means that some users need to
download and install Java plugins for their browsers. It is
easier, however to do that across all user desktops if the
application runs within a managed intranet.

Another effect of this approach is that the client machine needs
adequate memory to store session data. Since we are deploying our
applet as the delegate at the client side to store session state,
any memory leaks could crash the user's browser or JVM. To avoid
this, memory requirements need to be analyzed and taken care during
development.

However, if you are wondering if security is a limitation, think
again: our session tracker would be loaded on the
AppletClassloader which has strict but customizable
security features. See the Resources section
for pointers to related articles.

Extending the Idea

Using an applet as a session state tracker is just one application of a
powerful concept. Deciding whether to use an applet or not is the
crucial question. Once you decide in favor of it, it throws open a
completely new set of options to you as a designer or
architect.

One of them I am thinking about is something I have named
"Asynchronous JavaScript with Applets" (AJAPP). This is
basically using the applet to make asynchronous calls to the
server. All it takes is to design the applet in such a way that the
JavaScript call to the applet would be immediately returned. The
actual request to the server is done by the applet in the
background on the client side through XML-RPC (if you would like), or
simple HTTP, or any other communication protocol. Figure 3 shows
what it looks like when compared to AJAX.

<br "Asynchronous JavaScript with Applets" width="441" height="572" />
Figure 3. Asynchronous JavaScript with Applets

Conclusion

Today, when we talk about the presentation layer of an
application, we hear about Struts, JSF, Spring MVC, Beehive NetUI,
AJAX, and newer things daily. In the recent past, we have also
heard that applets were on their way out. This article introduced a
less known powerful characteristic of the applet, and on that basis,
a novel technique to maintain conversation state at client end.

Resources

width="1" height="1" border="0" alt=" " />
Ganesh Ram Santhanam is a graduate student at the Department of Computer Science in Iowa State University.
Related Topics >> Web Design   |