The Source for Java Technology Collaboration
User: Password:
Register | Login help    

Search

Online Books:
java.net on MarkMail:


 E-mail  Print

Track Conversation State on the Client using Applets

Tue, 2007-05-29

{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.

How conversation state is maintained at the client side
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.

                
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();
  }
}
                
        

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.

                        

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 ...
}
                
        

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.

Asynchronous JavaScript with Applets
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

Ganesh Ram Santhanam is a graduate student at the Department of Computer Science in Iowa State University.
Related Topics >> Web Design      
Comments
Comments are listed in date ascending order (oldest first)