In this article, we will review the web container (22000) model and itís services for servlets. We briefly touched on the web container in the first two articles of this series, ďTutorial: Review of HTTP Methods and Servlet API for the Web Component Developer ExamĒ and ďTutorial: Web Application Structure and Deployment for the Component Developer ExamĒ. Here we will look go into detail of the web container model and the key role that it has in providing a panopoly of services for servlets and JSPs. This is part of a series of articles to help you prepare for the web component developer exam.

The Web Container Model

In our previous article, ďTutorial: Review of HTTP Methods and Servlet API for the Web Component Developer ExamĒ, we talked about the servlet lifecycle. Now we will delve into it in more depth.

When the web server receives a request for a servlet, the server dispatches the request to the web container that handles requests based on the particular URL. In turn, the web container in which the servlet is deployed. If it is the first request, the servlet is first created, and its init method is invoked. This is done so that it can run its one-time setup code. After the one time setup, each subsequent user request results in the container allocating a thread for the servlet in order to handle the request and it will invoke the servletís service() method passing in a HttpServletRequest and HttpServletResponse object that it has created. Multiple concurrent requests will result in multiple threads calling the service method simultaneously. The service method will then call one of the doXXX methods like doGet or doPost along with the HttpServletRequest and HttpServletResponse objects. Finally, when the container decides to unload a servlet, it will call the servletís destroy method. See figure below for how the web container interacts with web server and a servlet:

Tutorial:Review of Web Container Model and Services for Web Component Developer Exam-a15-webcontainerservletconfig.jpg
Figure: Web Container Initializing Params and ServletConfig

The init Method

The init method is the first method invoked by the web container on the servlet after it has been created. It is used only once to perform servlet initializations. The servlet can be created either when a user first invokes a URL corresponding to the servlet or when the web container is started due to configuration of the web.xml file. If the servlet is not explicitly registered, the servlet will be instantiated on the first invocation of the URL otherwise it depends on the settings used for registering the servlet.The init method is shown below.

