Java Servlets

November 19th, 1998

Mika Silander
Department of Computer Science
Helsinki University of Technology
Mika.Silander@hut.fi

Abstract

This paper discusses a Java technology called servlets. Servlets are program modules written in Java that can be run under Java enabled servers. Thus they allow extending the functionality of a server. Servlets are mainly used for extending World Wide Web servers and hence resemble very much the traditional CGI programs as a technology. Servlets however, were found to resemble even more another technology called FastCGI.

This paper shows what servlets look like and demonstrates their use with code examples. The examples explain how servlets can accomplish the same tasks than CGI programs. It also makes a comparison of all the three aforementioned technologies, highlighting their drawbacks and benefits.


Table of Contents

1. Introduction
2. Servlets and the servlet API
3. Loading and running servlets
4. Security issues
5. Example servlets
5.1. One servlet - multiple requests
5.2. A servlet's execution environment
5.3. Server-side includes
5.4. Server parsed HTML
5.5. Servlet capabilities beyond CGI
6. Technology comparison
7. Conclusions
8. References
9. Further reading

1. Introduction

There is a number of technologies extending the capabilities of WWW servers. The most commonly known are CGI, FastCGI and various server extension APIs[1, 2, 3, 4, 5].

Servlets is Java's contribution to the WWW server extension technologies. Conceptually one can think of servlets as being the WWW server-side equivalents of applets, since the inclusion of a servlet into a WWW server is just as simple as adding an applet to a HTML page.

There exists a number of both freely available and commercial WWW servers that either include the servlet API or allow its inclusion, among them the popular Apache[6, 7]. Servlets provide the same functionality that can be implemented with CGI. They have however, some important advantages in comparison with CGI programs. Servlets were first introduced as a separate kit called Java Servlet Development Kit (JSDK) in conjunction with version 1.1. of the Java Developer Kit (JDK).

2. Servlets and the servlet API

Servlets are Java program modules running inside request/response-oriented servers[8]. They can be plugged in to a server about as easily as applets can be added to a HTML page. In order to do this, the server must comply with the Servlet API which acts as an interface between the server and the servlet[9]. The interface itself is defined in javax.servlet.Servlet, which is a standard Java extension. The server itself must of course include a Java Virtual Machine and the servlet base classes.

The Servlet API is simple. The methods are:

In order to write a servlet, one has to implement the above interface. The most common type of servlets is however the web servlet. WWW servlets are created by extending the class javax.servlet.http.HttpServlet.

To implement the functionality of the HttpServlet class, the following methods should be provided:

The Java Servlet Development Kit contains the necessary tools for servlet development and some alpha plug-ins to include servlet support to commonly used WWW servers.

3. Loading and running servlets

The server loads the servlet and starts it by calling the servlet's init method. After the completion of init, a servlet can start serving requests by accepting client requests with the method called service. In order to close down the service the servlet offers, the server invokes the servlet's method destroy. This is in essence a servlet's lifecycle.

There are many sources of servlets. They can be stored locally in files of their own, they can be stored in trusted directories thus allowing for more operations than could be done with respect to the security restrictions, or, they can be even uploaded from remote servers[10]:

Figure 1. Sources of servlets[9]

servletrunner is the equivalent development tool for servlets that appletviewer is for applets, though appletviewer is available on a wider variety of platforms.

4. Security issues

Many of the desirable features servlets have are due to the underlying Java and its Java Virtual Machine. Memory access and type violations are caught and this adds to the stability of the WWW server in case the servlet was poorly implemented or even if it was implemented with malicious intentions.

Another good thing is the security managers of Java since all servlets are run under the control of a security manager and in this sense the parallell between applets and servlets is even more evident. All servlets are considered untrusted by default - unless they are loaded from a local file or the trusted directory - and thus have a strictly limited set of operations they can perform concerning local storage and network connections. These restrictions can however, be lifted as they can with applets as well, by signing the servlets digitally. In practise, the archive (JAR) file containing the servlet classes is the one being digitally signed[11].

Figure 2. Controlled servlet execution[9]

5. Examples

