Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

Servlets, Server-Side Includes

Java Programming, Lecture Notes # 684, Revised 2/19/99.

Preface

Introduction

Sample Program

Interesting Code Fragments

Program Listing


Preface

Students in Prof. Baldwin's Advanced Java Programming classes at ACC will be responsible for knowing and understanding all of the material in this lesson beginning with the spring semester of 1999.

This lesson was originally written on January 6, 1999. The sample servlet was tested using the JDK 1.2 download package from JavaSoft along with the Java Servlet Development Kit (JSDK) 2.0 from JavaSoft. All tests were performed under Win95.

The servlet was tested using the Java Web Server 1.1.1 from JavaSoft. It was not tested using the servletrunner program because that program does not support Server-Side Includes.

Introduction

Previous lessons have introduced you to two different ways to activate a servlet. One of these ways was to point a browser to a URL containing the name of the servlet. The other way was to reference the servlet in the ACTION command of an HTML form.

There is another way to activate a servlet that I haven't, and probably won't demonstrate. That is to register a servlet under a different name, such as MyFile.html, using the administration feature of a server. Then the servlet can be activated by specifying the name of the file in the URL. This is useful if you need to replace an HTML file with a servlet and don't want to break the bookmarks that others may have already placed on that file.

The purpose of this lesson is to introduce you to one additional way to activate a servlet, using a methodology commonly referred to as a Server-Side Include or SSI for short.

In a manner similar to the use of <APPLET> tags in an HTML file, you can embed

<SERVLET> ... </SERVLET>

tags in an HTML file. When told to do so, the server will examine the content of the HTML file while delivering it to the client. Each time it encounters a servlet tag, it will activate the servlet whose name (and possibly location) is embedded in the servlet tag. The entire servlet tag sequence will be replaced by the material produced by the servlet before the HTML file is delivered to the client.

Thus, you can write an HTML file that activates different servlets at various points within the file and cause the material produced by the servlets to be embedded in the HTML file and delivered to the client who requested the HTML file.

Sample Program

The name of the sample program is Servlet03. This servlet is designed to illustrate Server-Side Includes, commonly known as SSI.

When tested with the HTML file named Servlet03.shtml and the JavaSoft Java Web Server 1.1.1, this servlet produced the following output in the browser window. The servlet determines the date and time 120 days in the future. (Note that it automatically took daylight savings time into account.)

The output was:

The current date and time is: 
06-Jan-99 6:53:12 PM 

The date and time in 120 days will be: 
06-May-99 7:53:12 PM

Note that it is necessary to use an extension of shtml on the HTML file. By default, the Java Web Server will parse HTML files looking for included references to servlets only if the file extension is shtml. (However, you can change the required extension if you want by using the administration program for the server.)

The substantive material contained in the body of the HTML file named Servlet03.shtml was as follows:

The current date and time is: <br> 
<SERVLET CODE=Servlet03>
</SERVLET>

<BR><BR>
The date and time in 120 days will be: <br> 
<SERVLET CODE=Servlet03>
<PARAM NAME=days VALUE=120>
</SERVLET>

There are two <SERVLET> tags in the HTML file, one that specifies a parameter value of 120 and one that doesn't specify a parameter value. The remainder of the HTML file was strictly boilerplate.

As the server parses the shtml file, whenever it finds a <SERVLET> tag, it activates the servlet specified by the CODE attribute. The material produced by the servlet is embedded in the HTML file by using that material to replace the entire <SERVLET>...</SERVLET> tag sequence before sending the HTML file to the client.

It is also possible to provide a CODEBASE attribute which specifies the URL, down to the directory level, of a remote location from which the servlet should be loaded. If the CODEBASE attribute is not provided, the servlet is assumed to be stored in the normal location for servlets with that server.

The program was tested using two computers on the network, each running JDK 1.2 under Win95.

The HTTP server program from JavaSoft named Java Web Server 1.1.1 was running on one machine. A browser was running on a second machine.

The file named Servlet03.shtml was stored in the public_html folder in the server's directory tree.

The servlet file named Servlet03.class was stored in the servlets folder in the server's directory tree.

