Web applications often need to maintain session state that spans more than one request. Generally, session state in a J2EE[TM] application can be stored in any of these tiers:
Each tier has benefits and weakness for storing session state. An application can store session state in more than one tier and can choose to partition the session state among different tiers. Because storing state on the web tier with HttpSession is a well-known topic, and other choices like using stateful session beans have been discussed in many places, this solution focusses on storing session state on the client tier. This solution is useful when your application needs to store session state on the client side instead of, or in addition to, using HttpSession to hold the session state. One of the key requirements of this solution is that the state is stored securely and this solution achieves that.
There are several ways for a web application to store session state on the client tier. One possible solution is to use Cookies to store the state on the client. However, cookies have limitations in size and are not ideal in cases where you want to store session state on the client.
A more robust mechanism can be designed by using hidden form fields in HTML, some code for serializing and deserializing, an encoder, and a few other tricks. Both URL parameters and the Java objects need to be encoded so that a view can be regenerated exactly as it was left. This solution can provide a reusable means for web applications to store state on the client. Lets briefly sketch a solution and example.
HTML provides a means for placing state in forms as hidden fields. This state can later be retrieved on a subsequent POST. Code Example 1 shows how hidden fields are used to store state in an HTML form:
<form action="controller.do" method="POST">
<input type="HIDDEN" name="var1" value="value 1">
<input type="SUBMIT" value="Push Me">
</form>
Code Example 1: Using Hidden Form Fields to Store Session State
In the case of the above code example, clicking the Push Me button
causes the form and the data to
be submitted as an HTTP POST to the web component mapped to controller.do
.
Note that using the HTTP GET
method instead of POST does not work with this solution because GET
encodes all form fields as URL parameters
creating a very long URL that may exceed the length supported by most
common browsers and web containers. Also remember that
the
HTTP GET method should be used for requests that are considered
idempotent, allowing the requests to be cached locally and by
intermediaries. You
can create links that appear to be <a href="someurl">
tags, but use JavaScript[TM] events associated with them to post the
form
containing
the client-side state. A link to submit the form Code Example 1 would
be the following:
<a href="#" onclick="document.forms[0].submit(); return false;">
The Java[TM] language provides a mechanism for serializing objects
so
that they can be recreated in the same
state as they were at a earlier point in time. Combined with an
encoding scheme, the serialized content is
placed in the HTML pages sent to a client. In the case of the example
above, the encoded serialized data
would be placed as the value of attribute var1
. The
serialized
content can also be compressed if the amount of data being stored in
the page is large.
The web component to which the form is POSTed (a servlet mapped to controller.do
in the example
above) may access the hidden form variables using the HttpServletRequest
API. The web component
may deserialize the state and perform some action based on that state.
Client-side state can be used to reduce the amount of data stored in the HttpSession. It helps spread the state over a number of web pages, all of which are kept on the client-side. This can help reduce the memory requirements at the server, which increases scalability. However, not all state is appropriate to be moved to the client. Note the following while using client-side state:
RequestDispatcher.forward()
API have access to the original HttpServletRequest
and HttpServletResponse
objects so the state may be transferred to other web components in the
same container. If these components are in a different context, they
need to be capable of typecasting the deserialized class into
the desired object or use the reflection APIs to access the state. Some states that would be ideal for storing on the client includes page-specific states such as objects (JavaServer[TM] Faces uses the client state in hidden form elements technique as an option for storing view state). User specific objects that might normally be kept in the HttpSession, and objects such as shopping carts, search results, wish lists, and user information may be good candidates. States such as web application configuration state, large objects such as those containing images, or objects shared among users should not be kept on the client.
Storing state on the client may not be the best solution for you. There are performance penalties and bandwidth usage associated with storing state on the client. Consider storing state using the strategies described in this document on a case-by-case basis.
Any state that is stored on the client is susceptible to various kinds of attacks, such as the following:
Although the code for storing session state can be directly embedded in the JSP page and the web tier classes, it is more approprite to put this code into a custom tag for reuse. Encoding the URL parameters and Java objects, along with generating the HTML forms with the necessary hidden fields in such a way that they can be reconstituted upon subsequent requests, can be somewhat tedious. A reusable custom tag library can hide the complex details needed to do the serialization and encoding of URL parameters and conversational state.
For more details on implementing this strategy see the Client Side State Design Details document.