Pearson IT Certification

The Servlet Container

By and

Date: May 2, 2003

Return to the article

If you're cramming for the J2EE Web Component Developer exam, this chapter will give you everything you need to know about the servlet container.

Terms you'll need to understand:

Techniques you'll need to master:

Context Architecture

You can see how Tomcat employs an architecture that implements Sun's specifications carefully. It is hard to understand context, though, if you don't know the overall architecture.

TIP

When you see the word application on the exam, think context. So, the application-initialization parameters are really those defined in the deployment descriptor with the context-param element and retrieved with ServletContext.getInitParameters.

A nice snapshot of the architecture is seen in Tomcat's primary configuration file server.xml (CATALINA_HOME\conf\server.xml). Other vendor containers also use configuration schemes, so if you aren't using Tomcat to study for the exam, look at your product's configuration files. The component elements shown in this chapter are nested corresponding to their parent-child relationships with each other. Descriptive comments are edits from comments in the sample server.xml file (ships with Tomcat). This file is not on the exam, but the architecture that Listing 3.1 defines helps give a big picture.

Listing 3.1 Sample Configuration Illustrates Architecture

<!--
A "Server" is a singleton element. It represents the
entire JVM. The server in turn may contain one or more "Service"
instances. The Server listens for a shutdown command 
on the indicated port. Notice: A "Server" is not 
itself a "Container".
 -->
<Server port="8005" shutdown="SHUTDOWN" debug="0">

<!-- 
A "Service" is a collection of one or more "Connectors"
that share a single "Container" (and therefore the web 
applications visible within that Container). Normally,
that Container is an "Engine". Notice: A "Service" is 
not itself a "Container".
-->

 <!-- Define the Tomcat Stand-Alone Service -->
 <Service name="Tomcat-Standalone">

<!-- A "Connector" represents an endpoint by which requests
are received and responses are returned. Each Connector 
passes requests on to the associated "Container" (normally
an Engine) for processing. By default, a non-SSL HTTP/1.1 
Connector is established on port 8080.

  <!-- non-SSL HTTP/1.1 Connector on port 8080 -->
  <Connector className=
   "org.apache.catalina.connector.http.HttpConnector"
   port="8080" minProcessors="5" maxProcessors="75"
   enableLookups="true" redirectPort="8443"
   acceptCount="10" debug="0" connectionTimeout="60000"/>

<!-- You can also define an SSL HTTP/1.1 Connector on port
8443, an AJP 1.3 Connector on port 8009, a Proxied HTTP/1.1 
Connector on port 8081, and non-SSL test connectors
on other ports such as 8082. -->


<!-- An Engine represents the entry point (within Catalina)
that processes every request. The Engine implementation 
for Tomcat stand alone analyzes the HTTP headers included 
with the request, and passes them on to the appropriate 
Host (virtual host). -->


   <!-- Define the default virtual host -->
   <Host name="localhost" debug="0" appBase="webapps"
    unpackWARs="true">


<!-- Logger shared by all Contexts related to this virtual 
host. By default (when using FileLogger), log files are 
created in the "logs" directory relative to $CATALINA_HOME.
If you wish, you can specify a different directory with the
"directory" attribute. Specify either a relative (to 
$CATALINA_HOME) or absolute path to the desired directory.
-->
    <Logger 
     className="org.apache.catalina.logger.FileLogger"
     directory="logs" prefix="localhost_log." 
     suffix=".txt" timestamp="true"/>

<!-- Define properties for each web application such as 
document roots in places other than the virtual host's 
appBase directory. -->

    <!-- Tomcat Examples Context -->
    <Context path="/examples" docBase="examples" debug="0"
         reloadable="true">
     <Logger className="org.apache.catalina.logger.FileLogger"
           prefix="localhost_examples_log." suffix=".txt"
    	 timestamp="true"/>
    </Context>
   </Host>
  </Engine>
 </Service>

TIP

The word context is really just a name that gets mapped to the document root of a Web application. For example, the context of the examples application is /examples. The request URL http://localhost:8080/examples/welcome.html retrieves the file welcome.html from CATALINA_HOME\webapps\examples\welcome.html.

Context-Initialization Parameters

