November 19th, 1998
Mika Silander
Department of Computer Science
Helsinki University of Technology
Mika.Silander@hut.fi
Abstract
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.
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:
javax.servlet.http.HttpServlet.
To implement the functionality of the HttpServlet class, the
following methods should be provided:
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]:

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].

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();
}
}
*.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:
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.