Accessibility
 
Icon or Spacer
Icon or Spacer

Initialization and Clean-up for JSP Pages

by Ronel Submicay

Most web developers at some point have faced or will face the dilemma of writing web applications requiring an initialization process triggered when a user first enters as well as some type of housekeeping when a user leaves. With the statelessness of the web, this task is not always straightforward and is often quite messy without some type of session tracking mechanism. At times developers may also need to operations when a JSP application starts up or ends. In this article, we will explore methods of triggering processes when JSP applications are entered or exited by users.

What makes up our web application?

For the remainder of the article, JSPs containing the same application name are considered to be within the same application. The name of the application is retrieved using the getApplicationName method of an instance of the ApplicationEventServlet. We will create the ApplicationEventServlet in this article.

The ApplicationEventServlet will be an abstract class that will perform operations triggered when an application or session starts or ends. Any JSP extending the ApplicationEventServlet will inherit the implemented actions. The life cycle of a named application starts when the init method is called on the first ApplicationEventServlet instance containing the name of the application and ends when the destroy method is called on the first ApplicationEventServlet instance containing the name of the application. For the above cases, the doApplicationOnStart and doApplicationOnEnd methods are called respectively.

The ApplicationEventServlet is also responsible for calling the doSessionOnStart when a session starts and doSessionOnEnd when a session expires, or is invalidated.

The following is our ApplicationEventServlet:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public abstract class ApplicationEventServlet extends HttpServlet
{
    private static Hashtable s_AppEventCache =
 null;
    
    protected abstract String getApplicationName();
    
    protected abstract boolean 
doApplicationOnStart();
    protected abstract boolean 
doApplicationOnEnd();
    protected abstract void 
doSessionOnStart(HttpSession ses, 
HttpServletRequest req,
         HttpServletResponse res);
 
    protected abstract void doSessionOnEnd(HttpSession ses);
    
    public void init(ServletConfig config) throws 
         ServletException
    {
        super.init(config);
        if( s_AppEventCache == null ) s_AppEventCache = new 
               Hashtable();
        if( s_AppEventCache.get( getApplicationName() ) == null)
        {
            if ( doApplicationOnStart() ) {
                s_AppEventCache.put( getApplicationName(), "" );
            }
        }
    }
    
        
    public void destroy()
    {
        super.destroy();
        
        if( s_AppEventCache.get( getApplicationName() ) != null) 
        {
            if( doApplicationOnEnd() ) 
            {
                s_AppEventCache.remove( getApplicationName() );
            }
        }
    }
    
    
    public void appSessionInit(HttpServletRequest req, 
          HttpServletResponse res)
             throws IOException, ServletException
    {
        HttpSession ses = req.getSession(true);
        if(ses.isNew()) {
            doSessionOnStart(ses, req, res);
            ses.putValue( getApplicationName(), new 
              SessionListener() );
        }
    }
          
    
    class SessionListener implements HttpSessionBindingListener
    {
        public void valueBound(HttpSessionBindingEvent evt) {}

        public void valueUnbound(HttpSessionBindingEvent evt) {
            doSessionOnEnd(evt.getSession()); }
    }
}

Lets now go through the ApplicationEventServlet's methods. The first thing to note is that it is an abstract class. The implementor is responsible for implementing the abstract methods:

getApplicationName
doApplicaionOnStart
doApplicationOnEnd
doSessionOnStart
doSessionOnEnd

Starting off with getApplicationName, this method returns the String 'name' of the application represented by the concrete class. This name will be used to tell whether an application of the given name has already been called for doApplicationOnStart or doApplicationOnEnd. The two methods are only called once per named application per application life cycle.

The doApplicationOnStart is called only once for a named application when an application is first started. So if myjsp1.jsp was requested and it belonged to the application named Banking and doApplicationOnStart has not already been called, then it will be called to initialize the Banking application. If myjsp2.jsp also belonged to the Banking application and was requested after myjsp1.jsp, then doApplicationOnStart will not be called again since it has already been triggered by myjsp1.jsp.

