How to create a servlet that uses data caching to eliminate retrieving data each time a page request is made.
You can run this technique code from:
NOTE First make sure that database is running on your localhost SilverStream Server | |
See the chapter on Using servlet business objects in the Programmer's Guide |
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 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;
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; }
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; }
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; }