A few years back I developed a custom tag library for The Java Pet Store to get around back button issues when a user decided to change the locale of the Java Pet Store. This was made possible by storing all the objects related to a specific request inside each HTML page using a application specific custom tag library. This technique was later adopted by Java ServerFaces to store the component tree information on the client.

In the BluePrints Solutions Catalog we generalized this technique of using a JSP custom tag library to allow a developer to easily and securely store state on the client. The following JSP fragment shows how simple it can be to securely store session state on the client.

<cs:client-state action="word" beanName="sampleBean" secure="true">
<table>
  <c:forEach var="word" varStatus="status" begin="0" items="${sampleBean.words}">
   <tr>
    <td>
     <input type="checkbox" name="word_${status.index}" value="${word}">
      ${word}
     </input>
    </td>
   </tr>
  </c:forEach>
  <tr>
   <td>
    New Word: <input type="text" name="newWord" size="25"/>
   </td>
  </tr>
  <tr>
   <td>
    <input type="submit" value="Update List"/>
   </td>
  </tr>
</table>
</cs:client-state>

The client-state tag acts like a form tag and wrapping a form submission. In the case the attribute "beanName" specifies a Java object (which implements java.io.Serializable) that is stored on the client. The "sampleBean" must exist in theHttpServletRequest scope with id "sampleBean". The "sampleBean" Java object is serialized and encrypted when the request is dispatched to the JSP page and the client-state tag is encountered. The resulting HTML page will look as follows.

   
<form method="POST" action="word">
  <input type="hidden" name="beanName" value="sampleBean" />
  <input type="hidden" name="sampleBean" value="rO0ABXNy AC5jb20uc3VuLmoyZWUuYmx1ZXByaW50cy5jbGllbnRzdGF0ZS5TYW1w bGVCZWFuhCyFzCR588MCAAJMAAhuZXh0UGFnZXQAEkxqYXZhL2xhbmcv U3RyaW5nO0wABXdvcmRzdAAVTGphdmEvdXRpbC9BcnJheUxpc3Q7eHBw c3IAE2phdmEudXRpbC5BcnJheUxpc3R4gdIdmcdhnQMAAUkABHNpemV4 cAAAAAJ3BAAAAAp0AARncmVndAAFaW5kZXJ4" />
<table>
   <tr>
    <td>
     <input type="checkbox" name="word_0" value="greg">
      greg
     </input>
    </td>
   </tr>
   <tr>
    <td>
     <input type="checkbox" name="word_1" value="inder">
      inder
     </input>
    </td>
   </tr>
  <tr>
   <td>
    New Word: <input type="text" name="newWord" size="25"/>
   </td>
  </tr>
  <tr>
   <td>
    <input type="submit" value="Update List"/>
   </td>
  </tr>
</table>
</form>
Notice that the form above contains a hidden field with the name "sampleBean" and value containing encrypted base64 encoded data. This is the serialized "sampleBean" object from theHttpServletRequest scope.

 

Before handling a request from a page containing the client-state tag the state must be decoded from base64 and decrypted (if secure is set to "true"). A utility class is provided as part of the client-state tag library to facilitate the decoding and decrypting as may be seen in the code sample below.

ClientStateDeserializer.deserialize(request,response);

This code above reconsitute the "sampleBean" Java object and place it in the HttpServletRequest scope.

After processing the request the server-side component may dispatch to a page that contains the same Java object. The end result is that the "sampleBean" object never exists outside of the HttpServletRequest scope.

Storing state on the client has the following benefits:

  • Scalability - A single server can support more clients. An increase in clients does not require more memory or database resources on the server.
  • Back Button is not a Problem - All state is saved in the page making the back button no longer an issue. What you see in the HTML page is the Java object used to generate that page.
  • Session Time-Outs not an Issue -HttpSession time outs are not a problem.

Saving state on the client does not come for free. Here are some of the drawbacks:

  • Computing Resources - There is a CPU cost associated with encoding/decoding and encrypting/decrypting of state for each interaction.
  • Bandwidth - Since all the state related to a page is sent back to the server on each request there will be more data sent.
  • Navigation must be from a form - The state is kept as HTML form hidden variables requiring page to page navigation to be from a form though links could use JavaScript to performs a form submits.
  • Browser Crashes - If the browser that contains the state crashes the state is lost.

What do you think about storing state on the client?

For a much more detailed description of the idea of client-side state management see:

https://bpcatalog.dev.java.net/nonav/webtier/clientside-state/frames.html

To download the client-state tag from:

https://blueprints.dev.java.net/files/documents/1713/14760/clientstate-installer.jar