Servlets in Apache Tomcat and BEA Systems' WebLogic Server

Deploy servlets and Web applications in two popular application servers

In "Develop N-Tier Applications Using J2EE" (JavaWorld, December 1, 2000), I gave an introduction to Java 2 Enterprise Edition (J2EE) and an overview of the technologies it includes. In this article, we delve into a little more detail with one of the more widely used J2EE technologies: servlets. We begin with a brief recap of servlet development fundamentals, then show how to build a Web application to house them. We discuss the use of Web Application Archives (WARs), then illustrate deployment of the servlet and Web application in Apache Tomcat. In addition, we'll look at deploying the same servlet and Web application in one of the most widely-used servlet containers -- BEA's WebLogic Server.

Develop servlets

Servlets were designed to allow for extension of a server providing any service. Currently, however, only HTTP and JSP page servlets are supported. In the future, a developer may be able to extend an FTP server or an SMTP server using servlets.

Generic servlets

A servlet extends a server's functionality by offering a specific service within a well-defined framework. It is a small piece of Java code -- often just a single class -- that provides a specific service. For example, an HTTP servlet may provide a bank customer with details of her recent deposits and withdrawals. Another HTTP servlet could allow a customer to view, and even edit, his mailing address.

To deploy a servlet usually requires configuration of the hosting server application. When the server encounters a particular type of request, it invokes the servlet, passing to it details about the request and a response object for returning the result.

All servlets implement the javax.servlet.Servlet interface either directly -- in the case of generic servlets -- or indirectly, in the case of HTTP or JSP servlets. The javax.servlet.Servlet interface's important methods include:

  • init(): defines any initialization code that should be executed when the servlet loads into memory.
  • service(): the main method called when the servlet receives a service request. It defines the bulk of the processing logic provided by the servlet.
  • destroy(): defines any clean-up code required before removing the servlet from memory.

When the servlet container first loads a servlet it invokes the servlet's init() method to initialize the servlet. Then, as requests are made to execute the servlet, the servlet container repeatedly invokes the servlet's service() method to provide the required service. Finally, when the servlet container no longer needs the servlet, it invokes the servlet's destroy() method and unloads it from memory. Note that during the lifetime of a single servlet instance, the init() and destroy() methods will be invoked only once, whereas the service() method will be invoked many times -- once each time a request is made to execute the servlet.

JSP Page servlets are mostly of interest to implementers of JSP containers and are beyond the scope of this article. Rather, we now go on to look specifically at HTTP servlets.

HTTP servlets

HTTP servlets extend the javax.servlet.http.HttpServlet class. This class extends the javax.servlet.GenericServlet class, which in turn implements javax.servlet.Servlet. The HttpServlet class overrides the service() method in such a way as to handle the different types of HTTP requests: DELETE, GET, OPTIONS, POST, PUT, and TRACE. For each of these request types the HttpServlet class provides a corresponding doXXX() method.

Although you can override the service() method in your servlet class, there is rarely any need to do so. More likely you'll want to override individual doXXX() methods. If you do override the service() method, be aware that the default doXXX() methods will be called only if you call super.service or invoke them directly.

For most applications you will want to override the doPost() and doGet() methods, since one of these usually handles data submitted by a user from an HTML FORM.

To summarize, when writing your HTTP servlets you should:

  1. Import -- at a minimum -- the servlet classes:
    • javax.servlet.ServletException
    • javax.servlet.http.HttpServlet
    • javax.servlet.http.HttpServletRequest
    • javax.servlet.http.HttpServletResponse
  2. Make the class public
  3. Have the class extend HttpServlet
  4. Override the appropriate doXXX() method(s) to implement your request/response logic

We illustrate these with a simple example below.

A sample servlet: RequestDetails

In the example below we illustrate a simple HTTP servlet. The first line simply defines what package the servlet belongs to. The next code block imports the classes used by this servlet. Then comes the servlet class definition. As you can see, the RequestDetails class extends HttpServlet.

The body of RequestDetails defines two methods: doGet() and doPost(). The doGet() method defines the primary functionality of this servlet. The doPost() method simply calls doGet(). The servlet therefore handles both get and post requests in the same way.

The doGet() method constructs an HTML page containing details of the HTTP request sent to the server. Note the method's first two lines. The first line sets the content type for the response. In general, you will be constructing an HTML page, in which case the content type should be set to text/html. The second line in the doGet() method obtains a reference to a PrintWriter output stream. All output to be returned to the client is then written to that output stream:

package org.stevengould.javaworld;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * This class provides a simple example of a servlet, and
 * illustrates some of the information available from an
 * HTTP request.
 */