This section contains a selection of servlet examples each demonstrating a different functionality. The examples cover all the services that can be accomplished with CGI programs. This shows that servlets is an interchangeable technology with CGI.

5.1. One servlet - many requests

This example shows explicitly how an ordinary servlet serves a request just like a corresponding CGI program but on top of that remains running and may thus serve many requests instead of one. This ability is the main efficiency improving factor in comparison with CGI. CGI programs would be spawned anew by the WWW server every time a new request was received thus adding a lot of overhead. A further gain in efficiency could be achieved by starting several threads within the servlet to serve requests. The threads would be started during the initialisation of the servlet, i.e. in the init method.
package my.demo.servlet;

import java.io.*;
import java.lang.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import sun.servlet.*;

public class TestServlet extends HttpServlet {

    int reqnum = 0;
    Vector accessList = new Vector();
    Date now = null;
    int i = 0;

    public String getServletInfo()
        {
        return "Test servlet demonstrating the\none invocation/multiple " +
	  "serve feature";
        }

    public void service( HttpServletRequest req, HttpServletResponse res )
       throws ServletException, IOException
       {
        res.setStatus( HttpServletResponse.SC_OK );
        res.setContentType( "text/html" );
        ServletOutputStream strm = res.getOutputStream();
        strm.println( "<html><head>" );
        strm.println( "<title>Test Servlet</title>" );
        strm.println( "</head><body>" );
	now = new Date();
        strm.println( "<h2>Test Servlet</h2>" );
        strm.println( "<P>This was request number <b>"
                   + Integer.toString(++reqnum)
		   + "</b> served at " + now.toString());
        strm.println( "<hr>Previous accesses:<p>" );
	for (i = accessList.size(); i > 0; i-- ) {
	  strm.println( i + ". access at " + accessList.elementAt(i-1)
			+ "<br>");
	}
	strm.println( "</body></html>" );
        strm.flush(); strm.close();
	accessList.addElement(now.toString());
       }
    }

5.2. A servlet's execution environment

The servlet can get hold of a lot of information about its execution environment in much the same way as CGI programs. This applies for all servlets, including the untrusted ones. A CGI program typically gets the information in environment variables whereas a servlet gets two lists of entries by applying appropriate methods to the two objects; ServletConfig and the request object ServletRequest.

package my.demo.servlet;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class EnvironServlet extends HttpServlet {

    public void doGet (HttpServletRequest req, HttpServletResponse res)
	throws ServletException, IOException
    {
	res.setContentType("text/html");

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

	out.println("<html><head>");
	out.println("<title>Environment Servlet</title>");
	out.println("</head><body>");
	out.println("<h2>Environment Servlet</h2><hr>");

	// Initialisation parameters given in the server's configuration
	ServletConfig conf = this.getServletConfig();
	Enumeration parameters = conf.getInitParameterNames();

	if ( parameters.hasMoreElements() ) {
	  out.println("<p><b>Environment Servlet's initialization parameters");
	  out.println(" given by the www server</b>:<p>");

	  for (	;parameters.hasMoreElements();) {
	    String param = (String) parameters.nextElement();
	    out.println( param + " =  " + conf.getInitParameter(param)
			 + "<br>");
	  }
	}

	// The header fields of the HTTP request
	out.println("<p><b>HTTP Header fields from the HTTP request</b>:<p>");
	for (Enumeration headerfields = req.getHeaderNames();
	     headerfields.hasMoreElements(); ) {
	    String field  = (String) headerfields.nextElement();
	    out.println( field.toString() + " = "
                         + req.getHeader(field) + "<br>");
	}

	// The environment variables of the servlet (given by the www server)
	String prefix = "org.apache.jserv.";
	Object attrsObj = req.getAttribute("org.apache.jserv.attribute_names");
	if ( attrsObj != null && attrsObj instanceof Enumeration ) {
	    Enumeration attrs = (Enumeration) attrsObj;
	    out.println("<p>");
	    out.println( "<b>HTTP request attributes passed from the www");
	    out.println(" server</b>:<p>");
	    while ( attrs.hasMoreElements()) {
	        String attr = attrs.nextElement().toString();
		if ( req.getAttribute(prefix + attr) != null ) {
	            out.println( attr + " = " +
			req.getAttribute(prefix + attr).toString());
		} else {
	            out.println( attr + " = NULL " );
		}
	        out.println("<br>");
	    }
	}

	out.println("</body></html>");
	out.flush();
	out.close();
    }
}