Java Code: Syntax of init Method
public void init() throws ServletException {
// Initialization code...
The init method obtains a ServletConfig object by calling getServletConfig(). This is another object that is created by the web container. The ServletConfig object provides a servlet with information about its initialization parameters. The parameters are given directly to the servlet itself instead of being associated with a particular request. ServletConfig has a getInitParameter method which can be used to look up initialization parameters associated with the servlet. The values for each parameter are located in a map which are accessed by providing a parameter name and obtaining the parameter value. All values returned are strings. These parameters are defined in the web.xml. An example of this is shown below:

XML Code: Servlet Declaration in Deployment Descriptor
Here we have defined two init values for parameters, driver and url for a servlet called DatabaseServlet. We use the init-param element and the param-name and param-value subelements to do this. One thing to remember when initializing servlets is that initialization parameters are only available when servlets are accessed through custom URL patterns associated with their registered names. For example, the driver and url init parameters would be available if you used, http://host/appPrefix/testDatabase but would be unavailable if you used http://host/appPrefix/servlet/

The service Method

When a server receives a request for a servlet, the server pass the request to the web container who then creates a new HttpServletRequest and HttpServletResponse object, spawns a new thread and calls the service method on the requested servlet. The service method in turn determines the HTTP request type (GET, POST, PUT, DELETE, etc.) and then calls the requisite doXXX method(i.e. doGet, doPost, doPut, doDelete, etc.). This is shown in the figure below:

Tutorial:Review of Web Container Model and Services for Web Component Developer Exam-a15-servlethandlinggetrequest.jpg
Figure: Web Container and Servlet Handle GET Request

In your servlet you only override the methods that you need to process. In most cases, the others can be left to the default handling. Sometimes you may need to have both POST and GET requests handled in the same manner. Rather than attempt to override the service method or place the processing code in both the doGet and doPost, the best approach to this is to override one where you place the code for processing the request and in the other you dispatch to the method where you are processing the request. This is shown in the listing below:

Java Code: Example of Two Methods with Same Processing Code
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { 
   // Servlet Code for processing the request and returning a response

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { 
   doGet(request, response);
This approach has several advantages over directly overriding the service method:
  • Allows you to make modifications later adding support for other services later (i.e. doPut, doTrace, etc.), Overriding the service method precludes this possibility.
  • Allows for support for modification dates through the getLastModified method. If you override doGet, the standard service method uses the getLastModified method to set Last-Modified headers and respond correctly to conditional GET requests (i.e. If-Modified-Since header).
  • Automatic support for HEAD requests. As we mentioned in the first article, on a HEAD request, the servlet will invoke doGet and it will return whatever headers and status codes set in the doGet method without the page body.
  • Automatic support for OPTIONS requests. Again overriding the doGet method, the standard service method will respond to OPTIONS requests by returning an Allow header indicating that GET, HEAD, OPTIONS, and TRACE are supported.
  • Automatic support for TRACE requests. Often used for client debugging, the TRACE request will be handled by the service method returning the HTTP request headers back to the client.

The destroy Method

The web container will invoke the destroy method on a servlet in order to give the servlet an opportunity to do clean up before it is made ready for garbage collection. The servlet can then close database connections, halt background threads, write cookie lists or hit counts to disk, and perform other cleanup activities. In rare case, however, if the Web server crashes, so if needed you might want to persist key parameters to disk periodically.

Application Wide Communication with the Servlet Context

Where as there is one ServletConfig per servlet and it is used to pass initialization parameters to a servlet at startup, the ServletContext is used to pass initialization parameters to the web container at startup. In fact it is the ServletContext which gives to a servlet the ServletConfig via the getServletConfig() method. Below is a table showing the key aspects of ServletContext and ServletConfig:

Tutorial:Review of Web Container Model and Services for Web Component Developer Exam-a15-servletcontext_vs_config.jpg
Table: ServletContext vs ServletConfig

The ServletContext serves as the means of communication among the different components running in the web application. So for example context initialization parameters can be accessed by both servlets and JSPs. This would allow for parameters that are needed by all components to be specified in one location. A figure demonstrating this is shown below:

Tutorial:Review of Web Container Model and Services for Web Component Developer Exam-a15-servletcontext.jpg
Figure: ServletContext within a Web Container for Several Servlets and JSPs

Similarly to the ServletConfig, the ServletContext also has a getInitParameter method which is used to access the initialization parameters for the ServletContext. The means of accessing the ServletContext is by calling the method, getServletContext(). This will return the ServletContext provided to you by the web container. Below is a listing showing how to obtain the servlet context and then the parameters for the former and actual managers for the football team:

Java Code: Example of Initialization of Config Parameters
import javax.servlet.*; 
import javax.servlet.http.*;

/** Simple servlet used to illustrate loading init-param 
into ServletContext. 

public class FCSouthServlet extends HttpServlet { 

private String actualManager = "There is no manager presently";
public void init() { 
   ServletConfig config = getServletConfig();
       if (config.getInitParameter("actualManager") != null) {
          actualManager = config.getInitParameter("actualManager");
       ServletContext context = getServletContext(); 
       context.setAttribute("actualManager", actualManager);
In the deployment descriptor, you provide the any values to be initialized in the content-param element and the mapping of the name and value in param-name and param-value respectively. This is shown in the listing below:
XML Code: Example of context-param
   <param-value>James Smith</param-value> 
Similarly to the ServletContext, the web container will create a ServletContext. Only in this situation, only one is created when the application is started and shared by all components during the lifetime of the application. The ServletContext interface has two methods available for you to use. These are discussed below.
  • getInitParameter - will return a String corresponding for the name of the context-wide initialization parameter, or null if the parameter does not exist.
  • getInitParameterNames - will return an enumeration of String objects or an empty enumeration for the names of the context's initialization parameters. If the context has no initialization parameters, it will return an empty enumeration.

Attributes at the Request, Session and Context Level

The ServletContext, Session and ServletRequest are all capable of storing attributes in order to facilitate communication among different servlets, JSPs and other objects in the application. Built on top of the setting, getting and removing of attributes is the application events model. This is accomplished via the application life-cycle event listeners which trigger events tied to changes in attributes at the request, session or context level. The same set of methods are available for each object for manipulating attributes, the methods are the following:
  • getAttribute - returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
  • getAttributeNames -returns an enumeration for the list of names of the attributes available to this request. If the request has not attributes, then an empty Enumeration is returned.
  • setAttribute - set the attribute of this request. Attributes get reset between requests. We often used the setAttribute method in conjunction with RequestDispatcher. If you value for the setAttribute is null, the result is that the attribute will be removed.
  • removeAttribute - removes a particular attribute from the request. You will not need to use this as the attribute lifecycle is only as long as the request.

The figure below shows the methods for a ServletRequest Object:

Tutorial:Review of Web Container Model and Services for Web Component Developer Exam-a15-servletrequestclass.jpg
Figure: ServletRequest Methods for Attributes

Application Event Listeners at Context Scope

There are servlet context listeners that are provided in order that events will be generated when the servlet context is initialized and destroyed. There is the ServletContextListener which responds to the initiation and destruction of the servlet context and the ServletContextAttributeListener which responds to changes in the context attributes. The ServletContextListener is used primarily to setup application wide resources like database connection pools and to read the initial values for data that will be used throughout the application by various servlets and JSPs. The steps need to do this are the following:
  1. Implement the ServletContextListener interface.
  2. Implement contextInitialized and contextDestroyed. The first method, contextInitialized is triggered by the Web application first loading and the servlet context being created. This is commonly used to create application-wide data. The second method, contextDestroyed is triggered by the Web application is being shut down and the servlet context just before it is destroyed. This is used commonly to release resources.
  3. Obtain a reference to the servlet context. Both contextInitialized and contextDestroyed take a ServletContextEvent as an argument. The ServletContextEvent object has a getServletContext method that returns the servlet context.
  4. Use the servlet context to read initialization parameters using getInitParameter, store data with setAttribute, and make log file entries with log.
  5. Declare the listener in the deployment descriptor (web.xml) as shown below:

    XML Code: Listener declaration
  6. You can also package listeners with tag libraries and then declare them within the TLD file of the tag library.
  7. Supply the required initialization parameters. Once defined, you can obtain them via the getInitParameter method to read context initialization parameters and make them available to all servlets and JSP pages. Syntax for declaring them in your deployment descriptor is shown below:
    XML Code: context-param declaration

Application Event Listeners at Request Scope

There are a number of request attribute listeners that can be used so that your components are notified when attributes are modified in any way for a request. In the case of an attribute at request scope, we have the the ServletRequestListener which monitors the creation and destruction of a ServletRequest and the ServletRequestAttributeListener which monitors the life cycle of request scope attributes. The container notifies the ServletRequestListener when a new ServletRequest is either created or destroyed. For the ServletRequestAttributeListener, the container notifies it when an object is put into the request scope initially, updated or replaced by another object, or completely removed from the request scope. To implement a ServletRequestAttributeListener, you do the following:
  1. Implement the javax.servlet.ServletRequestAttributeListener interface.
  2. Implement the methods for attributeAdded, attributeReplaced, and attributeRemoved. The attributeAdded method is triggered when a new attribute is added to a request, the attributeReplaced is triggered with the existing value being replaced and the attributeRemoved method is triggered when a request attribute is removed.
  3. Obtain references to the attribute name, attribute value, request, and servlet context. All of the three ServletRequestAttributeListener methods have the same argument using the ServletRequestAttributeEvent class. The ServletRequestAttributeEvent class has the following methods you can use: 
* getName - name of the attribute that was changed 
* getValue - the value of the changed attribute or added or remove 
* getServletRequest - to obtain a reference to the ServletRequest 
* getServletContext - to obtain a reference to the ServletContext
  4. Code your operations using the objects.
  5. Declare the listener either in the deployment descriptor or in the TLD file. The syntax is shown below:
    XML Code: ServletRequestAttributeListener declaration

Application Event Listeners at Session Scope

The listeners for a HttpSession attributes are similar to the ones for a ServletRequest in that there is one that allows you to bind an object to the session to listen for the creation, changes or removal of the attribute, HttpSessionAttributeListener and another that listens for the creation and destruction of the session, HttpSessionListener. But there are also two additional listeners. The first, HttpSessionBindingListener is notified when the implementing object is added or removed from the session object and the second, HttpSessionActivationListener is notified when session objects are serialized and deserialized by the container. This last can be very useful when session are being migrated in a distributed application. As providing an example with the HttpSessionActivationListener is out of scope, I will outline the steps needed for implementing it:
  1. Implement the javax.servlet.http.HttpSessionActivationListener interface.
  2. Implement the methods needed for activation (deserialization) and passivation (serialization) of the session. The sessionDidActivate method is triggered when the session has deserialized and the sessionWillPassivate method is triggered when the session is about to be serialized.
  3. Obtain references to the session event, and session. The two methods have the same argument using the HttpSessionEvent class. The HttpSessionEvent has only one method, getSession.
  4. Code your operation using the session.
  5. Declare the listener either in the deployment descriptor or in the TLD file. The syntax is shown below:
    XML Code: HttpSessionActivationListener declaration


The Request Processing Model

The Request Dispatcher is a mechanism to allow for another resource to handle a particular request. It is used by servlets to forward requests or to include external content in a response. Whereas the a redirect, will call the client to do the work in forwarding the request on to another resource for handling, a request dispatch will do this work on the server side. A RequestDispatcher is obtained by calling the getRequestDispatcher method of ServletContext. You provide a URL relative to the server root. For example, to obtain a RequestDispatcher associated with http://localhost/football/matches.jsp, you do the following:

Java Code: Use of Request Dispatcher
String url = "/football/matches.jsp"; 
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(url);
Once you have a reference to a RequestDispatcher, you can use it to transfer complete control to the associated URL and use an include to output the associated URLís content. You need to supply the HttpServletRequest and HttpServletResponse that are used as arguments. An example is shown in the following listing:

Java Code: Example of Request Dispatcher
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { 
   String coaching = request.getParameter("coaching"); 
   if (coaching == null) {
      coaching = "unknown";
   } if (coaching.equals("coaching1")) {
         dispatchTo("/coachings/pickteam1.jsp", request, response);
   } else if (coaching.equals("coaching2")) { 
         dispatchTo("/coachings/pickteam.jsp", request, response);
   } else { dispatchTo("/coachings/unknownRequestHandler.jsp",
         request, response);

private void dispatchTo(String address, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(address);
   dispatcher.forward(request, response);
Here the servletís doGet method will forward the request to one of the three different JSP pages based on the operation parameter. A method has been created dispatchTo in order to encapsulate getRequestDispatcher calls that would otherwise be repeated. The method takes the URL, the HttpServletRequest and HttpServletResponse objects; obtains a reference to a RequestDispatcher; and then calls itís forward method.

Using Static Resources in Request Dispatching

Request dispatching is used most frequently to forward requests to a JSP page or another servlet. But sometime, you might need to forward the request to a static HTML page. So for example, an e-commerce site requests where there is no a valid account name for the user, would be forwarded to an account application page using HTML forms to gather the required information. If youíre using GET requests, there is no problem with forwarding requests to a static HTML page. It only requires that you provide as an argument the address of the HTML page for the getRequestDispatcher. But you cannot forward POST requests because forwarded requests use the same request method as the original request. The way to resolve this situation is to simply change the .html of the HTML page to .jsp extension. This does not change its output for GET requests, but the .jsp file will give an identical response for both GET and POST.

Furnishing Information to the Destination Pages

If you want to provide information to your destination pages, the most straightforward approach is building on our previous discussion of attributes within a ServletRequest, you can use attributes as a means of furnishing the destination pages with information. You must decide what scope that you want the information to exist (i.e. request, session or application). An example of using attributes at the request scope is shown below:

Java Code: Attributes set by the originating servlet in the HttpServletRequest
request.setAttribute("myKey", foo);
Java Code: Attribute value being accessed in the destination page via JSP scripting element
MyObject myObject = (MyObject)request.getAttribute("myKey");
Another approach when working with more complex values, is to use a Java bean and persist it in a location used by jsp:useBean for shared beans. If you want to provide some values in a application scope, you can make the bean accessible to all components in the web application by doing the following:

Java Code: Attributes set by the originating servlet in ServletContext
MyObject myObject = computeValueFromRequest(request); 
getServletContext().setAttribute("myKey", myObject);
Java Code: Attribute value being accessed in the destination page via jsp:useBean
<jsp:useBean id="myKey" class="MyObject" scope="application" />
For a servlet to make data specific to a user session, the servlet would store the value in the HttpSession in the following manner:

Java Code: Setting Attribute in Session
 MyObject myObject = computeValueFromRequest(request); 
HttpSession session = request.getSession(true); 
session.putValue("myKey", myObject);
Attribute value being accessed in the destination page via jsp:useBean:
Java Code: Example of useBean for Session Attribute in JSP
<jsp:useBean id="myKey" class="MyObject" scope="session" />
There is another way to send data that was introduced in the Servlet 2.2 specification for GET request. You can simply append the query data to the URL. An example is shown below:

Java Code: Setting Attribute in Request
String address = "/path/resource.jsp?newParam=value"; 
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(address); dispatcher.forward(request, response);
By using this approach, you have an additional request parameter of newParam being added to whatever request parameters already existed. You add a new parameter to the beginning of the query data. This will replace existing values if the destination page uses getParameter with the first occurrence of the named parameter instead of the getParameterValues.

Interpreting Relative URLs in the Destination Page

If you are using relative URLs in the destination page for images or style sheets, it is necessary to make them relative to the server root. This is not relative to the destination pageís actual location but the originating servlet. For example, consider the following style sheet entry:

XML Code: Standard css Definition in HTML
<LINK REL=STYLESHEET HREF="mystyles.css" TYPE="text/css">
For a JSP page with this entry is accessed by means of a forwarded request. The mystyles.css style sheet is interpreted relative to the URL of the originating servlet. If it is relative to the JSP page itself, it will result in an error. The way around this is to give the full server path to the style sheet file. This is shown below:

XML Code: CSS Definition using Full Server Path in HTML
 <LINK REL=STYLESHEET HREF="/path/mystyles.css" TYPE="text/css">
The same approach can be used image and links as well.

Alternative Means of Getting a RequestDispatcher

There are a couple of other means for obtaining a RequestDispatcher reference outside of using the ServletContextís getRequestDispatcher method that were added in version 2.2 of the servlet specification. There are:
  • getNamedDispatcher method of ServletContext - when you want to access a servlet or JSP page by name rather than path.
  • getRequestDispatcher method of HttpServletRequest - for servlets that are registered under a specific path.

Using Filters

Filters are similar in a sense to an interceptor in that they are programs that run on in the web container before the servlet or JSP page with which it is associated. Filter allow you to intercept the request and thus effectively control the response being return by the servlet. This is done without the servlet ever being aware that the request has been intercepted. You can attach a filter to one or more servlets or JSP pages and can inspect the request information going into these resources. When completed, the filter can do one of the following:
  1. Invoke the resource (i.e., the servlet or JSP page) normally.
  2. Invoke the resource with modified request information.
  3. Invoke the resource but change the response before sending it to the client.
  4. Block the resource from being invoked and redirect to another resource, return a specific status code, or generate replacement output.

Filters allow you to encapsulate common behavior in a modular and reusable manner. If you have a large number of servlet and JSP pages that require the content to be compressed in order to improve response time, you can make a compression filter and use it for all of your resources. You can also achieve a separation of concerns between these enhancements and your actual presentation code. For JSPs, where within the Model-View-Controller (MVC) paradigm, the JSP page serves as the view you want to avoid having any sort of business logic mingled into the JSP. Filters allow you to apply large scale changes to many different resources without needing to do significant refactoring. So for example, you could change the companyís name or the name of the president by creating a string replacement filter and apply it across the site. A figure of a filter in a web application is shown below:

Tutorial:Review of Web Container Model and Services for Web Component Developer Exam-a15-filters.jpg
Figure: Use of Filters in Web Application

How to Create a Filter

There are five steps that are need to create a filter. We go into this in the following sections.

1. Create a Class That Implements the Filter Interface

All filters are required to implement javax.servlet.Filter. There are three methods that you must implement:

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws ServletException, IOException

The doFilter method is the main method for filters containing the majority of the filter logic. It is executed every time a filter is invoked. It is invoked once for each request for a servlet or JSP page with which the filter is associated. It is this method that contains the bulk of the filtering logic. The ServletRequest is first argument is used to get information from form data, cookies and HTTP request headers. You will need to cast the ServletRequest object to HttpServletRequest in order to access the getHeader and getCookies methods. The second argument, ServletResponse is for the most part ignored. The two times when it is used is to completely block access to associated servlet or JSP page. This is done by using the ServletResponseís getWriter to send a response directly to the client. The other circumstance is when you modify the output of the associated servlet or JSP page. In this case, you wrap the response inside an object that collects all output sent to it. Then when the after servlet or JSP page is invoked, the filter can modify the output and forward it to the client. The last argument is the FilterChain object. This is used to invoke the next filter associated with the servlet or JSP page via a call to the FilterChainís doFilter method.

public void init(FilterConfig config) throws ServletException
The init method is only used when the filter is first initialized. There is one argument, FilterConfig. Afterwards it is not executed the next time the filter is invoked. The init method is used primarily to store the FilterConfig object so that the doFilter method can access the servlet context or the filter name. The other reason for using init is to access the filterís initialization parameters via the FilterConfigís (comparative to ServletConfig) getInitParameter method. Otherwise we leave the init method empty.

public void destroy()
The destroy method is called when the web container is permanently finished with a given filter object (e.g., when the web container is being shut down). In the majority of filters, this method is left empty but if you have files or database connections open, you can use this method to perform cleanup.

2. Put the Filtering Behavior in the doFilter Method

It is in the doFilter method that you put all the processing code for your filter. Everytime a filter is invoked, the doFilter method is executed. In general, the processing involves information that the filter will get from the ServletRequest object after you have cast it to a HttpServletRequest to access headers, cookies and content of the request.

3. Call the doFilter Method of the FilterChain Object

Once the filter has finished processing with the doFilter method, it will use the third argument of the doFilter method, the FilterChain and call its doFilter method in order to invoke the next associated filter. This process continues until the last filter in the chain is invoked unless there is some error. After the final filter invokes its doFilter method, the next invocation of doFilter from the FilterChain object, the target resource (i.e. servlet or JSP page) will be invoked. When any filter in the chain interrupts the process by omitting the call to the doFilter method of its FilterChain, the servlet or JSP page will not be invoked and the filter must provide the output to the client.

4. Register the Filter with the Appropriate Servlets and JSP Pages

Once you have complemented implementing your filter, you need to register it either using a deployment descriptor. The deployment descriptor provides two elements to use for filters: filter and filter-mapping. We discuss these below.

The filter Element

The filter element has six possible subelements:
  • icon - this optional element declares an image file that an IDE can use.
  • filter-name - this required element assigns a name of your choosing to the filter.
  • display-name - this optional element provides a short name for use by IDEs.
  • description - this optional element that provides textual documentation to the IDEs.
  • filter-class - this required element specifies the fully qualified name of the filter implementation class.
  • init-param - this optional element defines an initialization parameter that can be read with the getInitParameter method of FilterConfig. One filter element can contain multiple init-param elements. An example of the filter element is shown below:

XML Code: Definition of Filter Element
<?xml version="1.0" encoding="ISO-8859-1"?> 
<web-app ... version="2.4">
The filter-mapping Element

The filter-mapping element has four possible subelements:
  • filter-name - this required element must match the name of the filter when you declared it with the filter element.
  • url-pattern - this element provides the pattern starting with either a slash (/) or a *. that designates the URLs to which the filter applies. All filter-mapping elements must have a url-pattern or servlet-name. There is one url-pattern entries per filter-mapping element. To apply to multiple patterns to a filter, just repeat the entire filter-mapping element.
  • servlet-name - this element gives the name of the servlet or JSP page provide in its servlet element. There is one servlet-name elements entry per filter-mapping element. For multiple servlet names for the filter, repeat the entire filter-mapping element.
  • dispatcher - this optional element specifies what type of request this filter mapping should apply to. The possible values are REQUEST, FORWARD, INCLUDE, and ERROR. The default for dispatcher element, if nothing is specified is REQUEST. You can apply the same filter to different types of requests by using several dispatcher elements. An example of the filter mapping is shown below:

XML Code: Definition of filter-mapping Element
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app ... version="2.4">
OK. Thatís it. We have looked at the web container model and the services it offers to your web application. As you can see with ServletContext, ServletConfig, Attributes at different scopes, the servlet event model, request dispatches and filters, the web container provides you with alot of functionality for building your application. In the next article we will look at session management.