Browser window bound application context

The problem: multiple windows

Suppose that you write an application that will have the ability to open multiple windows at once. These windows will contain views for different application modules. Sometimes, different windows will show the same module, but the data or it's presentation form will be different. It is obvious that each of the windows has an amount of state information associated with it. The HTTP protocol is by design stateless. Because statefullness is necessary for a multitude of applications, cookies mechanism was introduced. Usually, the cookies passed between the server and browser carry only an identifier of the session. The actual data is kept in the servers memory (or other storage device) Unfortunately cookies are not appropriate for managing state information associated with a single window. The primary way of overcoming this limitation is encoding information about the subset of data to be displayed and the presentation details (like sorting order) into the request URLs. This technique allows the user to maintain multiple simultaneous sessions with the same screen of the application in different browser windows, viewing different data sets or using different presentation settings. This technique might be unacceptable in two situations:

  • the presentation settings should not be visible in the URL so that the user can not tamper with them.
  • the amount of state information is large and/or the generated page contains large number of links. This would lead to generating large amounts of markup, decreasing application responsiveness and consuming resources.

The solution: server side window context

A technique similar to that applied to global session data. Window specific information can be stored on the server, and an token allowing to uniquely identify this information can be added to all URLs generated on the page. This way on the next request originating from a given browser window, the application has access to the state information associated with this window.

The problem: "Open in new window"

If opening of windows in a multi-windowed application is utterly under control of the application (the window is created using JavaScript, with context identifier token removed from the URL, to inform the application that it needs to create a new context) window contexts will work fine. In reality users will often create new windows using "open in new window" command, or by dragging URLs between windows. In each of the situations mentioned above, multiple windows displaying the same URL (and thus, by definition the same collection of cookies will appear. These windows are indistinguishable to the application, but it is undesirable that these windows share the window context. That would mean that changes to the state information performed in one window would affect all future requests to the other windows in the group.

The solution: session context tree

To effectively detect opening of windows, the token identifying a session context must be different for every request. Please recall the example of a few windows opened "open in new window" command. All of them share the URL, and the context identifying token contained in it. This means that they can access the state information that was valid during the previous request. The data subset displayed and the presentation settings used in all of the windows is the same. But because there are multiple windows now, the session context must split. New contexts must be created, inheriting the contents of the parent (previous) context, an tokens identifying these newly generated context must be included in all URLs generated on the associated pages.

The problem: the "back" button

While reading the previous paragraph, you may have an impression that it is possible to perform educated guesses about context branching points and store only as many contexts as there are windows simultaneously open. But when you consider the situation when user uses "back" and "forward" buttons to navigate the application, you'll find out that ALL of the contexts must be remembered by the server. The state information associated with each request may be used multiple times in the future. An LRU garbage collection scheme could be performed on the context objects (only a fixed number of most recently accessed context would be remembered) to conserve server's memory. Unfortunately, this could easily lead to undesirable application operation. Imagine an application with two windows open. An user performs an operation in the window A, then switches to window B an performs so many operations in it that the context of the window A is discarded. Then, performing an operation in the window A may yield unexpected results because the state information was lost.

Explicit vs Implicit cloning.

All of the the session contexts have to be replicated per every hit to the application. Memory consumption seems like an important factor to consider here. I had an idea of reducing it a bit, by requiring the programmer to explicitly copy the data from the previous context to the current context that are important. This is makes using session contexts tedious, but avoids cloning unused data over and over, when the user moves from one screen to another (which will obviously need different state information). This has the following downside - when the user uses a link to go back to a screen that he visited earlier, the state information will be lost, because the other screen didn't clone it (because it had no idea about them). The presentation details will be reset to normal. On the other hand, if the user pressed the "back" button multiple times to go back to that screen, the presentation details would be remembered (the URLs contain valid context identifier tokens). The conclusion is, that cloning all of the stuff contained in the context gives a better user experience. Memory is cheap these days, right? Oh, don't worry that those context have to stay in memory forever. They should be bound to a global (cookie style) session and discarded when the global session times out.

A sketch of implementation

  • SessionContext interface similar to that of ServletSession
  • getGlobalContext() and getLocalContext() methods in RunData
  • a wrapper object containing a global context and multiple local context keyed by id, to be stored in the HTTP session
  • context id tokens automatically picked up (after ParameterParser runs) and the context extracted/cloned/created as needed using the wrapper object from the session, and appropriate contexts made available through RunData
  • context id added to the url by the DynamicURI et al