Java Servlets

An introduction to writing and running Java servlets on Linux.
Writing Servlets

The Servlet interface provides the foundation for all servlets. All servlets must either implement this interface or be extensions of a class which implements it. The Servlet package provides a class called HttpServlet which implements the Servlet interface, so as a servlet developer, much of the work is done for you. The Servlet interface allows the creation of generic servlets, but we will only look at how to create servlets that act as CGI scripts. For this, all you have to worry about is the HttpServlet class.

Listing 1.

Let's step through the code of the simple servlet shown in Listing 1 to see how it works. This servlet overrides the doGet method provided by the HttpServlet class. doGet is called when a client makes a GET request to the servlet. Here we have the servlet respond with a simple web page that gives the standard “Hello World” message. The doGet method gets two objects, HttpServletRequest and HttpServletResponse, which encapsulate information that allows the servlet to obtain information from and communicate with the client. For example, the HttpServletResponse object contains a PrintWriter object that can be used to send information back to the client. In this example, we use it to send our “Hello World” message back to the client. We also use the setContentType method of the HttpServletResponse object to inform the client that it will be receiving text/HTML data from the servlet.

Now that we've seen a simple example, let's step back a bit and look at how HTTP Servlets work. Servlets extending the HttpServlet class handle all of their client requests through its service method. The service method understands standard HTTP requests, and calls appropriate methods to handle each request. In the example above, the service would recognize the GET request and call the doGet method accordingly. Similarly, doPost, doPut and doDelete methods are provided to handle other types of HTTP requests.

The Life Cycle of a Servlet

A servlet's life begins when the servlet's init method is called. The web server calls the init method when it loads the servlet, but before any client requests are handled. The init method is called only once when the servlet is loaded. So, if you need to perform any initialization before your servlet starts handling requests, overload the init method as follows:

public void init(ServletConfig config) throws ServletException {
                super.init(config);

                ...
        }

The init method is passed an object which contains configuration information about the servlet. It is a good idea to store this object to make it available if the client needs it. The easiest way to do this is to call the init method of superclass and pass the ServletConfig object to it. One final tip regarding the initialization of servlets: if your initialization fails and the servlet can't handle client requests, throw an UnavailableException. After initialization takes place, the servlet is up and the service method handles client requests.

Finally, when the servlet is unloaded from the web server, its destroy method is called. The web server waits until all service methods are finished or a certain number of seconds have passed (whichever comes first) before calling the destroy method. In the case of long-running service methods, it is possible the destroy method will be called before all service calls have been completed.

This situation can be handled with a few additional methods and variables. First, create a variable that keeps track of how many service methods have been called and provide synchronized methods for increasing and decreasing the counter, as well as one to return the value of your service counter.

public MyServlet extends HttpServlet {
   private int numServices = 0;
   protected synchronized void enterService() {
   numServices++;
   }
   protected synchronized void exitService() {
   numServices-;
   }
   protected synchronized int serviceCount() {
   return numServices;
   }
}

Now, that we have these counters, we need to modify the service method to increment and decrement them accordingly. This is done by adding a call to the enterService method at the top of the service method, calling the service method of the superclass to handle the real work and then decrementing the counter by calling the exitService method.

protected void service(HttpServletRequest req, HttpServletResponse
resp)
   throws ServletException, IOException
   {
   enterService();
   try {
   super.service(req, resp);
   } finally {
   exitService();
   }
   }
Next, a flag is needed to determine if the servlet is in the process of shutting down. To accompany this flag, use accessor methods to set the flag and return its value.
MyServlet continued {
   private Boolean exiting;
   protected setExiting(Boolean flag) {
     exiting = flag;
   }
   protected Boolean isExiting() {
      return exiting;
   }
}
Now the destroy method should first check if any services haven't completed, then loop until all services are finished.
public void destroy() {
   if (serviceCount() > 0) {
      setShuttingDown(true);
   }
   while(serviceCount() > 0) {
      try {
      Thread.sleep(interval);
      } catch (InterruptedException e) {
      }
   }
}
Finally, modify any of your methods that may run for a long time to check if the servlet is shutting down, and act accordingly.
public void doPost(...) {
  /* You could do something like this or put
   * the check into a loop
   * that takes a long time */
   if(!isExiting) {
   ...
   }
}
So there you have it: a quick introduction to getting servlets up and running on your Linux box and writing some simple ones. If you want to learn more about writing servlets, books are available which cover them in depth. I would also recommend looking at the Java Tutorial, available on Sun's web site; it contains a nice introduction to servlets I used when I started learning about them.

Resources

Doug Welzel recently finished up his undergraduate work at Carnegie Mellon University and is continuing his graduate studies. He has been using Linux throughout his career at CMU and welcomes your comments at welzel@andrew.cmu.edu.

______________________

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState