By Mark Andrews
You could say that a servlet is what you get when you cross an applet with a CGI script. From a programmatic point of view, a servlet resembles an applet; it is an executable that's written in the Java TM programming language, and it usually (though not always) is executed in response to an invocation from an HTML page.
From the standpoint of the kind of work it does, a servlet more closely resembles a CGI (Common Gateway Interface) script. Like a CGI script, a servlet can respond to user input -- such as the clicking of a button on a form -- and can either collect information from the user or send information back to the user (or both), depending upon what kinds of actions are initiated by the form the user fills out. If a servlet is designed to provide information to the user, it can track down the information it needs in any number of ways -- by retrieving it from a database, for example. The servlet can then dynamically construct an HTML page containing the information it has collected, and can display that page in the user's browser.
"Because they are designed to fulfill the "Write Once, Run Anywhere TM " promise inherent in the Java programming language, servlets can be executed without modification on any platform."
Servlets are not the only mechanism that can interact in this way with a user. CGI scripts can perform similar operations -- and indeed, until servlets came along, CGI scripts were the standard mechanism for creating and displaying HTML pages dynamically. But servlets have many advantages over CGI scripts, and are quickly replacing them in the world of enterprise computing.
One way in which a CGI script is inferior to a servlet that a CGI script spawns a new process every time it is executed, consuming more and more processing time -- and more and more server resources -- every time it is invoked. Also, CGI scripts are platform-dependent and cannot take advantages of many of a server's capabilities because they run in processes that are separate from the server's process. For example, a CGI program cannot write to a server's log file.
Servlets do not have any of these liabilities. They are efficient and scalable because they don't create new processes every time they execute; instead, servlets are handled by separate threads within the Web server process. They can write to server log files and can take advantages of other server capabilities because they run in the server's own process. And, because they are designed to fulfill the "Write Once, Run Anywhere TM " promise inherent in the Java programming language, servlets can be executed without modification on any platform.
Writing Servlets with IDEs
Before you can invoke a servlet, you must compile it. Many vendors offer IDEs equipped with servlet wizards that make it easy to create and compile servlets almost automatically. The Guestbook servlet presented in this article was created and compiled using IBM's WebSphere Studio IDE. You can download a free trial version of WebSphere Studio from the IBM Web site.This article introduces servlets and shows how they can be used in applications written in accordance with the Sun BluePrints Design Guidelines for the Java TM 2 Platform, Enterprise Edition (J2EE) . The article presents an example servlet that you can invoke, study, and -- if you like -- download for more experimentation.
The example servlet is named Guestbook. When you invoke it, the servlet displays a Guestbook page and prompts you to type in some information about yourself. When you fill in the requested data and click a Submit button, the servlet checks to see if you have provided all the data that it feels it needs for a complete database entry. If you have failed to fill in any critical fields -- not just any fields, but any critical fields -- the servlet prompts you to supply the missing data.
Finally, when the servlet has collected all the information it has asked for, it adds the data you have entered to a text file that serves as a database.
To see how the Guestbook servlets works, you must compile it and then install it on a Web server -- or, if you don't have access to a Web server, on a workstation equipped with special software for running servlets locally. One such software package is the servletrunner tool.
Whether you decide to compile and invoke the servlet or not, you'll get an opportunity later in this article take a look at its source file. You can also examine the source file of the HTML page that invokes the servlet. If you like, you can download both the servlet and the HTML page that calls it. Then, if you like, you can download and install servletrunner and play around with Guestbook servlet at your leisure -- and, perhaps, use it as a stepping stone for creating similar servlets of your own.
Invoking a ServletAs mentioned earlier, in the first paragraph of this article, a servlet is an executable that's written in the Java programming language. Servlets are supported through the Servlet API, an extension to the Java programming language.
To create a servlet, you must write a program that implements the javax.servlet.Servlet interface. Most servlets implement this interface by extending either the javax.servlet.GenericServlet class, which is implemented in the javax.servlet package, or the javax.servlet.http.HttpServlet class, which provides extra functionality needed by HTTP servlets and is implemented in the javax.servlet.http package. Almost all servlets written today are designed to use the HTTP protocol, so most servlets currently extend the javax.servlet.http.HttpServlet class.
One of the most common ways to invoke a servlet from an HTML page is to provide a link to it from a button on a form. You can also invoke a servlet by embedding a link to it in an HMTL page, or even by typing its pathname into the Address bar of a browser. Still another way to invoke a servlet is to call it from another servlet -- but we won't go any further into that option in this article.
The Java Servlet API provides a number of methods that servlets can (and do) override. One method you will always override is the init() method. (Servlets, like applets, are always equipped with an init() method rather than a main() method). Two other methods that are commonly overridden are the doGet() method, which retrieves data in response to GET actions embedded in a form, and the doPost() method, which posts data in response to POST requests.
When a user invokes a servlet by clicking a button or using some other mechanism that activates a link to the servlet, the Web server that is hosting the user's browser session tracks down the servlet by looking in a special directory. The name of this directory can vary, depending on the Web server or application server being used. But no matter what the actual pathname of the directory is, an HTML page that invokes a servlet can always use the /servlet alias to find the servlet it's looking for. For instance, the HTML code
<FORM METHOD=GET ACTION="/servlet/HelloWorld">
will always invoke a servlet named HelloWorld -- provided, of course, that (1) the Web server being used supports servlets and (2) a "Hello World" a servlet actually exists in the directory in which servlets are stored on your Web server.
Figure 1 shows one of the most common ways of using a servlet. A user (1) requests some information by filling out a form containing a link to a servlet and clicking the Submit button (2). The server (3) locates the requested servlet (4). The servlet then gathers the information needed to satisfy the user's request and constructs a Web page (5) containing the information. That Web page is then displayed on the user's browser (6).
We have scarcely begun to cover what there is to know about servlets. But we do have enough information now to take a look at the Guestbook servlet, the example servlet that is provided with this chapter.
To access a servlet, you simply invoke it by writing a line of HTML code on an ordinary HTML page. To take a look at the HTML code that invokes the Guestbook servlete, just click the red HTML button:
The page that invokes the Guestbook servlet looks pretty busy, but it's really just a plain old static HTML page, and only a line or two of its HTML code is directly related to the invocation and execution of a servlet. Here's a line of HTML code that isn't directly connected with a servlet but sets things up for invoking one:
<INPUT TYPE="submit" NAME="InvokeServlet" VALUE="Submit">
If you've ever worked with forms on the HTML level, you know what this line does: It creates a button that the user can click to submit a form. Farther down on the page, we see another line of HTML code that invokes a servlet when the user clicks the Submit button:
<FORM METHOD="POST" ACTION="/servlet/FormDisplayServlet">
As we have seen, servlets always reside in a directory that can be accessed using the alias /servlet. So it's easy to see what the preceding line does: It sends some data -- in this case, all the data that the user has entered on the Guestbook form -- to a servlet named FormDisplayServlet, which resides in the Web server's /servlet directory.
A large chunk of the Guestbook servlet is the part that collects information from the user. This part of the servlet displays a number of text fields and combo boxes that the user can fill in. For example, this line of HTML code creates the first text field on the page -- the field in which the user types his or her first name:
<INPUT TYPE="text" NAME="firstname" VALUE="" SIZE=44 MAXLENGTH=30>
The Guestbook HTML page uses combo boxes to collect other kinds information. This block of code creates a combo box that is used to request the user's occupation:
<select name="profession">
<option>Select One
<option>Student
<option>Homemaker
<option>Computer-related
<option>Business/Office
<option>Sales
<option>Industry
<option>Education
<option>Sports
<option>Entertainment
<option>Agriculture/Outdoors
<option>Other
</select>
When the user has finished filling in the Guestbook form, she clicks the form's Submit button. The Guestbook program's HTML page then tracks down and executes the form-display servlet, which analyzes the user's data and then responds to it. You'll see how that happens in the next section, "How the Guestbook Servlet Works."
Now that you've seen how the Guestbook program's HTML page works, we're ready to take a look at the Guestbook servlet. At the end of this section, you'll get a chance to examine the servlet's source file in its entirety. First though, it might be helpful to break the servlet down into parts and take a look at some of its individual routines.
In the Guestbook servlet's source file, the code that implements the servlet is all mixed up with code that analyzes user input to see whether the user has filled in all critical fields. That coding technique makes it easy to see exactly what an instructional servlet does, because all of the servlet's code is in your face at all times. In a real-world servlet, though, a better technique might be to strip out all the input-analysis code and encapsulate it in a JavaBean. That modification would streamline the servlet and would make it possible to update or improve the servlet's supporting data-analysis code later on without touching the servlet itself. In an upcoming issue, we'll present a follow-up tutorial that will show how a JavaBean could improve the Guestbook program.
The Guestbook servlet's source file is named FormDisplayServlet.java. The servlet instantiates just one class, named FormDisplayServlet.
The FormDisplayServlet.java source file looks rather complicated at first glance, but most of the logic it that contains is devoted analyzing the user's input to ensure that no required fields are left blank. That is an important task because the purpose of the Guestbook form is to collect data, and the data that's collected is not worth much if the user leaves critical fields blank -- for example, if the user fails to type in his or her first name or last name, or leaves the city or country fields blank.
The init() Routine
The first method that's called in the Guestbook program is an override of the init() method defined in the javax.servlet.http package. The first part of the init() method used in the Guestbook servlet looks like this:
public void init(ServletConfig config)
throws ServletException
{
super.init(config);
connections = 0;
}
boolean error;
String want_offers = "YES";
String want_info = "YES";
Enumeration params;
String[] entries = {"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", ""};
// This servlet keeps track of a lot of strings.
// These are the names of variables.
public final String[] parms = {"firstname", // 0
"lastname", // 1
"age", // 2
"profession", // 3
"email", // 4
. . .
// These are the same variables, expressed as
// labels that are written in English and look nicer
// on the page.
public final String[] labels = {"First Name", // 0
"Last Name", // 1
"Age", // 2
"Profession", // 3
"Email", // 4
"Home Page", // 5
. . .
};
As you can see, the first thing the Guestbook servlet's init() method does is override its superclass's init() method by calling super.init(config). Currently, that's a required call in every HTTP servlet. So it's probably best to take care of it right away and then move on to more interesting routines.
After overriding super.init(), the Guestbook servlet defines a number of variables, including a couple of arrays to help it keep track of its parameters. Then the program calls the doPost() method, which does three things:
It analyzes the user's input.
It stores that input in a text file that's used as a makeshift database.
Finally, it sends a response back to the user.
You'll see how all three of those operations work in the remaining sections of this article.
The doPost() Method
When the Guestbook servlet has executed its init() function, it overrides the HttpServlet class's doPost() method. At first glance, Guestbook's doPost() routine looks quite complex. Actually, though, the first half of the routine is nothing but a series of statements that define the variables used for each of the servlet's parameters. These variable definitions are so cut-and-dried that the code initiating them can actually be generated automatically. In fact, this part of the Guestbook's source file was automatically generated, using IBM's WebSphere Studio IDE ( see box).
Here's the initial part of the Guestbook servlet's doPost() method:
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// This line tells the servlet where the database is.
String guestbook = request.getRealPath("guestbook.txt");
//First name
String firstname = "";
try
{
firstname = request.getParameter("firstname");
}
catch (Exception e)
{
e.printStackTrace();
}
userName = firstname;
//Last name
String lastname = "";
try
{
lastname = request.getParameter("lastname");
//Age
String age = "Select One";
try { age = request.getParameter("age");
}
catch (Exception e)
{
e.printStackTrace();
}
. . .
Once all this preparatory work is done, the Guestbook servlet is finally to get down to business. Here are the lines in which that starts to happen:
response.setContentType("text/html");
PrintWriter pw = new PrintWriter (response.getOutputStream());
pw.println("");
pw.println(" <head><title>GuestBookServlet</title></head>");
pw.println("");
These five lines are worth studying closely. Here's what they do:
The Rest of the doPost() Method
The rest of the doPost() method is fairly straightforward. First there's a loop that uses a switch statement to check the thoroughness of the user's input. If the servlet determines that that one or more required fields have been left blank, it calls a method named printErrorPage(). The printErrorPage()method displays an HTML page that prompts the user to go back and fill in the omitted fields. If no errors are detected, doPost() calls a method named printData(), which adds the user's input to a database (actually just a text file) and then thanks the user. Here's the code that determines which of those pages should be displayed, and then sends the selected page back to the user:
// If any required field has been left blank,
// we display an error page.
if (error == true)
{
params = request.getParameterNames();
printErrorPage(pw, params, true);
}
// If no important items have been left blank,
// we display the Thank You HTML page and update the
// database with the user's input.
else
{
// This is the method that prints the data to the database
// and displays the Thank You HTML page.
printData(null, null, dbString, guestbook, pw);
}
. . .
When the doPost() method has sent an appropriate response page to the user, the servlet sets up an output stream that will print a </body> tag and an </html> tag to out the Web page it is creating. Then doPost() concludes its own work with by calling the PrintWriter.close() method:
. . .
pw.println("");
pw.close();
}
The printErrorPage() and printData() Methods
The printErrorPage() and printData() functions are the first functions we have examined that are not overrides of HttpServlet methods. Instead, they are custom routines unique to the Guestbook servlet. The printErrorPage() method is particularly worth studying because it shows quite clearly how a servlet can generate a complete HTML page. In this case, printErrorPage() constructs a Web page containing an error message if it has been determined that the user has left one or more required fields blank. Then the error page is sent back to the user and displayed in the user's browser:
public void printErrorPage(PrintWriter pw, Enumeration e,
boolean errorStatus) throws IOException
{
// This loop prints the error message.
pw.print("<H1>Oops!</H1>);
pw.print("<BR>");
pw.print(s8 + "<BR>"); // s8 and s9 are predefined strings;
pw.println(s9 + "<BR><P>"); // see complete source listing.
for (int n = 0; n < NR_OF_PARAMS; n++) {
if (entries[n] == "ERROR") {
pw.println(labels[n]);
pw.print("<BR>");
entries[n] = "";
}
}
pw.println("</BODY></HTML>");
pw.flush();
pw.close();
return;
}
// end of printErrorPage()
The printData() method is a little more complicated; before it dispatches its page to be printed, it checks to see which required fields on the Guestbook form have been left blank, and then it tells the user exactly what fields still need to be filled in. Those operations aren't directly related to the overall creation and implementation of servlets, so you we won't dwell on them here. But they are commented pretty thoroughly in the Guestbook servlet's source code, and you can check them out there if you're interested.