5.3. Server-side includes

Servlets can be invoked in such a manner that they filter part of the information the user requested for prior to delivering it. This kind of preprocessing on-the-fly is commonly known as server-side includes. In WWW terms, one could preprocess HTML files before the contents are delivered to the end user's browser. This way of using servlets is also called servlet embedding.

Assume for example it is crucial the users know when a HTML page was updated. If the number of HTML pages to be maintained is high, then it would be handy to at least avoid the necessity of changing the update dates by hand. This can be achieved by renaming the HTML pages, say to have the suffix *.shtml instead of *.html and configure the WWW server to invoke a servlet for preprocessing all files having this modified suffix.

The *.shtml files would then include the following HTML tags for automatically invoking the servlet and thus including the date of last update to the generated HTML page:

    <SERVLET NAME="LastUpdated" CODE="my.demo.servlet.LastUpdated.class">
    </SERVLET>
In between the SERVLET tags one could add parameters which are fed to the servlet in syntactically the same way as parameters are fed to applets. The tags in the above example get replaced on-the-fly with the output of the LastUpdated servlet whereas the rest of the document remains intact, e.g:


    This page was last updated at Sun Mar 15 14:02:44 GMT+10:00 1998.

This servlet works by extracting the requested file's name from the HTTP request and then checking from the file system the corresponding modification time. The time is then output together with an explicatory message. The code of the LastUpdate servlet looks as follows:
package my.demo.servlet;

import java.io.*;
import java.lang.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import sun.servlet.*;

public class LastUpdated extends HttpServlet {

    String filename = null;
    File docFile = null;
    Date modifDate = null;

    public String getServletInfo()
        {
	  return "A servlet which can be embedded to a HTML page.";
        }

    public void service( HttpServletRequest req, HttpServletResponse res )
       throws ServletException, IOException
       {
        res.setStatus( HttpServletResponse.SC_OK );
        res.setContentType( "text/html" );
        ServletOutputStream strm = res.getOutputStream();

	filename =
	  req.getAttribute("org.apache.jserv.DOCUMENT_ROOT").toString();
	filename = filename.concat(req.getRequestURI());

	docFile = new File(filename);
	modifDate = new Date (docFile.lastModified());

	strm.println("This page was last updated at "
                     + modifDate.toString() + ".");
        strm.flush();
	strm.close();
       }
    }

5.4. Server parsed HTML

The previous example can be taken even further so that entire HTML documents, or any other documents for that matter, are processed on-the-fly by servlets. To distinguish the embedded servlet example from this one, we can configure the WWW server to invoke a servlet for files ending with the *.jhtml suffix.

Now, assume that we want to make a practical joke by adding typos in HTML documents. By naming the documents with the aforementioned suffix, or better still, running the servlet for ordinary HTML files (*.html), we may create a servlet which automatically makes these typos so the writers of the documents, even though writing grammatically impeccable text, would end up having funny surprises when they looked at the results with a browser.

An example typo servlet affecting only the raw text, i.e. not the HTML tags, could look like this:

package my.demo.servlet;

import java.io.*;
import java.lang.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import sun.servlet.*;

public class TypoServlet extends HttpServlet {

    static final int nextTypoOffset = 20;
    static final int maxOffset = 15;
    static final int maxErrorModes = 3;

    String hmltDoc = null;
    BufferedReader docFile = null;
    String line = null;
    String collect = null;
  
    int tagBegin;
    int tagEnd;

    boolean inTag = false;

    public String getServletInfo()
        {
	  return "A servlet for demonstrating server parsed html.";
        }

