Saturday, August 15, 2009

Handling JSF ViewExpiredException with Ajax server polling

One of the problem with JSF and other web technologies that are base on ViewState, is that when session expires, also view expires. In this case, when you are on a page, session expires and you do some action (like navigating between table pages or submitting a form) you get ViewExpiredException with a message telling: “No saved view state could be found for the view identifier: /some_page.jsp”. One way of solving this issue is by using a Filter or JSF PhaseListener that will catch the exception and redirect the user to the login screen or will automatically login the user again and direct him to some page (if user login information is stored on a cookie on the local machine). This is a nice solution, but it still doesn’t cover this scenario:

  • User leave computer on login screen.
  • Session expires.
  • User come back to the computer, enter login details and press the “login” button.
  • JSF throws ViewExpiredException that is being cached by Filter/PhaseListener and user is being redirected to the login screen and login details are being cleared.
  • User doesn’t understand what happened, tries to login again. This time ViewState already exists in session and login takes place successfully.

This case probably can be solved by all sort of solutions. One of them will be to simply write the login page without JSF. I heard that .NET technology allows a page to disable ViewState simply by setting a property: EnableViewState=”false”. I looked for a way of doing it in JSF and had no luck.

Anyway, there is a neat way of elegantly working around this problem by simply polling the server every fixed interval of time (for example 5 minutes), causing the server to never loose session as long as browser is open with our web application. If session never expires, ViewExpiredException will never be thrown.

Polling there server can be done in all sort of ways. I have chosen what I think is the simplest way requiring the least technologies in order to accomplish this task: Generating a request to an image using a small JavaScript code. The image can be anything, but of course, putting a small pixel as an image is preferred, since it will consume less resources.

Generating a request to an image, can be done very easily in JavaScript by creating a new Image class:

var image = new Image();
image.src = "pixel.gif";

Since browsers tend to cache resources, we may want to make sure our request is not being cached. This can easily be done be calling the image with a dummy parameter that contains random data. This will trick the browser to think we are making a request to a new resource, although we are actually calling same resource every time:

var image = new Image();
image.src = "pixel.gif?ind=" + Math.random();

Now, all is left to do, is make sure this request is being called every fixed amount of time. For example 5 minutes. This can be done by using JavaScript method called: window.setInterval which calls a function every given amount of millisecond. Here is how the complete code looks:

<script type="text/javascript">
  function dummyRequest()
  {
    var image = new Image();
    image.src = "pixel.gif?ind=" + Math.random();
  }
  window.setInterval("dummyRequest();", 5 * 1000 * 60);
</script>

Of course that it will be best to place this code on your web application header file (or template file, depending on the technology you are using), in order to apply the server polling functionally on all the web application pages automatically.

In addition, a good idea is to place this code on an external JavaScript file, since the browser will cache it and download it only once.

1 comment: