The Java Servlet Architecture

 < Day Day Up > 



A Java servlet is a platform-independent Web application component that is hosted in a JSP/servlet container. Servlets cooperate with Web clients by means of a request/response model managed by a JSP/servlet container. Figure 2.1 depicts the execution of a Java servlet.

click to expand
Figure 2.1: The execution of a Java servlet.

Two packages make up the servlet architecture: javax.servlet and javax.servlet.http. The first of these, the javax.servlet package, contains the generic interfaces and classes that are implemented and extended by all servlets. The second, the javax.servlet.http package, contains all servlet classes that are HTTP protocol specific. An example of this would be a simple servlet that responds using HTML.

At the heart of this architecture is the interface javax.servlet.Servlet. It is the base class interface for all servlets. The Servlet interface defines five methods. The three most important of these methods are:

  • the init() method, which initializes a servlet

  • the service() method, which receives and responds to client requests

  • the destroy() method, which performs cleanup

These are the servlet lifecycle methods. We describe these methods in a subsequent section. All servlets must implement the Servlet interface, either directly or through inheritance. Figure 2.2 is an object model that gives you a very high-level view of the servlet framework.

click to expand
Figure 2.2: A simple object model showing the servlet framework.

The GenericServlet and HttpServlet Classes

The two main classes in the servlet architecture are the GenericServlet and HttpServlet classes. The HttpServlet class is extended from GenericServlet, which in turn implements the Servlet interface. When developing your own servlets, you will most likely extend one of these two classes.

When extending the GenericServlet class, you must implement the service() method. The GenericServlet.service() method has been defined as an abstract method in order to force you to follow this framework. The service() method prototype is defined as follows:

 public abstract void service(ServletRequest request,   ServletResponse response) throws ServletException, IOException; 

The two parameters that are passed to the service() method are ServletRequest and ServletResponse objects. The ServletRequest object holds the information that is being sent to the servlet, and the ServletResponse object is where you place the data you want to send back to the client.

In contrast to the GenericServlet, when you extend HttpServlet you don't usually implement the service() method; the HttpServlet class has already implemented the service() method for you. The following prototype contains the HttpServlet.service() method signature:

 protected void service(HttpServletRequest request,   HttpServletResponse response)   throws ServletException, IOException; 

When the HttpServlet.service() method is invoked, it reads the method type stored in the request and determines which HTTP-specific methods to invoke based on this value. These are the methods that you will want to override. If the method type is GET, it will call doGet(). If the method type is POST, it will call doPost(). Five other method types are associated with the service() method, but the doGet() and doPost() methods are the methods used most often and are therefore the methods that we focus on.

The Lifecycle of a Servlet

The lifecycle of a Java servlet follows a very logical sequence. The interface that declares the life-cycle methods is the javax.servlet.Servlet interface. These methods are the init(), the service(), and the destroy() methods. This sequence can be described in a simple three-step process:

  1. A servlet is loaded and initialized using the init() method. This method is called when a servlet is preloaded or upon the first request to this servlet.

  2. The servlet then services zero or more requests. The servlet services each request using the service() method.

  3. The servlet is then destroyed and garbage-collected when the Web application containing the servlet shuts down. The method that is called upon shutdown is the destroy() method.

The init() Method

The init() method is where the servlet begins its life. This method is called immediately after the servlet is instantiated and is called only once. The init() method should be used to create and initialize the resources that it will be using while handling requests. The init() method's signature is defined as follows:

 public void init(ServletConfig config) throws ServletException; 

The init() method takes a ServletConfig object as a parameter. This reference should be stored in a member variable so that it can be used later. A common way of doing this is to have the init() method call super.init() and pass it the ServletConfig object.

The init() method also declares that it can throw a ServletException. If for some reason the servlet cannot initialize the resources necessary to handle requests, it should throw a ServletException with an error message signifying the problem.

The service() Method

The service() method services all requests received from a client using a simple request/response pattern. The service() method's signature is shown here:

 public void service(ServletRequest req, ServletResponse res)   throws ServletException, IOException; 

The service() method takes two parameters:

  • A ServletRequest object, which contains information about the service request and encapsulates information provided by the client

  • A ServletResponse object, which contains the information returned to the client

You will not usually implement this method directly, unless you extend the GenericServlet abstract class. The most common implementation of the service() method is in the HttpServlet class. The HttpServlet class implements the Servlet interface by extending GenericServlet. Its service() method supports standard HTTP/1.1 requests by determining the request type and calling the appropriate method.