The doApplicationOnEnd is called only once for a named application when an application ends. So if myjsp1.jsp was requested and it belonged to the application named Banking and doApplicationOnEnd has not already been called, then it will be called to perform cleanup on the Banking application. If myjsp2.jsp also belonged to the Banking application and was being destroyed after myjsp1.jsp, then doApplicationOnEnd will not be called again since it has already been triggered by myjsp1.jsp.

Synchronization of the two methods is not necessary, since calls to init and destroy are already called synchronously.

The doSessionOnStart and doSessionOnEnd methods are only called once for each new session, and when the session is removed, or expires respectively.

Implemented methods in ApplicationEventServlet

Implemented methods in the ApplicationEventServlet are:

init
destroy
initSession

The init method determines when the applicationOnStart method is called. It does this by keeping a Hashtable of named applications that it has already called applicationOnStart for. The Hashtable reference is s_AppEventCache. This Hashtable sticks around for the whole life of the VM. The destroy method determines when the applicationOnEnd method is called by checking into the s_AppEventCache for the named application.

The initSession method is responsible for creating an HttpSessionBindingListener and storing it in the user's session only if the session is new. The inner class SessionListener will call into the sessionOnEnd method will be called when the user's session expires or is invalidated. Since the session is determined new within a request, the implementor will have access to the request and response objects. This is why we do not bother implementing the valueBound method, and instead call doSessionOnStart directly to pass in the request and response objects.

A Simple JSP Application Test Servlet

We will now implement the ApplicationEventServlet and apply it to a couple of JSP pages. The following is our concrete class called MyJSPApplicationServlet:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import com.livesoftware.jrun.plugins.JSP.JSPResponse;
import com.livesoftware.jrun.plugins.JSP.JSPRequest;

public class MyJSPApplicationServlet extends ApplicationEventServlet
{
    protected boolean doApplicationOnStart() 
    {
        System.out.println("ApplicationOnStart called for: 
         "+getApplicationName());
        return true;
    }
    
    
    protected boolean doApplicationOnEnd() 
    {
        System.out.println("ApplicationOnEnd called for: 
         "+getApplicationName());
        return true;
    }
    
    
    protected void doSessionOnStart(HttpSession ses, 
       HttpServletRequest req, HttpServletResponse res) 
    {
        System.out.println("SessionOnStart called for: 
          "+getApplicationName());
        System.out.println("Session id: "+ses.getId());
        
        try {
           res.getOutputStream().println("A new session 
         "+ses.getId());
        }
        catch(IOException io){ System.err.println("Bad 
       OutputStream");    
    }
    
    protected void doSessionOnEnd(HttpSession ses) 
    {
        System.out.println("SessionOnEnd called for: 
           "+getApplicationName());
        System.out.println("Session id: "+ses.getId());
    }
    
    protected String getApplicationName() 
    {
        return "MyJSPApplicationServlet";
    }
}

This servlet defines a JSP page to extend MyJSPApplicationServlet. It can give you an idea of when the methods are called and what class wide logic you want to apply for any JSP page extending MyJSPApplicationServlet.

The following is an example jsp file that uses the functionality of MyJSPApplicationServlet.

JspAppTest.jsp

<%@ import=MyJSPApplicationServlet %>
<%@ extends=MyJSPApplicationServlet %>
<% appSessionInit (request, response); %>

MYJSPApplicationServlet test

The two directives import and extends is required within the jsp file as well as the call to appSessionInit, which is responsible for initializing the session. By creating two jsp files both extending MyJSPApplicationServlet, you can get a clearer picture of when the application and session methods are called.

What else can you do with it?

For starters, the ApplicationEventServlet can make available and manage objects within the naming scope of the application. For instance, the s_AppEventCache can be used to store name/Hashtable pairs where each Hashtable contains objects that can be set and retrieved by appropriately named application. We can add get and put methods so extending JSP pages can get to the available data, and set them appropriately.