Sun Java System Web Server 6.1 SP6 Programmer's Guide to Web Applications

Creating Servlets

To create a servlet, perform the following tasks:

The rest of this section discusses the following topics:

Creating the Class Declaration

To create a servlet, write a public Java class that includes basic I/O support as well as the package javax.servlet. The class must extend either GenericServlet or HttpServlet. Since Sun Java System Web Server servlets exist in an HTTP environment, the latter class is recommended. If the servlet is part of a package, you must also declare the package name so the class loader can properly locate it.

The following example header shows the HTTP servlet declaration called myServlet:


import java.io.*;
     import javax.servlet.*;
     import javax.servlet.http.*;

     public class myServlet extends HttpServlet {
        ...servlet methods...
     }

Overriding Methods

Override one or more methods to provide servlet instructions to perform its intended task. A servlet does all the processing on a request-by-request basis and happens in the service methods, either service() for generic servlets or one of the do Operation() methods for HTTP servlets. This method accepts incoming requests, processes them according to the instructions you provide, and directs the output appropriately. You can create other methods in a servlet as well.

Overriding Initialize

Override the class initializer init() to initialize or allocate resources for the servlet instance's life, such as a counter. The init() method runs after the servlet is instantiated but before it accepts any requests. For more information, see the servlet API specification.


Note –

All init() methods must call super.init(ServletConfig) to set their scope. This makes the servlet's configuration object available to other servlet methods. If this call is omitted, a 500 SC_INTERNAL_SERVER_ERROR displays in the browser when the servlet starts up.


The following example of the init() method initializes a counter by creating a public integer variable called thisMany:


public class myServlet extends HttpServlet {
        int thisMany;
public void init (ServletConfig config) throws ServletException
        {
           super.init(config);
           thisMany = 0;
       }
       }

Now other servlet methods can access the variable.

Overriding Destroy

Override the class destructor destroy() to write log messages or to release resources that have been opened in the servlet's life cycle. Resources should be appropriately closed and dereferenced so that they are recycled or garbage collected. The destroy() method runs just before the servlet itself is deallocated from memory. For more information, see the servlet API specification.

Based on the example for Overriding Initialize, the destroy() method could write a log message like the following:


out.println("myServlet was accessed " + thisMany " times.\n");

         

Overriding Service, Get, and Post

When a request is made, the Sun Java System Web Server hands the incoming data to the servlet engine to process the request. The request includes form data, cookies, session information, and URL name-value pairs, all in a type HttpServletRequest object called the request object. Client metadata is encapsulated as a type HttpServletResponse object called the response object. The servlet engine passes both objects as the servlet's service() method parameters.

The default service() method in an HTTP servlet routes the request to another method based on the HTTP transfer method (POST, GET, and so on). For example, HTTP POST requests are routed to the doPost() method, HTTP GET requests are routed to the doGet() method, and so on. This enables the servlet to perform different request data processing depending on the transfer method. Since the routing takes place in service(), there is no need to generally override service() in an HTTP servlet. Instead, override doGet(), doPost(), and so on, depending on the expected request type.

The automatic routing in an HTTP servlet is based simply on a call to request.getMethod(), which provides the HTTP transfer method. In a Sun Java System Web Server, request data is already preprocessed into a name-value list by the time the servlet sees the data, so simply overriding the service() method in an HTTP servlet does not lose any functionality. However, this does make the servlet less portable, since it is now dependent on preprocessed request data.

Override the service() method (for generic servlets) or the doGet() or doPost() methods (for HTTP servlets) to perform tasks needed to answer the request. Very often, this means collating the needed information (in the request object or in a JDBC result set object), and then passing the newly generated content to a JSP for formatting and delivery back to the client.

Most operations that involve forms use either a GET or a POST operation, so for most servlets you override either doGet() or doPost(). Implement both methods to provide for both input types or simply pass the request object to a central processing method, as shown in the following example:


public void doGet (HttpServletRequest request,
                  HttpServletResponse response)
         throws ServletException, IOException {
   doPost(request, response);
}

All request-by-request traffic in an HTTP servlet is handled in the appropriate doOperation() method, including session management, user authentication, JSPs, and accessing Sun Java System Web Server features.

If a servlet intends to call the RequestDispatcher method include() or forward(), be aware the request information is no longer sent as HTTP POST, GET, and so on. In other words, if a servlet overrides doPost(), it may not process anything if another servlet calls it, if the calling servlet happens to receive its data through HTTP GET. For this reason, be sure to implement routines for all possible input types, as explained above. RequestDispatcher methods always call service().