    public void doGet( HttpServletRequest req, HttpServletResponse res )
       throws ServletException, IOException
       {

	 hmltDoc =
	   req.getAttribute("org.apache.jserv.DOCUMENT_ROOT").toString();
	 hmltDoc = hmltDoc.concat(req.getRequestURI());

	 docFile = new BufferedReader(new FileReader(hmltDoc));
	    
	 res.setStatus( HttpServletResponse.SC_OK );
	 res.setContentType( "text/html" );
	 ServletOutputStream outstrm = res.getOutputStream();

	 line = docFile.readLine();
	 while (line != null) {
	   collect = new String();

	   while(line.length() > 0) {
	     tagBegin = line.indexOf("<");
	     while(tagBegin == -1) {
	       // Here we can do some modifications to the line's
	       // remainder being processed
	       outstrm.println(collect + maketypo(line));
	       collect = new String();
	       line = docFile.readLine();
	       tagBegin = line.indexOf("<");
	     }

	     // Here we:
	     // 1. cut line till the first < character
	     // 2. on this beginning we replace all 'e' with '+'
	     // 3. we concat this beginning with collect
	     // 4. we cut lineBeg's length from line

	     //	     lineBeg = line.substring(0,tagBegin);
	     //lineBeg = lineBeg.replace('e','+');
	     collect = collect.concat(maketypo(line.substring(0,tagBegin)));
	     line = line.substring(tagBegin);

	     // We start searching for tag end
	     tagEnd = line.indexOf(">");
	     while (tagEnd == -1) {
	       collect = collect.concat(line);
	       outstrm.println(collect);
	       collect = new String();
	       line = docFile.readLine();
	       tagEnd = line.indexOf(">");
	     }

	     // Tag end found
	     collect = collect.concat(line.substring(0,tagEnd));
	     line = line.substring(tagEnd);
	     // Here we go back to making typo's
	   }

	   // Send the modified line to the receiver
	   // System.out.println("3:" + collect);
	   outstrm.println(collect);
	   line = docFile.readLine();
	}
	docFile.close();
        outstrm.flush();
	outstrm.close();
       }

  private String maketypo (String line) {
    Random rnum = new Random();
    int mode, position;

    if (line.length() < 3) return line;

    mode = rnum.nextInt() % 4;
    position = rnum.nextInt() % (line.length()-2);
    if (mode < 0) mode+=4;
    if (position < 0) position+=(line.length()-2);
    position++;

    // System.out.println("mode was " + mode + ", position was " + position );
    switch (mode) {
    case 0:
    case 1:
      // duplicate a char
      return (line.substring(0,position+1) + line.substring(position));
    case 2:
    case 3:
      // delete a char
      return (line.substring(0,position) + line.substring(position+1));
    }
    return line;
  }
}

5.5. Servlet capabilities beyond CGI

There is a variety of more things that can be done with servlets. Since servlets are persistent in memory, one can also make a supervisor servlet which knows about the other servlets running in the same ClassLoader.

Another example is load management. One can distribute and manage load between different servers by implementing a request redirection servlet which applies some heuristic about how to dispatch the incoming requests to other servers. In practise, the servlet would contain an algorithm for deciding the server getting the request and some mechanism for receiving feedback from the slave servers about their current status: load, number of requests being processed etc.

6. Technology comparison

As a technology servlets resemble CGI and FastCGI (FCGI), since all these three allow extending a server's functionality. Another parallell can be drawn between servlets and WWW server vendors' server APIs, as they too offer tools for modifying server behaviour.

Servlets are more efficient than the traditional CGI programs. A CGI program is restarted by the WWW server every time it serves a request, introducing thus a lot of overhead, whereas the servlet can serve many requests with no additional penalties due to restarts.

FCGI is a CGI-like interface but allows a process to be permanently in execution and serve many requests[3]. After the WWW server has started the FCGI program, the WWW server just pipes requests to the FCGI program. After having served the request, the FCGI program remains waiting for the WWW server to dispatch the next request to it[2]. This makes servlets and FCGI conceptually almost identical technologies.

The major differences between servlets and FCGI are:

