Writing Java Servlets


Writing Java Servlets

In concept, servlets are analogous to applets. Both applets and servlets reside on a server, but an applet runs in a Java-capable Web browser after the browser downloads the applet from the Web server. Because the Web browser is a client to the Web server, applets are referred to as client-side applications. A servlet, on the other hand, runs in a Java Virtual Machine (JVM) on the Web server. Thus, servlets are server-side applications.

Another difference between applets and servlets is that an applet typically produces some visible output, whereas servlets do not display anything. Instead, servlets perform specific tasks for the Web server. They are commonly used at websites to support interactive and dynamic Web pages, which are then displayed by the Web browser that downloads the pages.

A Web search engine such as Google (http://www.google.com/) is a good example of an interactive Web page; the user enters one or more keywords, and the Google search engine returns an HTML document containing links to other Web pages that contain the search words. The HTML document returned by the search engine is dynamic because the contents of that page depend on what search words the user types; it's not a predefined, static document.

To create an interactive Web page, you have to use certain HTML codes (to display the form that solicits user input) and implement special computer programs on the Web server. These programs process the user input (sent by the Web browser) and return requested information to the user, usually in the form of a dynamic Web page-a page that is constructed on the fly by a computer program. Such programs are known as gateways because they typically act as a conduit between the Web server and an external source of information such as a database (even if the database is simply a collection of files).

Traditionally, websites have used gateway programs that are started by the Web server and that exchange information with the Web server using a standard protocol known as Common Gateway Interface (CGI). These standalone CGI programs can be written in any language (C, C++, Perl, Tcl/Tk, and even Java). One drawback of CGI programs is that the Web server has to start a new process to run a standalone CGI program whenever the server receives data from an HTML form.

Servlets provide functionality similar to that of CGI programs, but servlets avoid the overhead of new process startup. Typically, the Web server runs a JVM, and that JVM, in turn, loads and runs the servlets. The JVM runs a servlet in a Java thread, which is faster and requires fewer operating system resources than a new process. Additionally, the JVM can keep a servlet loaded and running so that a single instance can handle many future requests. This makes servlets more responsive than other CGI programs, especially ones written in scripting languages such as Perl. At the same time, servlets are portable to any system that supports Java, just as Perl CGI programs can run on any system with a Perl interpreter.

Many websites already use servlets extensively. While browsing the Web, you may have accessed some servlets without even realizing it. Typically, a giveaway that the Web server is using a servlet is the occurrence of /servlet/ in the URL (in the same way that /cgi-bin/ commonly appears in URLs that refer to CGI programs). The next few sections explain how Java servlets work and what you need to develop servlets.

The Role of Java Servlets

A servlet performs specific tasks for a Web server and typically returns the results formatted as an HTML document (if necessary, servlets can also return images and other multimedia content). Often, the servlet program acts as a bridge between the Web server and some other repository of information such as a database. Typically, you use a servlet engine such as Apache Tomcat in conjuction with a Web server such as Apache httpd to set up a Java capable Web server. Figure 26-8 highlights the interrelationships among the Web browser, Web server, servlets, database, and HTML documents, using the Apache httpd and Apache Tomcat as examples. Web servers also serve images and other multimedia content, but the figure does not show these.

Click To expand
Figure 26-8: The Interrelationships among the Web Browser, Web Server, and Servlets.

As Figure 26-8 shows, the Web browser running on the user's system uses the HyperText Transfer Protocol (HTTP) to exchange information with the Web server. The Web server (also called the HTTP deamon or httpd) has access to the HTML documents and other content. Depending on the type of request from the browser, the Web server either serves an HTML document or passes the request to run a servlet thread to its Java servlet engine. The servlets run in the servlet engine and results are communicated to the Web server. If necessary, the servlets may access other system resources such as disk files or databases. Typically, a servlet generates a dynamic HTML document that the Web server sends back to the Web browser.

To understand how servlets process data from an HTML form, you need to know how a Web browser sends form data to the Web server. The Web browser uses the method attribute of the <form> tag to determine how to send the form's data to the Web server. There are two submission methods:

  • In the GET method, the Web browser submits the form's data as part of the URL.

  • In the POST method, the Web browser sends the form's data separately from the URL.

The GET and POST methods are so called because the browser uses the HTTP GET and POST command to submit the data. The GET command sends a URL to the Web server. This means that to send a form's contents to the server using the GET method, the browser must include all data in the URL. Because there is typically an upper limit on the length of a URL, the GET method cannot be used to transfer large amounts of form data from the browser to the server. The POST command, on the other hand, sends the form's data in a separate stream. Therefore, the POST method can send much larger amounts of data to the server.

Regardless of which method-GET or POST-is specified in the HTML form, a servlet can get the form's data by overriding specific methods in the HttpServlet class and calling other servlet API methods to retrieve specific parameters from the HTML form.

Because you, as the developer, design the form as well as the servlet that will process the form's data, you can select the method that best suits your needs. The basic guidelines for choosing a data submission method are as follows:

  • Use GET to transfer a small amount of data, and use POST to send potentially large amounts of data. For example, GET is appropriate for a search form that solicits a few keywords from the user. On the other hand, you'd want to use POST for a feedback form with a free-form text-entry area because the user might enter considerable amounts of text.

  • Use the GET method if you want to access the servlet without using a form. For example, if you want to access a servlet at the URL http://www.someplace.com/servlet/dbquery with a parameter named keyword as input, you could invoke the servlet with a URL such as http://www.someplace.com/servlet/dbquery?keyword=Linux. In this case, Linux is the value of the keyword parameter. If a servlet is designed to receive data with the POST method only, you cannot activate that servlet with a URL alone.

What You Need to Develop Servlets

To try out Java servlets and learn how to write a servlet, you need the following:

  • Java 2 Enterprise Edition (J2EE) SDK

  • A Web server that supports Java servlets or a Java servlet engine that works with a Web server

The J2EE SDK provides the APIs for writing servlets. In particular, J2EE SDK includes the servlet classes in the javax.servlet and javax.servlet.http packages. You also need the Java 2 Standard Edition (J2SE) SDK, which you already installed earlier in this chapter.

Cross Ref 

As for a Web server that can run Java servlets, your best bet is to use Apache Tomcat along with the Apache httpd server. Chapter 14 shows you how to download, install, and configure Apache Tomcat to work with the Apache httpd server. If you plan to try out some servlets, please set up Apache Tomcat by following the instructions in Chapter 14.

Downloading and Installing J2EE SDK

You can download the latest version of J2EE SDK from:

http://java.sun.com/products/servlet/download.html

The file that you eventually download is a shell script that you have to execute on your system. For example, here are the steps I followed to download and install J2EE SDK 1.4 (beta version):

  1. On the Web page http://java.sun.com/products/servlet/download.html, I click on the link for J2EE SDK 1.4. This brings up a new Web page where I can register and set up a user ID and password.

  2. I register and then enter my new user ID and password. The J2EE SDK download page appears.

  3. I select 'Linux Install' from the drop-down list near the end of the page and then click Download. The license agreement appears.

  4. I click Accept to accept the license agreement. A new page appears with the link to the file to be downloaded.

  5. I click the link labeled 'Download j2sdkee-1_4-beta-linux.sh.' It's a file close to 32 MB in size. The file starts to download and I save it in the /usr/local directory.

  6. After downloading is complete, I make the file executable with the following command:

    chmod +x j2sdkee*.sh
  7. I execute the shell script with the following command:

    ./j2sdkee*.sh

    A GUI installer screen appears informing me that Java 2 SDK Enterprise Edition will be installed on my system.

  8. I click Next. The installer displays the license agreement again. I click the Approve radio button and then click Next. The installer shows the name of the directory where the current Java 2 SDK Standard Edition runtime environment is installed.

  9. I make sure that the J2SE SDK directory is correct and then click Next. The installer asks for the name of the directory where to install J2EE and shows a suggested directory (/usr/local/j2sdkee1.4).

  10. I accept the suggested directory and click Next. The installer installs the J2EE files. When done, I click Finish to exit the installer.

    Insider Insight 

    After installing J2EE SDK, I had to copy the j2ee.jar file from the lib subdirectory of the J2EE installation to the jre/lib/etc subdirectory of the Java 2 SDK install directory. For example, on my system the JAVA_HOME environment variable is set to the directory where the Java 2 SDK is installed. So I type the following commands to copy the j2ee.jar file to the appropriate location:

    cd /usr/local/j2sdkee1.4/lib
    cp j2ee.jar $JAVA_HOME/jre/lib/ext

After completing these steps, I am able to write and compile servlets on my Red Hat Linux system.

Linking HTML Forms to Servlets

Before you jump into servlet programming, you need to understand how to associate servlets to an HTML form. A key relationship between servlets and HTML forms is that the servlet processes the data that users enter on the form. One of the attributes of the form specifies the name of the servlet that receives the input from the form. Additionally, each element of the form has an identifying name that helps the servlet isolate the user's input for that element. This section highlights the aspects of an HTML form that are important when you are writing a servlet to handle the form's data.

Consider a typical book order form that lets the user sign in using an ID and password, select one or more books, select the payment option, fill out the credit card information, and submit the order. Figure 26-9 shows a simple book order form.

Click To expand
Figure 26-9: A Book Order Form in HTML.

Listing 26-3 shows the HTML text used to display the book order form. You should save this HTML text in a file named OrderBooks.html.

Listing 26-3: The OrderBooks.html File, Which Displays the Book Order Form
Start example
<html> <head> <title>Book Order Form</title> </head> <body> <form action="../servlet/OrderBooks/" method=post> <h3> Book Order Form</h3> <hr> <b>Please sign in and order</b> <pre> Your ID: <input type=text size=10 name=id>  Password:<input type=password size=10 name=passwd> 
Select books to purchase:
          <select name=books size=4 multiple>
            <option>Red Hat Linux Professional Secrets
            <option>Discover Perl 5
            <option>UNIX Webmaster Bible
            <option>Success with Windows 95
            <option>X Window System Programming
            <option>Object-oriented programming in C++
            <option>Visual C++ Developer's Guide
            <option>Borland C++ Developer's Guide
            <option>Turbo C++ Bible 
           <option>Microsoft Macro Assembler Bible
          </select>  Special Instructions:
          <textarea name=instructions rows=2 cols=35></textarea>
  Charge:
  <input type=radio checked name=card value="Visa">Visa
          <input type=radio name=card value="MC">MasterCard
          <input type=radio name=card value="Amex">American Express
  Acct No: <input type=text name=acct size=16> Exp Date:<input type=text name=expire size=5> <hr>
          <input type=submit value="Order">
  <input type=reset> </pre> </form> </body> </html>
End example

This is a good example of the typical HTML elements that you can use in interactive forms. You can also see how the <form> element associates a servlet URL with a form. Here are the key points to note in this HTML sample:

  • The entire form is enclosed within <form> and </form> tags. The action attribute of the <form> tag specifies the URL of the servlet that processes this form's data. The method attribute specifies how the Web browser sends the form's data to the Web server.

  • The <input> tag defines a number of common form elements, such as single-line text fields, password fields, radio buttons, and submit buttons.

  • The <select> element defines menus. An <option> tag defines each menu item.

  • The <textarea> element allows the user to enter multiple lines of text.

  • Most importantly, each of the tags-<input>, <select>, and <textarea>-has a name attribute that identifies that input parameter. In the servlet that handles this form's data, you have to use the value of the name attribute to indicate which input parameter's value you want to retrieve.

A Servlet That Reads an HTML Form

The previous sections explain how servlets work, what you need to use and develop servlets, and how HTML forms are linked to servlets. This section shows you a simple Java servlet that retrieves the parameters that the user enters in the book order form shown in the section 'Linking HTML Forms to Servlets' (see Figure 26-9).

The book order form uses a <form> tag that begins with the following:

<form action="../servlet/OrderBooks/" method=post>

This tells you that you need a servlet named OrderBooks to process the data sent by this form. Listing 26-4 of the OrderBooks.java file that implements the servlet:

Listing 26-4: The OrderBooks Servlet, Which Processes a Book Order Form
Start example
//---------------------------------------------------------------
// File: OrderBooks.java
// A servlet that demonstrates how to process data from
// a form.
//---------------------------------------------------------------
import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class OrderBooks extends HttpServlet
{
    public void doPost(HttpServletRequest  request,
                       HttpServletResponse response)
                            throws ServletException, IOException
    {
        StringBuffer buffer = new StringBuffer();
        String title = "Received book order";
        // Set content type to HTML
        response.setContentType("text/html");
        // Write the response using HTML tags.
        PrintWriter out = response.getWriter();
        buffer.append("<html><head><title>");
        buffer.append(title);
        buffer.append("</title></head><body bgcolor=\"#ffffff\">");
        buffer.append("<h2>" + title + "</h2>");
        buffer.append("Customer ID: ");
        buffer.append(request.getParameter("id"));
        buffer.append("<br>");
        buffer.append("Password: ");
        buffer.append(request.getParameter("passwd"));
        buffer.append("<br>");
        buffer.append("Books Ordered: ");
        String books[] = request.getParameterValues("books");
        if(books == null)
            buffer.append("NONE<br>");
        else
       {
            buffer.append("<ul>");
            for(int i = 0; i < books.length; i++)
            {
                buffer.append("<li>");
                buffer.append(books[i]);
            }
            buffer.append("</ul>");
        }
        buffer.append("Charge to: ");
        buffer.append(request.getParameter("card"));
        buffer.append("<br>");
        buffer.append("Account Number: ");
        buffer.append(request.getParameter("acct"));
        buffer.append("<br>");
        buffer.append("<br>");
        buffer.append("Expiration Date: ");
        buffer.append(request.getParameter("expire"));
        buffer.append("<br>");
        buffer.append("Special Instructions = ");
        buffer.append(request.getParameter("instructions"));
        buffer.append("<hr>");
        buffer.append("<em>Order received at: ");
        buffer.append(new Date().toString());
        buffer.append("</em>");
        buffer.append("</body></html>");
        out.println(buffer.toString());
        out.close();
    }
}
End example

A real-life OrderBooks servlet would use the customer's ID and password to authenticate the customer and retrieve the customer record from a database. Then, the servlet should probably display all of the information that will be used to process the order and allow the customer to confirm that information. Only then should the servlet actually record the order in the database. In this case, the OrderBooks servlet simply sends back the parameters received from the order form in another HTML document.

As Listing 26-4 illustrates, to use the servlet classes, you need to include the following import statements in a servlet:

import javax.servlet.*;
import javax.servlet.http.*;

Like everything else in Java, a servlet is also a class. Listing 26-4 defines OrderBooks as a subclass of the HttpServlet class (from the javax.servlet.http package):

public class OrderBooks extends HttpServlet

This is how you declare a servlet that is designed to work with the HTTP protocol (which is how the Web server communicates with the Web browser).

You implement the servlet by overriding the appropriate methods of the HttpServlet class. If you are designing the servlet to handle HTML form data, the method of form data submission-GET or POST-determines the method you have to override. If the form's data is submitted using the GET method, you should override the doGet() method. On the other hand, if the method attribute of the <form> tag is POST, you should override the doPost() method.

The OrderBooks servlet expects the form data to be sent by the POST method, so it overrides the doPost() method of the HttpServlet class. The doPost() declaration is as follows:

public void doPost(HttpServletRequest  request,
                   HttpServletResponse response)
                        throws ServletException, IOException

As this declaration shows, the doPost() method receives two arguments: an HttpServletRequest and an HttpServletResponse. The doPost() method throws two exceptions: ServletException and IOException. Apart from declaring the function like this, there is no need to handle any exceptions in the method.

In the body of the doPost() method, you use the HttpServletRequest interface to access HTTP-protocol-specified header information and any parameters sent by the Web browser. In particular, you would call this interface's getParameter() method to obtain the value of a parameter whose name matches the name assigned with the name attribute in the HTML tag. Recall from the discussion in the section 'Linking HTML Forms to Servlets' that the name attribute of the <input>, <select>, and <textarea> HTML tags identifies the input parameter. You have to use the name of each as an argument when retrieving the parameter value with the getParameter() method. For example, to get the value that the user had entered for the HTML form element <input type=text size=10 name=id>, you would call request.getParameter("id").

The HttpServletResponse interface is used to send data back to the Web browser. You would set the MIME type of the servlet response by calling a method of this interface. For example, the following line of code sets the response type to text/html (this means that the servlet sends back a text file with HTML tags):

response.setContentType("text/html");

To actually send the response to the Web browser, you would get an output stream by calling a method of the HttpServletResponse interface, and then you would write the servlet's response to that output stream. For example, the OrderBooks servlet calls the getWriter() method of the HttpServletResponse interface named response to get a PrintWriter stream for formatted text output:

PrintWriter out = response.getWriter();

You can send HTML text to the Web browser client by calling the println() or print() method of this PrintWriter class. However, instead of writing text a line at a time, it's better to accumulate the text in a StringBuffer and then send the accumulated text with a single call to the println() method. The OrderBooks servlet illustrates this approach. For example, here is a line that initializes a StringBuffer named buffer:

StringBuffer buffer = new StringBuffer();

The servlet's response is then accumulated in this buffer through calls to the append() method of StringBuffer. For example, the following lines of code append the HTML <head> and <body> tags to the buffer:

buffer.append("<html><head><title>");
buffer.append(title);
buffer.append("</title></head><body
               bgcolor=\"#ffffff\">");

If a parameter can have multiple values, you have to call the getParameterValues() method. In the book order form, the customer may select multiple books from the selection menu (in the HTML form that menu is assigned the name books). For example, the following code shows how to get the values of the books parameter and format them in an unnumbered list enclosed in the HTML tags <ul> and </ul>:

String books[] = request.getParameterValues("books");
if(books == null)
    buffer.append("NONE<br>");
else
{
    buffer.append("<ul>");
    for(int i = 0; i < books.length; i++)
    {
        buffer.append("<li>");
        buffer.append(books[i]);
    }
    buffer.append("</ul>");
}

The first line calls getParameterValues() to get the values in a String array named books[]. If the return value is null, the string NONE is appended to the buffer. Otherwise, the for each returned value is appended to the buffer as an entry in an unnumbered list.

After everything has been appended to the StringBuffer, the println() method of the PrintWriter class is used to send the response to the client:

out.println(buffer.toString());

After the response has been written to the PrintWriter, you should close the stream like this:

out.close();

Testing Java Servlet with Apache httpd and Tomcat

To test the OrderBooks servlet, you need a Web server capable of running Java servlets. I tested the servlet by using a Apache httpd server that used the Apache Tomcat server to support servlets.

Cross Ref 

Consult Chapter 14 for detailed instructions on how to download and configure Apache Tomcat to work with Apache httpd server. You need to complete that step before you can try out the servlet.

I log in as root and follow these steps to compile and test the OrderBooks servlet shown in Listing 26-4:

  1. Check that the CATALINA_HOME environment variable is set to the directory where Apache Tomcat is installed (as explained in Chapter 14). On my system, CATALINA_HOME is set as follows:

    export CATALINA_HOME=/usr/local/jakarta-tomcat-4.1.18-LE-jdk14
  2. Copy the OrderBooks.java file to the location where the classes for the servlet examples should be located. In my case, I type the following command:

    cp OrderBooks.java $CATALINA_HOME/webapps/examples/WEB-INF/classes
  3. Change directory to where the OrderBooks.java file is saved and then compile the file. Here are the commands I type:

    cd $CATALINA_HOME/webapps/examples/WEB-INF/classes
    javac OrderBooks.java
    
  4. Copy the HTML file shown in Listing 26-3-OrderBooks.html-to the directory where the Apache Tomcat servlet examples are located. In my case, I type the following command to copy the HTML file to the correct location:

    cp OrderBooks.html $CATALINA_HOME/webapps/examples/servlets
  5. Start Apache Tomcat with the following command:

    $CATALINA_HOME/bin/startup.sh
  6. Wait ten seconds or so and then start Apache httpd server with the following command:

    service httpd start
  7. Start the Mozilla Web browser and point the Web browser to the following URL:

    http://localhost/examples/servlets/OrderBooks.html

    This causes the HTML form that was shown in Figure 26-9 to appear.

  8. I fill in some information the information in the form and click Order. Mozilla displays some dialog boxes about sending unencrypted information. I click OK, and Mozilla displays the HTML document returned by the OrderBooks servlet. Figure 26-10 shows the servlet's response to what I entered on the book order form.

    Click To expand
    Figure 26-10: The OrderBooks Servlet Displays What the User Entered in the Book Order Form.