The browser was pointed to the following URL

http://webserver:8080/Servlet03.shtml

to request that the file named Servlet03.shtml be downloaded. This caused the server to deliver the requested HTML file. During delivery, the file was modified by two calls to the servlet caused by two <SERVLET> tags embedded in the HTML.

The servlet was not tested against the servletrunner program because it does not support SSI.

Interesting Code Fragments

The first fragment shows the beginning of the doGet() method including its request and response parameters.

public class Servlet03 extends HttpServlet{
  public void doGet(HttpServletRequest req, 
                    HttpServletResponse res)
                      throws ServletException, IOException{
                        
    try {

The next fragment shows the correct code for getting an output writer object for sending data to the server for inclusion in the HTML page. However, this statement doesn't work in this case, apparently due to a bug in Java Web Server 1.1.1. For that reason, the fragment is shown as a comment.

//      PrintWriter out = res.getWriter();

The next fragment shows a slightly more complicated way to get an output writer object, which serves as a work-around for the bug described above. The reference variable named out is a reference to a writer object that is linked to the response object received as an incoming parameter.

      PrintWriter out = new PrintWriter(
                               res.getOutputStream(),true);

The next fragment gets a Date object using a constructor that defaults to the current date and time.

      Date theDate = new Date();

Dates and times in Java are maintained as the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT. The next fragment gets the number of milliseconds that represents current date and time as a long integer..

      long theCurrentMillis = theDate.getTime();

If the servlet tag in the HTML file specifies a parameter named days, this servlet uses the value of that parameter as an offset to determine the date and time that many days in the future or in the past. If the servlet tag doesn't specify a value for the days parameter, the offset is treated as zero.

The next fragment gets the value of the parameter named days. If the HTML doesn't specify a value for this parameter, the getParameter() method returns null. Note that even though this parameter is intended to represent a number of days, it is received as a String object that must be converted to an integer numeric value.

      String futureDaysString = req.getParameter("days");

The value of the days parameter is tested to see if it is null. If not, the parseInt() method of the Integer class is used to convert it to a long variable named futureDays.

      if(futureDaysString != null){
        long futureDays = Integer.parseInt(
                                         futureDaysString);

Appropriate arithmetic is then performed to convert the offset in days to an offset in milliseconds and the number of milliseconds is stored in a long variable named theFutureMillis.

        long theFutureMillis = futureDays*24*60*60*1000;

The offset in milliseconds is added to the number of milliseconds that represents the current date and time. The sum of the two produces a value in milliseconds that represents a different date and time. In the event that the value of the days parameter is negative, the sum represents negative future, or history.

A new Date object is constructed using a version of the constructor that takes milliseconds as an input parameter. A reference to the new Date object is assigned to the reference variable named theDate. That ends the code that is executed when the value of days is not null.

        theDate = new Date(
                       theCurrentMillis + theFutureMillis);
      }//end if

If the original value returned by getParameter() is null, all of the code that applies the offset is bypassed and the reference variable named theDate refers to an object that represents the current date and time. At this point, theDate refers to a Date object that either represents the current date and time, or represents a date and time calculated by applying an offset to the current date and time.

The next fragment is a rather complicated statement that formats the contents of the Date object in a particular way and delivers it as a String back to the server by passing the String as a parameter to the println() method. If you don't understand the formatting that is being used here, you should look it up in the JDK documentation.

      out.println(DateFormat.getDateTimeInstance().
                                          format(theDate));

The remaining code that is not shown here is an exception handler and some other wrap-up code. You can view it in the complete listing of the program that follows in the next section.

Program Listing

A complete listing of the program follows.

/*File Servlet03.java, Copyright 1999, R.G.Baldwin

Rev 1/6/99 

This servlet is designed to illustrate Server Side 
Includes, commonly known as SSI.  

When used with the HTML file named Servlet03.shtml and the
JavaSoft Java Web Server, this servlet produced the 
following output in the browser window.  (Note that the 
output automatically took daylight savings time into 
account.)

The current date and time is: 
06-Jan-99 6:53:12 PM 

The date and time in 120 days will be: 
06-May-99 7:53:12 PM

Also note the requirement to use an extension of shtml on
the HTML file.  By default, the Java Web Server will parse
HTML files looking for included references to servlets only
if the extension is shtml.  (The required extension can be
changed using the administration program for the server.)

The substantive part of the HTML file named Servlet03.shtml
was as follows:
  
The current date and time is: <br> 
<SERVLET CODE=Servlet03>
</SERVLET>

<BR><BR>
The date and time in 120 days will be: <br> 
<SERVLET CODE=Servlet03>
<PARAM NAME=days VALUE=120>
</SERVLET>

This shows two <SERVLET> tags in the HTML file, one which
specifies a parameter value of 120 and one that doesn't
specify a parameter value.  The remainder of the HTML file
was strictly boilerplate.

As the server is parsing the shtml file, whenever it finds
a <SERVLET> tag, it activates the servlet specified by the
CODE attribute.  The material produced by the servlet is
embedded in the HTML file by using that material to replace
the entire <SERVLET>...</SERVLET> tag sequence before 
sending the HTML file back to the client.

The program was tested using two computers on the 
network, each running JDK 1.2 under Win95.

The HTTP server program from JavaSoft named Java Web 
Server 1.1.1 was running on one machine.  A browser was
running on a second machine.  

The file named Servlet03.shtml was stored in the 
public_html folder in the server's directory tree.

The servlet file named Servlet03.class was stored in the
servlets folder in the server's directory tree.

The browser was pointed to the following URL

http://webserver:8080/Servlet03.shtml

to request that the file named Servlet03.shtml be 
downloaded.  This caused the server to deliver the 
requested HTML file.  During delivery, the file was 
modified by two calls to the servlet caused by two 
<SERVLET> tags embedded in the HTML.

The servlet was not tested against the serevletrunner
program because it does not suppor SSI.
**********************************************************/
import java.io.*;
import java.util.Date;
import java.text.DateFormat;
import javax.servlet.*;
import javax.servlet.http.*;

public class Servlet03 extends HttpServlet{
  public void doGet(HttpServletRequest req, 
                    HttpServletResponse res)
                      throws ServletException, IOException{
                        
    try {
      //Get an output writer object to send data back to
      // the client.
/*
      //The following is the correct code to get an output
      // writer object to send data to the server for 
      // inclusion in the HTML page being returned to the 
      // client.  However, it doesn't work, apparently due
      // to a bug in the Java Web Server 1.1.1 from 
      // JavaSoft.
      PrintWriter out = res.getWriter();
*/
      //The following is a work-around for a bug in Java 
      // Web Server 1.1.1 from JavaSoft.
      PrintWriter out = new PrintWriter(
                               res.getOutputStream(),true);
      
      //Get a Date object containing the current date and
      // time.
      Date theDate = new Date();
      
      //Get the number of milliseconds required to 
      // represent the current date and time.
      long theCurrentMillis = theDate.getTime();

      //Get the parameter value from the SERVLET tag in
      // the shtml file.
      String futureDaysString = req.getParameter("days");
      
      //If a parameter was submitted, use it to determine
      // the date and time at a point in the future
      // represented by the number of days specified by
      // the parameter.
      if(futureDaysString != null){
        //Convert the String parameter to a long
        long futureDays = Integer.parseInt(
                                         futureDaysString);
        //Calculate number of milliseconds required to
        // represent that number of days.
        long theFutureMillis = futureDays*24*60*60*1000;
        //Add that number of milliseconds to the current
        // number of milliseconds and get the date and time
        // represented by the total.
        theDate = new Date(
                       theCurrentMillis + theFutureMillis);
      }//end if
      
      //Produce and output string that will be used by the
      // server.  See the JDK documentation for an 
      // explanation of the formatting provided by this
      // statement.  It is rather complex.
      out.println(DateFormat.getDateTimeInstance().
                                          format(theDate));

    }catch( Exception e ) {
      e.printStackTrace();
    }//end catch
  }//end doGet()
}//end class Servlet03

-end-