Vendor specific server APIs is another means of changing a server's behaviour, e.g. NSAPI for Netscape's commercial server suite, and ISAPI for Microsoft's. These tools are heavily tied to the functionality and implementation of the servers themselves. Therefore, servlets beat these in terms of portability, but not in efficiency since the entire vendor APIs and their methods are compiled into native code. Some completely unconventional functionality will always remain as a task achievable only by applying server API extension tools.

7. Conclusions

Servlets offer a nice way of rapidly tailoring the services of a www server. The near future solution, before 100% pure Java WWW servers become fast enough, is to include the Servlet API to traditional servers. There are currently a number of WWW servers that already contain the Servlet API and many others are undergoing modifications to have the Servlet API included.

Future servlets may to some extent outrival FCGI technology based applications, probably to a great extent CGI based applications and to some extent the vendor specific server APIs. Everything depends on how fast the servlets get due to a continuous speed up of Java itself.


8. References

  1. Anon. The Common Gateway Interface: Overview, NCSA, 1995. http://hoohoo.ncsa.uiuc.edu/cgi/intro.html
  2. M.R.Brown. FastCGI Specification, Open Market Inc., 1996. http://www.fastcgi.com/kit/doc/fcgi-spec.html
  3. Anon. FastCGI: A High-Performance Web Server Interface, Open Market Inc., 1996. http://www.fastcgi.com/kit/doc/fastcgi-whitepaper/fastcgi.htm
  4. Anon. NSAPI Programmer's Guide, Netscape Communications Corp., 1997. http://developer1.netscape.com:80/docs/manuals/enterprise/nsapi/contents.htm
  5. Anon. Internet Server API Overview, Microsoft Corp., 1997. http://www.microsoft.com/win32dev/apiext/isapimrg.htm
  6. Anon. Java Servlets Out In The World, Javasoft, [18.11.1998]. http://jserv.javasoft.com/products/java-server/servlets/environments.html
  7. Anon. The Java-Apache Project, 1998. http://java.apache.org/
  8. Anon. Servlet Tutorial, Sun Microsystems Inc., 1997. http://jserv.java.sun.com/products/java-server/documentation/webserver1.1/servlets/servlet_tutorial.html
  9. Anon. The Java Servlet API, Sun Microsystems Inc., 1997. http://jserv.java.sun.com/products/java-server/documentation/webserver1.1/servlets/api.html
  10. Anon. Loading and Invoking Servlets, Sun Microsystems Inc., 1997. http://jserv.java.sun.com/products/java-server/documentation/webserver1.1/servlets/load.html
  11. Anon. Servlet Sandbox, Sun Microsystems Inc., 1997. http://jserv.java.sun.com/products/java-server/documentation/webserver1.1/security/sandbox.html


9. Further reading

Configuring Servlets
Describes the servlet configuration interface of the Java Web Server.
FAQ about Servlets
General, but far too short FAQ about servlets.
FastCGI Developers' Kit Index Page
Nitty-gritty details on how FastCGI can be setup to support several programming languages.
Filters and Servlet Chaining
Description on how to use servlets to achieve complex server-parsing functionality.
Internal Servlets
A list of general purpose servlets to be used as building blocks for other, servlet driven services.
Introduction to Servlets
Easy-going whitepaper describing what servlets are.
JRun Data Sheet
A commercial Java servlet engine that can be added to a variety of WWW servers.
Replacing CGI Scripts with Servlets
A thorough explanation on how servlets can be used to substitute CGI programs. Good examples included.
Sample Servlets
A collection of simple servlets which can be tested directly together with source code.
Server Side Includes
An in-depth description of how servlets are configured to make server-side includes to HTML pages.
Servlet Aliases
Description on how to define aliases for servlets in order to avoid using long servlet class names.
Understanding FastCGI Application Performance
Discussion about FastCGI's performance with measurements.
Using JavaBeans in Servlets and in JHTML Files
An advanced example of including Java code to a HTML page and having it compiled and executed on-the-fly.
Using Servlet Beans
An interesting paper about how Java Beans and servlet technology can be combined.

Mika "Miguel" Silander Mika.Silander@hut.fi