For more information, see Calling a Servlet Programmatically.


Note –

Arbitrary binary data, such as uploaded files or images, can be problematic, because the web connector translates incoming data into name-value pairs by default. You can program the web connector to properly handle these kinds of data and package them correctly in the request object.


Accessing Parameters and Storing Data

Incoming data is encapsulated in a request object. For HTTP servlets, the request object type is HttpServletRequest. For generic servlets, the request object type is ServletRequest. The request object contains all request parameters, including your own request values called attributes.

To access all incoming request parameters, use the getParameter() method. For example:


String username = request.getParameter("username");

         

Set and retrieve values in a request object using setAttribute() and getAttribute(), respectively. For example:


request.setAttribute("favoriteDwarf", "Dwalin");

         

Handling Sessions and Security

From a web server's perspective, a web application is a series of unrelated server hits. There is no automatic recognition if a user has visited the site before, even if their last interaction was seconds before. A session provides a context between multiple user interactions by remembering the application state. Clients identify themselves during each interaction by a cookie, or, in the case of a cookie-less browser, by placing the session identifier in the URL.

A session object can store objects, such as tabular data, information about the application's current state, and information about the current user. Objects bound to a session are available to other components that use the same session.

For more information, see Chapter 5, Session Managers.

After a successful login, you should direct a servlet to establish the user's identity in a standard object called a session object. This object holds information about the current session, including the user's login name and any additional information to retain. Application components can then query the session object to obtain user authentication.

For more information about providing a secure user session for your application, see Chapter 6, Securing Web Applications.

Handling Threading Issues

By default, servlets are not thread-safe. The methods in a single servlet instance are usually executed numerous times simultaneously (up to the available memory limit). Each execution occurs in a different thread, though only one servlet copy exists in the servlet engine.

This is efficient system resource usage, but is dangerous because of the way Java manages memory. Because variables belonging to the servlet class are passed by reference, different threads can overwrite the same memory space as a side effect. To make a servlet (or a block within a servlet) thread-safe, do one of the following:


 import java.io.*;
   import javax.servlet.*;
   import javax.servlet.http.*;

   public class myServlet extends HttpServlet {

   public void doGet (HttpServletRequest request,
                     HttpServletResponse response)
            throws ServletException, IOException {
      //pre-processing
       synchronized (this) {
         //code in this block is thread-safe
      }
      //other processing;
      }

    public synchronized int mySafeMethod (HttpServletRequest request)
      {
      //everything that happens in this method is thread-safe
      }
   }

         

import java.io.*;
   import javax.servlet.*;
   import javax.servlet.http.*;

   public class myServlet extends HttpServlet
       implements SingleThreadModel {
      servlet methods...
   }

         

Note –

If a servlet is specifically written as a single thread, the servlet engine creates a pool of servlet instances to be used for incoming requests. If a request arrives when all instances are busy, it is queued until an instance becomes available. The number of pool instances is configurable in the sun-web.xml file, in the singleThreadedServletPoolSize property of the sun-web-app element.


Delivering Client Results

The final user interaction activity is to provide a response page to the client. The response page can be delivered in two ways, as described in the following topics:

Creating a Servlet Response Page

Generate the output page within a servlet by writing to the output stream. The recommended way to do this depends on the output type.

Always specify the output MIME type using setContentType() before any output commences, as in this example:


response.setContentType("text/html");

            

For textual output, such as plain HTML, create a PrintWriter object and then write to it using println. For example:


PrintWriter output = response.getWriter();
output.println("Hello, World\n");

            

For binary output, write to the output stream directly by creating a ServletOutputStream object and then write to it using print(). For example:


ServletOutputStream output = response.getOutputStream();
output.print(binary_data);

            

Creating a JSP Response Page

Servlets can invoke JSPs in two ways, the include() method and the forward() method:


RequestDispatcher dispatcher =
       getServletContext().getRequestDispatcher("JSP_URI");
 dispatcher.include(request, response);
   ... //processing continues

            

Note –

You cannot use the forward() method if you have already defined a PrintWriter or ServletOutputStream object.


This example shows a JSP using forward():


RequestDispatcher dispatcher =
       getServletContext().getRequestDispatcher("JSP_URI");
 dispatcher.forward(request, response);

            

Note –

Identify which JSP to call by specifying a Universal Resource Identifier (URI). The path is a String describing a path within the ServletContext scope. There is also a getRequestDispatcher() method in the request object that takes a String argument indicating a complete path. For more information about this method, see the Java Servlet 2.3 specification, section 8.


For more information about JSPs, see Chapter 4, Using JavaServer Pages.