public class RequestDetails extends HttpServlet
  {
  /**
   * Handler for all GET requests. We simply dump out the
   * request header information, followed by the body of
   * the request.
   * @param request the HTTP request submitted to the
   *        server for processing. It is this object that
   *        contains the details of the requested URL, and
   *        it is the details of this object that we
   *        output as a response.
   * @param response the response object to be used to
   *        send a result back to the client.
   * @exception IOException thrown if a communications
   *        error occurs.
   * @exception ServletException if the GET request could
   *        could not be handled
   */
  public void doGet( HttpServletRequest request,
                     HttpServletResponse response )
    throws IOException, ServletException
    {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Request Details Example</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h3>HTTP Request Header</h3>");
    out.println("<table border='1'>");
    out.println(" <tr bgcolor=#e0e0e0>");
    out.println("  <td><strong>Name</strong></td>");
    out.println("  <td><strong>Value</strong></td>");
    out.println(" </tr>");
    Enumeration e = request.getHeaderNames();
    while (e.hasMoreElements())
      {
      String name = (String)e.nextElement();
      String value = request.getHeader(name);
      out.println(" <tr>");
      out.println("  <td bgcolor=#e0e0e0>"+name+"</td>");
      out.println("  <td>"+value+"</td>");
      out.println(" </tr>");
      }
    out.println("</table>");
    out.println("<h3>HTTP Request Information</h3>");
    out.println("<table border='1'>");
    out.println(" <tr bgcolor=#e0e0e0>");
    out.println("  <td><strong>Name</strong></td>");
    out.println("  <td><strong>Value</strong></td>");
    out.println(" </tr>");
    out.println(" <tr>");
    out.println("  <td bgcolor=#e0e0e0>Method:</td>");
    out.println("  <td>"+request.getMethod()+"</td>");
    out.println(" </tr>");
    out.println(" <tr>");
    out.println("  <td bgcolor=#e0e0e0>Request URI:</td>");
    out.println("  <td>"+request.getRequestURI()+"</td>");
    out.println(" </tr>");
    out.println(" <tr>");
    out.println("  <td bgcolor=#e0e0e0>Protocol:</td>");
    out.println("  <td>"+request.getProtocol()+"</td>");
    out.println(" </tr>");
    out.println(" <tr>");
    out.println("  <td bgcolor=#e0e0e0>PathInfo:</td>");
    out.println("  <td>"+request.getPathInfo()+"</td>");
    out.println(" </tr>");
    out.println(" <tr>");
    out.println("  <td bgcolor=#e0e0e0>Remote Address:</td>");
    out.println("  <td>"+request.getRemoteAddr()+"</td>");
    out.println(" </tr>");
    out.println("</table>");
    out.println("<hr>");
    Date date = new Date();
    out.println("<p align=center>Page generated on "+date);
    out.println("</body>");
    out.println("</html>");
    out.close();
    }
  /**
   * For POST requests, we will simply perform the same
   * operations as for GET requests. The best way to do this
   * is to simply invoke the doGet() method with the appropriate
   * parameters.
   * @param request the HTTP request submitted to the server
   *        for processing. It is this object that contains
   *        the details of the requested URL, and it is the
   *        details of this object that we output as a
   *        response.
   * @param response the response object to be used to send a
   *        result back to the client.
   */
  public void doPost( HttpServletRequest request,
                      HttpServletResponse response )
    throws IOException, ServletException
    {
    doGet(request, response);
    }
  }

Compile the servlet

Since servlets use Java extension classes (classes that are not part of the core JDK) you must be sure to correctly set up your CLASSPATH before attempting to compile any servlet. The Java compiler needs to be able to find the javax.servlet.* packages and classes. Other than that, compilation proceeds just as for any other Java program:

  javac RequestDetails.java

Create a Web application

Now that you have created the servlet, you need to think about deployment. The Java Servlet 2.2 specification introduced at least two significant new features: a Web application and a Web application archive (WAR). According to the Servlet 2.2 specifications:

A Web application is a collection of servlets, HTML pages, classes, and other resources that can be bundled and run on multiple containers from multiple vendors.

WARs are simply Java archives of a Web application with a different extension to differentiate them from commonly used JARs.

Before the Servlet 2.2 specifications, servlet deployment differed significantly between servlet containers -- also previously called servlet engines. The 2.2 specifications standardized deployment across containers, thus taking Java code portability one step further. We shall see the power of this later in this article, when we illustrate the creation of a single Web application that is then deployed on both Apache Tomcat and WebLogic Server without any modification or recompilation.

Web application directory structure

The Servlet 2.2 specifications define the directory structure of the files in a Web application. The top directory -- or root directory -- should be given the name of your Web application and will define that document root for your Web application. All files beneath this root can be served to the client except for files under the special directories META-INF and WEB-INF in the root directory. All private files -- such as servlet class files -- should be stored under the WEB-INF directory.

The directory structure of your Web application should look something like that shown in Figure 1.

Figure 1. Web application directory structure

To create a Web application, begin by creating this directory structure. Take your compiled servlet classes and place them in the WEB-INF/classes directory. If you have defined your servlet to belong in a package, you must follow the standard Java rules and create the appropriate subdirectories so the JVM will be able to find your classes. For example, if your servlet is defined in a package com.mycompany.myproject, you should create the following directory structure:

  .../WEB-INF
      |-- classes
          |-- com
              |-- mycompany
                  |-- myproject

Place your Java classes in the myproject subdirectory.

A useful alternative to copying the class files into the appropriate directory is to configure your build environment (a Makefile or IDE) to save the compiled class files directly in the required directories. Doing so thereby eliminates that step during development.

1 2 3 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more