The destroy() Method

This method signifies the end of a servlet's life. When a Web application is shut down, the servlet's destroy() method is called. This is where all resources that were created in the init() method should be cleaned up. The following code snippet shows the signature of the destroy() method:

 public void destroy(); 

Building a Servlet

Now that we have a basic understanding of what a servlet is and how it works, let's build a very simple servlet of our own. Its purpose will be to service a request and respond by outputting the address of the client. After we have examined the source for this servlet, we will take a look at the steps involved in compiling and installing it. Listing 2.1 contains the source code for this example.

Listing 2.1: SimpleServlet.java.

start example
 package chapter2; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class SimpleServlet extends HttpServlet {   public void init(ServletConfig config)     throws ServletException {     // Always pass the ServletConfig object to the super class     super.init(config);   }   //Process the HTTP Get request   public void doGet(HttpServletRequest request,     HttpServletResponse response)     throws ServletException, IOException {     doPost(request, response);   }   //Process the HTTP Post request   public void doPost(HttpServletRequest request,     HttpServletResponse response)     throws ServletException, IOException {     response.setContentType("text/html");     PrintWriter out = response.getWriter();     out.println("<html>");     out.println("<head><title>Simple Servlet</title></head>");     out.println("<body>");     // Outputs the address of the calling client     out.println("Your address is " + request.getRemoteAddr()       + "\n");     out.println("</body></html>");     out.close();   } } 
end example

Now that you have had a chance to look over the source of the SimpleServlet, let's take a closer look at each of its integral parts. We examine where the servlet fits into the Java Servlet Development Kit (JSDK) framework, the methods that the servlet implements, and the objects being used by the servlet. The following three methods are overridden in the SimpleServlet:

  • init()

  • doGet()

  • doPost()

Let's take a look at each of these methods in more detail.

The init() Method

The SimpleServlet first defines a straightforward implementation of the init() method. It takes the ServletConfig object that it is passed and then passes it to its parent's init() method, which stores the object for later use. The code that performs this action is as follows:

 super.init(config); 

start sidebar

The SimpleServlet's parent that actually holds on to the ServletConfig object is the GenericServlet.

end sidebar

You should also notice that this implementation of the init() method does not create any resources. This is why the SimpleServlet does not implement a destroy() method.

The doGet() and doPost() Methods

The SimpleServlet's doGet() and doPost() methods are where all of the business logic is truly performed, and in this case, the doGet() method simply calls the doPost() method. The only time that the doGet() method is executed is when a GET request is sent to the container. If a POST request is received, then the doPost() method services the request.

Both the doGet() and the doPost() methods receive HttpServletRequest and HttpServletResponse objects as parameters. The HttpServletRequest contains information sent from the client, and the HttpServletResponse contains the information that will be sent back to the client.

The first executed line of the doPost() method sets the content type of the response that will be sent back to the client. This is done using the following code snippet:

 response.setContentType("text/html"); 

This method sets the content type for the response. You can set this response property only once, and it must be set prior to writing to a Writer or an OutputStream. In our example, we are setting the response type to text/html.

The next thing we do is get a PrintWriter. This is accomplished by calling the ServletResponse's getWriter() method. The PrintWriter will let us write to the stream that will be sent in the client response. Everything written to the PrintWriter will be displayed in the client browser. This step is completed in the following line of code:

 PrintWriter out = response.getWriter(); 

Once we have a reference to an object that will allow us to write text back to the client, we use this object to write a message to the client. This message will include the HTML that will format this response for presentation in the client's browser. The next few lines of code show how this is done:

 out.println("<html>"); out.println("<head><title>Simple Servlet</title></head>"); out.println("<body>"); // Outputs the address of the calling client out.println("Your address is " + request.getRemoteAddr()   + "\n"); 

The SimpleServlet uses a very clear-cut method of sending HTML to a client. It simply passes to the PrintWriter's println() method the HTML text we want included in the response and closes the stream. The only question you may have involves these few lines:

 // Outputs the address of the calling client out.println("Your address is " + request.getRemoteAddr()   + "\n"); 

This section of code takes advantage of information sent by the client. It calls the HttpServletRequest's getRemoteAddr() method, which returns the IP address of the calling client. The HttpServletRequest object holds a great deal of HTTP protocol-specific information about the client. If you would like to learn more about the HttpServletRequest or HttpServletResponse objects, you can find additional information at the Sun Web site:

  • http://java.sun.com/products/servlet/

Building and Deploying a Servlet

To see the SimpleServlet in action, you need to first create a Web application that will host the servlet, and then you need to compile and deploy this servlet to the Web application. These steps are described below:

  1. Create a Web application named ch02app, using the directory structure described in Chapter 1.

  2. Add the servlet.jar file to your classpath. This file should be in the <CATALINA_HOME>/ common/lib/ directory.

  3. Compile the source for the SimpleServlet.

  4. Copy the resulting class file to the <CATALINA_HOME>/webapps/ch02app/WEB-INF/classes/chapter2 directory.

  5. Add the following Servlet definition to the web.xml file. This definition causes the SimpleServlet to be invoked when the requested URL contains the pattern simple.

 <servlet>   <servlet-name>SimpleServlet</servlet-name>   <servlet-class>chapter2.SimpleServlet</servlet-class> </servlet> <servlet-mapping>   <servlet-name>SimpleServlet</servlet-name>   <url-pattern>simple</url-pattern> </servlet-mapping> 

Once you have completed these steps, you can execute the SimpleServlet and see the results. To do this, start Tomcat and open your browser to the following URL:

  • http://localhost:8080/ch02app/simple

You should see an image similar to Figure 2.3.

click to expand
Figure 2.3: The output of the SimpleServlet.

The ServletContext

A ServletContext is an object that is defined in the javax.servlet package. It defines a set of methods that are used by server-side components of a Web application to communicate with the servlet container.

The ServletContext is most frequently used as a storage area for objects that need to be available to all of the server-side components in a Web application. You can think of the ServletContext as a shared memory segment for Web applications. When an object is placed in the ServletContext, it exists for the life of a Web application, unless it is explicitly removed or replaced. Four methods defined by the ServletContext are leveraged to provide this shared memory functionality. Table 2.1 describes each of these methods.

Table 2.1: The Shared Memory Methods of the ServletContext

Method

Description

setAttribute()

Binds an object to a given name and stores the object in the current ServletContext. If the name specified is already in use, this method removes the old object binding and binds the name to the new object.

getAttribute()

Returns the object referenced by the given name, or returns null if there is no attribute bind to the given key.

removeAttribute()

Removes the attribute with the given name from the ServletContext.

getAttributeNames()

Returns an enumeration of strings containing the object names stored in the current ServletContext.

The Relationship between a Web Application and the ServletContext

The ServletContext acts as the container for a given Web application. For every Web application, there can be only one instance of a ServletContext. This relationship is required by the Java Servlet Specification and is enforced by all servlet containers.

To see how this relationship affects Web components, let's use a servlet and a JSP. The first Web component we look at is a servlet that stores an object in the ServletContext, with the purpose of making this object available to all server-side components in this Web application. Listing 2.2 shows the source code for this servlet.

Listing 2.2: ContextServlet.java.

start example
 package chapter2; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class ContextServlet extends HttpServlet {   private static final String CONTENT_TYPE = "text/html";   public void doGet(HttpServletRequest request,     HttpServletResponse response)     throws ServletException, IOException {     doPost(request, response);   }   public void doPost(HttpServletRequest request,     HttpServletResponse response)     throws ServletException, IOException {     // Get a reference to the ServletContext     ServletContext context = getServletContext();     // Get the userName attribute from the ServletContext     String userName = (String)context.getAttribute("USERNAME");     // If there was no attribute USERNAME, then create     // one and add it to the ServletContext     if ( userName == null ) {       userName = new String("Bob Roberts");       context.setAttribute("USERNAME", userName);     }     response.setContentType(CONTENT_TYPE);     PrintWriter out = response.getWriter();     out.println("<html>");     out.println("<head><title>Context Servlet</title></head>");     out.println("<body>");     // Output the current value of the attribute USERNAME     out.println("<p>The current User is : " + userName +       ".</p>");     out.println("</body></html>");   }   public void destroy() {   } } 
end example

As you look over the ContextServlet, you notice that it performs the following steps:

  1. It first gets a reference to the ServletContext, using the getServletContext() method:

              ServletContext context = getServletContext(); 

  2. Once it has a reference to the ServletContext, it gets a reference to the object bound to the name USERNAME from the ServletContext, using the getAttribute() method:

              String userName =            (String)context.getAttribute("USERNAME"); 

  3. It then checks to see if the reference returned was valid. If getAttribute() returned null, then there was no object bound to the name USERNAME. If the attribute is not found, it is created and added to the ServletContext, bound to the name USERNAME, using the setAttribute() method:

               // If there was no attribute USERNAME, then create           // one and add it to the ServletContext           if ( userName == null ) {             userName = new String("Bob Roberts");             context.setAttribute("USERNAME", userName);           } 

  4. The value of this reference is then printed to the output stream, using an instance of the PrintWriter.println() method:

               // Output the current value of the attribute USERNAME           out.println("<p>The current User is : " +             userName + ".</p>"); 

After you have looked over this servlet, complete these steps:

  1. Compile the source for the SimpleServlet.

  2. Copy the resulting class file to the <CATALINA_HOME>/webapps/ch02app/WEB-INF/classes/chapter2 directory.

  3. Add the following Servlet definition to the web.xml file:

     <servlet>   <servlet-name>ContextServlet</servlet-name>   <servlet-class>chapter2.ContextServlet </servlet-class> </servlet> <servlet-mapping>   <servlet-name>ContextServlet</servlet-name>   <url-pattern>context</url-pattern> </servlet-mapping> 

The JSP that we will be using is much like the servlet above; however, there are two differences:

  • The code to access the ServletContext is in a JSP scriptlet, which we discuss later in this chapter.

  • If the JSP cannot find a reference to the USERNAME attribute, then it does not add a new one.

Otherwise, the code performs essentially the same actions, but it does them in a JSP. You can see the source for the JSP in Listing 2.3.

Listing 2.3: Context.jsp.

start example
 <HTML> <HEAD> <TITLE> Context </TITLE> </HEAD> <BODY> <%   // Try to get the USERNAME attribute from the ServletContext   String userName = (String)application.getAttribute("USERNAME");   // If there was no attribute USERNAME, then create   // one and add it to the ServletContext   if ( userName == null ) {     // Don't try to add it just, say that you can't find it     out.println("<b>Attribute USERNAME not found");   }   else {     out.println("<b>The current User is : " + userName +       "</b>");   } %> </BODY> </HTML> 
end example

start sidebar

In Context.jsp, we are using two JSP implicit objects: the application object, which references the ServletContext, and the out object, which references an output stream to the client. We discuss each of these later in this chapter.

end sidebar

Now, copy Context.jsp to the <CATALINA_HOME>/webapps/ch02app/ directory, restart Tomcat, and open your browser first to the following URL:

  • http://localhost:8080/ch02app/Context.jsp

You should see a page similar to Figure 2.4.

click to expand
Figure 2.4: The output of the Context.jsp prior to the execution of the servlet ContextServlet.

As you can see, the Context.jsp cannot find a reference to the attribute USERNAME. It will not be able to find this reference until the reference is placed there by the ContextServlet. To do this, open your browser to the following URL:

  • http://localhost:8080/ch02app/context

You should see output similar to Figure 2.5.

click to expand
Figure 2.5: The output of the ContextServlet.

After running this servlet, the ch02app Web application has an object bound to the name USERNAME stored in its ServletContext. To see how this affects another Web component in the ch02app Web application, open the previous URL that references the Context.jsp and look at the change in output. The JSP can now find the USERNAME, and it prints this value to the response.

start sidebar

To remove an object from the ServletContext, you can restart the JSP/servlet container or use the ServletContext.removeAttribute() method.

end sidebar

Using Servlets to Retrieve HTTP Data

In this (our final) section on servlets, we are going to examine how servlets can be used to retrieve information from the client. Three methods can be used to retrieve request parameters: the ServletRequest's getParameter(), getParameterValues(), and getParameterNames() methods. Each method signature is listed here:

 public String ServletRequest.getParameter(String name); public String[] ServletRequest.getParameterValues(String name); public Enumeration ServletRequest.getParameterNames (); 

The first method in this list, getParameter(), returns a string containing the single value of the named parameter, or returns null if the parameter is not in the request. You should use this method only if you are sure the request contains only one value for the parameter. If the parameter has multiple values, you should use the getParameterValues() method.

The next method, getParameterValues(), returns the values of the specified parameter as an array of java.lang.Strings, or returns null if the named parameter is not in the request.

The last method, getParameterNames(), returns the parameter names contained in the request as an enumeration of strings, or an empty enumeration if there are no parameters. This method is used as a supporting method to both getParameter() and getParameterValues(). The enumerated list of parameter names returned from this method can be iterated over by calling getParameter() or getParameterValues() with each name in the list.

To see how you can use these methods to retrieve form data, let's look at a servlet that services POST requests: it retrieves the parameters sent to it and returns the parameters and their values back to the client. The servlet is shown in Listing 2.4.

Listing 2.4: ParameterServlet.java.

start example
 package chapter2; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class ParameterServlet extends HttpServlet {   // Process the HTTP GET request   public void doGet(HttpServletRequest request,     HttpServletResponse response)     throws ServletException, IOException {     doPost(request, response);   }   // Process the HTTP POST request   public void doPost(HttpServletRequest request,     HttpServletResponse response)     throws ServletException, IOException {     response.setContentType("text/html");     PrintWriter out = response.getWriter();     out.println("<html>");     out.println("<head>");     out.println("<title>Parameter Servlet</title>");     out.println("</head>");     out.println("<body>");     // Get an enumeration of the parameter names     Enumeration parameters = request.getParameterNames();     String param = null;     // Iterate over the paramter names,     // getting the parameters values     while ( parameters.hasMoreElements() ) {       param = (String)parameters.nextElement();       out.println(param + " : " +         request.getParameter(param) +         "<BR>");     }     out.println("</body></html>");     out.close();   } } 
end example

The first notable action performed by this servlet is to get all of the parameter names passed in on the request. It does this using the getParameterNames() method. Once it has this list, it performs a while loop, retrieving and printing all of the parameter values associated with the matching parameter names, using the getParameter() method. You can invoke the ParameterServlet by encoding a URL string, with parameters and values, or simply by using the HTML form found in Listing 2.5.

Listing 2.5: Form.html.

start example
 <HTML> <HEAD> <TITLE> Parameter Servlet Form </TITLE> </HEAD> <BODY> <form  action="parameter"  method=POST>   <table width="400" border="0" cellspacing="0">     <tr>       <td>Name: </td>       <td>         <input type="text"                name="name"                size="20"                maxlength="20">       </td>       <td>SSN:</td>       <td>         <input type="text" name="ssn" size="11" maxlength="11">       </td>     </tr>     <tr>       <td>Age:</td>       <td>         <input type="text" name="age" size="3" maxlength="3">       </td>       <td>email:</td>       <td>         <input type="text"                name="email"                size="30"                maxlength="30">       </td>     </tr>     <tr>       <td>&nbsp;</td>       <td>&nbsp; </td>       <td>&nbsp; </td>       <td>         <input type="submit" name="Submit" value="Submit">         <input type="reset" name="Reset" value="Reset">       </td>     </tr>   </table> </FORM> </BODY> </HTML> 
end example

This HTML document contains a simple HTML form that can be used to pass data to the ParameterServlet. To see this example in action, complete the following steps:

  1. Compile the source for the ParameterServlet.

  2. Copy the resulting class file to the <CATALINA_HOME>/webapps/ch02app/WEB-INF/classes/chapter2 directory.

  3. Add the following Servlet definition to the web.xml file:

     <servlet>   <servlet-name>ParameterServlet</servlet-name>   <servlet-class>chapter2.ParameterServlet </servlet-class> </servlet> <servlet-mapping>   <servlet-name>ParameterServlet</servlet-name>   <url-pattern>parameter</url-pattern> </servlet-mapping> 

  4. Copy the Form.html file to the <CATALINA_HOME>/webapps/ch02app/ directory.

    Now open your browser to the following URL:

    • http://localhost:8080/ch02app/Form.html

    Go ahead and populate the form (similar to what we've done in Figure 2.6), and then click the Submit button. The response you receive will, of course, depend on your entries, but it should resemble Figure 2.7.

    click to expand
    Figure 2.6: Output from Form.html.

    click to expand
    Figure 2.7: The response of the ParameterServlet.

start sidebar

This example shows just how easy it is to retrieve request parameters in a servlet. While the ParameterServlet works well for most requests, it does contain an error. When we chose to use getParameter() to retrieve the parameter values, we were counting on receiving only one value per request parameter. If we could not rely on this fact, then we should have used the getParameterValues() method discussed earlier.

end sidebar



 < Day Day Up > 



Professional Jakarta Struts
Professional Jakarta Struts (Programmer to Programmer)
ISBN: 0764544373
EAN: 2147483647
Year: 2003
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net