The exam expects you to know the interface and methods to get context-initialization parameters. To understand these, remember that a Web application is a combination of JSP pages, servlets, tag libraries, JavaBeans, and other class files. The Java Virtual Machine creates a memory box for all of these called a ServletContext object that maintains information (context) about your Web application. You access the ServletContext for information about the application state. As the API states, the ServletContext grants you access to many types of information. You can get application-level initialization parameters. You can also set and get application attributes, as well as the major and minor version of the Servlet API that this servlet container supports. One very interesting capability refers to a RequestDispatcher object to forward requests to other application components within the server, or to include responses from certain components within the servlet and to log a message to the application log file. The ServletContext object enables you to set, get, and change application-level (not session-level) attributes and talk to the servlet container.

Context means application scope. The getInitParameter and getInitParameterNames methods retrieve context-wide, application-wide, or "Web application" parameters. The getInitParameter method returns a string containing the value of the parameter (you provide the name), or null if the parameter does not exist.

Some parameters have no information, so this method returns a string containing at least the servlet container name and version number. The getInitParameterNames method retrieves the names of the servlet's initialization parameters as an Enumeration of string objects. If there aren't any, it returns an empty Enumeration. Be careful; don't confuse this with session-wide attributes. The following snippet is how you might define a couple context-initialization parameters in the deployment descriptor:

<web-app>
  ...
  <context-param>
    <param-name>publisher</param-name>
    <param-value>QUE</param-value>
  </context-param>
  <context-param>
    <param-name>exam</param-name>
    <param-value>SCWCD</param-value>
  </context-param>
  ...
</web-app>

Refer to Chapter 2, "Deploying Web Applications," for more information about the deployment descriptor. Presently, realize that the context-param (with subelements param-name, param-value) declares the Web application's servlet context-initialization parameters for your application. You can access these parameters in your code using the javax.servlet.ServletContext.getInitParameter() and javax.servlet.ServletContext.getInitParameterNames() methods. Remember that the name specified in the param-name element must be unique in the Web application.

Given the previous deployment descriptor snippet, you would retrieve the two pairs of parameters with the following:

    // servlet configuration initialization parameters
    Enumeration params = 
        getServletConfig().getInitParameterNames();
    while (params.hasMoreElements()) 
    {
      String param = (String) params.nextElement();
      String value = 
        getServletConfig().getInitParameter(param);
      PrintWriter.println(param + "=" + value);
    }
//client would receive:
//publisher=QUE
//exam=SCWCD

Using Listeners

You also must know how to use the servlet context attribute listener and the session attribute listener. You can write code that responds to servlet events by defining listener objects. These objects have methods that the container invokes when life-cycle events occur. The event is triggered by a change in the application. For example, the session listener is invoked by the container when a session attribute changes. Also, this happens if an attribute in the application object changes and when the context or session is created and destroyed. You take advantage of this event model by defining a listener class that implements a listener interface. The container invokes the listener method and passes it information about that event. Notice that the methods in the HttpSessionListener interface are passed an HttpSessionEvent.

You can expect to see four listener interfaces on the exam. The following two tables describe them. Table 3.1 lists the context (Web application) events and the interface/method that your class must implement to respond to the event.

Table 3.1 Servlet Context Events

Event

Interface

Method

Servlet context has just been created

javax.servlet.ServletContextListener

contextInitialized()

Just before killing servlet context

ServletContextListener

contextDestroyed()

Adding an attribute

javax.servlet.ServletContextAttributesListener

attributeAdded()

Removing an attribute

ServletContextAttributesListener

attributeRemoved()

Replacing an attribute

ServletContextAttributesListener

attributeReplaced()


Table 3.2 lists the session events and the interface/method that your class must implement to respond to the event.

Table 3.2 Servlet Session Events

Event

Interface

Method

Session has just been created

javax.servlet.http sessionCreated()

HttpSessionListener

Just before passivating session

HttpSessionListener

sessionDestroyed()

Adding an attribute

javax.servlet.http.HttpSessionAttributesListener

attributeAdded()

Removing an attribute

HttpSessionAttributesListener

attributeRemoved()

Replacing an attribute

HttpSessionAttributesListener

attributeReplaced()


The following is a short commentary on the methods mentioned previously:

Obvious similarities exist between context and session interfaces and methods. Use javax.servlet.ServletContextAttributeListener when a context attribute is added, removed, or replaced. On the other hand, use HttpSessionAttributeListener when the same is done in a session. Both of these are public interfaces (they extend java.util.EventListener) and have the same method names but different parameters.

Suppose that you wanted to mark the times when your Web application started and ended. The following code snippet shows how you could use the initialization and destruction events to do that:

public final class ContextListener
  implements ServletContextListener 
{
  public void contextInitialized(
                ServletContextEvent event) 
  {
   ServletContext context = event.getServletContext();
   String IP = "209.83.3.142";
   context.setAttribute("DefaultAddress", IP);
  }
   
  public void contextDestroyed(ServletContextEvent event) 
  {
   ServletContext context = event.getServletContext();
   String IP = context.getAttribute("DefaultAddress");
   //do something with IP
   //context.removeAttribute("DefaultAddress");
  }
}

The attribute DefaultAddress is set when the container initializes the application. Of course, you could dynamically get the IP. Then when the application quits, the same attribute is retrieved. When you have this IP, you could log it and then delete it, for example. For an excellent article that provides an overview of application life-cycle events, see "Servlet App Event Listeners," by Stephanie Fesler (April 12, 2001, http://www.onjava.com/pub/a/onjava/2001/04/12/listeners.html).

For a better example, Listing 3.2 demonstrates a simplified approach to how you could listen to an application and record what is going on.

Listing 3.2 Listening to Context and Session Events

package com.companyname.listening;

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

/**
 * A custom listener for session events. 
 * All events that occur are monitored.
 */

public class MySessionListener
  implements HttpSessionListener, HttpSessionAttributeListener 
{
 private StringBuffer log = new StringBuffer("MySessionListener log\n");
  
 public void attributeAdded(HttpSessionBindingEvent event)
 {
   log.append(event.getName() + "," + event.getValue() +
        "," + new Date() + "\n");
 }

 public void attributeRemoved(HttpSessionBindingEvent event)
 {
   log.append(event.getName() + "," + event.getValue() +
        "," + new Date() + "\n");
 }

 public void attributeReplaced(HttpSessionBindingEvent event) 
 {
   log.append(event.getName() + "," + event.getValue() +
        "," + new Date() + "\n");
 }

 public void sessionCreated(HttpSessionEvent event) 
 {
   log.append("sessionCreated: " + new Date() + "\n");
 }

 public void sessionDestroyed(HttpSessionEvent event) 
 {
   HttpSession session = event.getSession();
   if (session!=null) 
   {
    log.append("Session Id:" + session.getId());
    log.append("Current Time: " + new Date());
    log.append("Created Time: " + 
          session.getCreationTime());
    log.append("Last Accessed: " + 
          session.getLastAccessedTime());
   }

   //permanently record the events; something like:      
   //myLogger.record( log.toString() );
 }
}

TIP

The listener architecture in servlets is based on the event model. The container automatically calls certain methods when an event occurs. For example, the container calls attributeRemoved in a servlet that implements HttpSessionAttributeListener when an attribute is removed from a session object.

Before you can listen to events, you must configure your Web application to have an event listener. Most containers have default listeners already configured, so most likely you don't have to change the configuration. However, you should understand the steps involved. You would edit the web.xml (located in the WEB-INF) deployment descriptor of the Web application for which you are creating an event listener; you would add the <listener> element. Among containers, the required order of top-level elements varies. I recommend placing the <listener> element directly after the <filter> and <filter-mapping> elements and before the <servlet> element. You can specify many listeners, and usually the container invokes the event listeners in the order in which they appear in the deployment descriptor. Conversely, most containers invoke these events in the reverse order during shutdown. The following snippet is an example of two listener declarations:

<listener>
 <listener-class>myContextListener</listener-class>
</listener>
<listener>
 <listener-class>
    mySessionAttributeListener
 </listener-class>
</listener>

Remember that the listener element indicates the deployment properties for a Web application listener bean. The listener-class element declares that a class in the application must be registered as a Web application listener bean. The value is the fully qualified class name of the listener class.

Context and Attributes within a Distributable

The behavior of these listeners in a distributable is exactly the same as the behavior of the listeners discussed in the previous section, with one notable exception: Event notification of addition, removal, or replacement affects the listener for only that context. No other context, even in the same JVM, knows about the listener events. However, some vendors do provide cross-context event capabilities.

The deployment descriptor contains the configuration for a Web application. The distributable element, by its presence in a Web application deployment descriptor, indicates that a given Web application is programmed appropriately to be deployed into a distributed servlet container. It is the only indication within the descriptor that the application is distributable. The syntax for the distributable element is shown in the following snippet:

<web-app> 
    <distributable /> 
</web-app>

When a Web application is marked as distributable, the servlet container may distribute the application to multiple JVMs. There are advantages for clustering, scalability, and failover. Because the context exists locally in the JVM (where created), the ServletContext object doesn't share memory space with other JVMs. Therefore, to manually share information between contexts, you should store this information externally in a DB or an EJB. Notice that the session is scoped to the service handling requests. However, the context is scoped to the Web container's JVM. Be careful—events and sessions are not propagated to other containers automatically. That is how you should answer any test questions about distributed applications. Vendors are free to improve on this, but answer according to how it works by default.

Practice Questions

Question 1

Read the following code snippet:

<listener>
 <listener-class>myContextListener
         </listener-class>
</listener>
<listener>
 <listener-class>
    mySessionAttributeListener
 </listener-class>
</listener>

Which two statements are true regarding this snippet? (Choose two.)

  1. The container calls the appropriate methods, such as attributeAdded and attributeRemoved, in the classes specified in the listener-class element.

  2. The methods in the classes specified in the listener-class element call the attributeAdded and attributeRemoved methods.

  3. The methods such as attributeAdded and attributeRemoved are defined in the classes specified in the listener-class element.

  4. The listener-class element goes in server.xml.

Answers A and C are correct. The listener-class element declares that a class in the application must be registered as a Web application listener bean. The value is the fully qualified class name of the listener class. In these classes, you can add the attributeAdded and attributeRemoved methods.

Question 2

What is the correct declaration of a context parameter?

  1.   <context-param>
        <name>publisher</name>
        <value>QUE</value>
      </context-param>
  2.   <context_param>
        <param_name>publisher</param_name>
        <param_value>QUE</param_value>
      </context_param>
  3.   <context>
        <name>publisher</name>
        <value>QUE</value>
      </context>
  4.   <context-param>
        <param-name>publisher</param-name>
        <param-value>QUE</param-value>
      </context-param>

Answer D is correct. This is the correct way to declare a context parameter named publisher with a value of QUE. All the other options have incorrect elements.

Question 3

What parameter is passed to the attributeAdded method for a session attribute?

  1. HttpSessionListenerEvent

  2. HttpSessionEventEvent

  3. HttpSessionBindingEvent

  4. HttpSessionAttributeEvent

Answer C is correct. Only the HttpSessionBindingEvent object is passed to attributeAdded by the container when an attribute is added to a session.

Question 4

Regarding the Web application directory structure, what is the root directory?

  1. CATALINA_HOME\webapps\

  2. CATALINA_HOME\webapps\WEB-INF\

  3. CATALINA_HOME\WEB-INF\webapps\

  4. CATALINA_HOME\WEB-INF\

Answer A is correct. Option A is the root directory for the Web application also known as the context.

Question 5

Which two of the following are elements of the Web application descriptor? (Choose two.)

  1. init-type

  2. init-param

  3. listener-class

  4. error-class

Answers B and C are correct. There is neither an init-type element nor an error-class element.

Question 6

What interface do you implement if you want to use the attributeAdded method?

  1. HttpSessionListener

  2. HttpSessionAttributeListener

  3. SessionAttributeListener

  4. SessionAttributeListener

Answer B is correct. The HttpSessionAttributeListener interface enables you to override the attributeAdded method, which is called by the container when an attribute is added to a session. HttpSessionListener enables you to listen to the notification that a session is created or destroyed. The other two options are not valid interfaces.

Question 7

Given the contextInitialized(ServletContextEvent event) method, how do you get the context (assuming that the request object is properly assigned)?

  1. ServletContext context = request.getServletContext();
  2. ServletContext context = event.getServletContext();
  3. ServletSession context = event.getContext();
  4. ServletContext context = request.getSessionContext();

Answer B is correct. This option is the only correct syntax shown. The others have incorrect syntax.

Need to Know More?

Writing Web Application Deployment Descriptorsedocs.bea.com/wls/docs70/
webapp/webappdeployment.html

The Java Servlet 2.3 Specificationjcp.org/aboutJava/communityprocess
/firsthttp://www.pearsonitcertification.com/jsr053/index.html

Deploying Web applicationsjava.sun.com/webservices/docs
/ea2/tutorial/doc/WebApp.html

Configuring Tomcat Servletsjava.sun.com/docs/books/tutorial
/servlets/servletrunner/webappdd.html

Tomcat—An Implementation of the Java Servlet 2.3 and JavaServer Pages 1.2 Specificationshttp://jakarta.apache.org/
tomcat/index.html

Assembling and Configuring Web Applicationsedocs.bea.com/wls/docs70/webapp/index.html

800 East 96th Street, Indianapolis, Indiana 46240