Application Techniques



Developing a Servlet that Uses Caching

How to create a servlet that uses data caching to eliminate retrieving data each time a page request is made.

About this technique

Details

Category

Triggered Business Object Techniques> Servlets

Description

You'll learn about:

You can run this technique code from:

NOTE   First make sure that database is running on your localhost SilverStream Server

Related reading

See the chapter on Using servlet business objects in the Programmer's Guide

How this example works   Top of page

The object used in this example was created using the Object Designer, and includes listeners for the serverStarted, tableModified, and servlet events. The object is bound to the Departments table through an AgData called "tableDepartments".

At server start, the code retrieves the department data and stores it in an instance variable. When requested, the servlet gets the data from the instance variable and builds the page.

A table-modified trigger detects when the department data changes and sets a flag accordingly. On the next request for the page, the data modified flag causes the data to be refreshed, the data modified timestamp to be updated, and the page to be rebuilt.

If a request comes in and the last-modified date on the cached page is more recent than the date the page was last built, the page does not need to be sent back to the browser. This is done by setting a flag in the header telling the browser to use the page already in the cache.

Class member variables   Top of page

Class variable declarations for this example are listed below. Note that these values must be available to various event methods, hence the need to declare them in the General section of the code.

     // Stores the data result set 
     StringBuffer sbPage = null; 
     // Gets the cached data from the server 
     AgoHttpRequestEvent hRequest; 
    // flag to determine if data has changed during session 
     boolean m_bDataChanged = false; 
    // Store last modified time to determine if new page is needed 
     long m_lTimeStampModified = 0; 

Caching data when the server is started   Top of page

The code for the serverStarted event calls a utility (user-defined) method buildThePage() that queries the database and stores the result in the StringBuffer variable. This makes the page with the data immediately available to the caller.

  public void serverStarted(AgoServerStartEvent evt) 
  { 
     // At server start, retrieve the data. 
     // When it is done at server start, the data does not 
     // need to be retrieved when the request comes in. 
  	  
     // Retrieve the departments 
     buildThePage( evt.getAgaData("dataDepartments") ); 
   
     return; 
  } 

Determining if session data has been updated   Top of page

If the table is modified at any time during the session, the m_bDataChanged flag is reset. The servlet code will use this flag, along with the m_lTimeStampModified variable to determine if the page must be rebuilt.

  public void beforeTableChange(AgoTableEvent evt) 
  { 
    // If the Department table data changes, set this flag so we 
   //  will refresh the data the next time a request comes in. 
   
     m_bDataChanged = true; 
     return; 
  } 

Managing the cached data in the servlet   Top of page

When the servlet is called, the code in the service() method manages the request by checking the modified flag to determine if the data has been modified since the current request. If it has been modified, the code calls the utility method buildThePage() to build the page. After processing, the utility method resets the modified flag and modified time variables.

Then the code compares the time stamp on the header request to the time stored in the last-modified variable. If the header request is later than the variable value, then the page does not need to be rebuilt, and the code just modifies the response header accordingly. Otherwise, the code updates the response header and ouputs the page using the Java OutputStream object.

  public void service(javax.servlet.ServletRequest req, javax.servlet.ServletResponse res) throws javax.servlet.ServletException, java.io.IOException 
      
    AgoHttpRequestEvent hRequest = (AgoHttpRequestEvent) req; 
    AgiHttpServletResponse hResponse = (AgiHttpServletResponse) res; 
   
    // If for some reason the page was not built,or the data has  
    //  changed since we built the page,we need to rebuild the page. 
   
       if (sbPage == null || m_bDataChanged) 
           buildThePage( hRequest.getAgaData("dataDepartments")); 
    
   // If the page in the browser cache is more recent than the time // we last built the page, return a not-modified status reponse. 
  // We are assuming here that we will get a -1 returned for the  
  // "If-Modified-Since" time if the page is not in cache, so it 
  //  will be less than the time last modified. 
  // Note:  getDateHeader is not accurate to nanoseconds, although 
  // it returns an arbitrary last 3 digits. We eliminate them by 
  // dividing by 1000 and multiplying again by 1000. 
   
     long lDateHeader = hRequest.getDateHeader( 
         "If-Modified-Since") / 1000 * 1000; 
     if (hRequest.getDateHeader("If-Modified-Since") > 
          m_lTimeStampModified ) 
        { 
            // Set the response header to not-modified 
            hResponse.setStatus(hResponse.SC_NOT_MODIFIED);    
            System.out.println("====>bosrvletDepartmentList: 
              Sending back SC_NOT_MODIFIED!");    
            return; 
         } 
            
      // Otherwise, update the header and show the page. 
         System.out.println("====>bosrvletDepartmentList:  
             Sending the page!");    
     // Update the 'Last-Modified' date in the response header 
     // before leaving. 
         hResponse.setDateHeader("Last-Modified",  
            (System.currentTimeMillis()/1000*1000))          
     // Set the content type 
         hResponse.setContentType("text/html;  
              charset=iso-8859-1");       
     // Update the header status field 
           hResponse.setStatus(hResponse.SC_OK); 
      
       // Output the HTML 
        OutputStream out = hResponse.getOutputStream(); 
        out.write(sbPage.toString().getBytes()); 
   
        return; 
  } 






Copyright © 2000, SilverStream Software, Inc. All rights reserved.