4.5 Configuring the web.xml File for Struts

Although the web.xml file is used for configuring any generic web application, there are a few Struts-specific configuration options that you must configure within this file when using the Struts framework. The next section describes the necessary steps that you'll need to perform to ensure that your Struts application is properly configured.

4.5.1 Mapping the Struts ActionServlet

The first and perhaps most important step that you need to perform is to configure the ActionServlet that will receive all incoming requests for the application.

You need to configure only a single ActionServlet, regardless of the number of subapplications that are being used. Some developers choose to set up multiple controller servlets to handle different functional areas of the application. Because servlets are multithreaded, you don't gain any real performance or scalability value by using multiple ActionServlet mappings. Currently, the Struts framework allows only a single controller servlet to work. This problem surely will be fixed in a future release and might even be resolved before 1.1 goes final. However, you should verify that the problem has been fixed before attempting to use multiple controllers in your application.

There are two steps in configuring the Struts controller servlet in the web.xml file. The first step is to use the servlet element to configure the servlet instance that can later be mapped in the servlet-mapping element. The child elements that can be used in the servlet element are shown here:

<!ELEMENT servlet (icon?, servlet-name, display-name?, description?,
   (servlet-class|jsp-file), init-param*, load-on-startup?, run-
   as?, security-role-ref*)
>

The child elements that we are most interested in are servlet-name, servlet-class, and init-param. The servlet-name elementspecifies the name used by the deployment descriptor to reference the servlet throughout the remainder of the file. When you're configuring the servlet-class element for a Struts application, this element must specify a fully qualified class that extends the org.apache.struts.action.ActionServlet class.

Because the Struts ActionServlet class is not abstract, you are free to use that class and avoid having to create a subclass of the ActionServlet for your application. With earlier versions of the Struts framework, it was more important to extend the ActionServlet class with one of your own because most of the processing occurred there, and subclassing allowed you to override that functionality with your own. With Version 1.1, however, most of the processing functionality has been moved to another class, which you can configure declaratively (as you'll see later in this chapter). There is little reason to create your own ActionServlet class, although you are still free to do so.

The following web.xml fragment illustrates how to use the servlet element to configure the servlet class:

<web-app>  
 <servlet>
  <servlet-name>storefront</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
 </servlet>
</web-app>

The next step that needs to be performed to configure the Struts controller servlet in the deployment descriptor is to configure the servlet mapping. This is done using the servlet-mapping element. The following partial deployment descriptor illustrates how to combine the servlet-mapping element with the servlet element shown previously:

<web-app>  
 <servlet>
  <servlet-name>storefront</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>storefront</servlet-name>
  <url-pattern>*.do</url-pattern>
 </servlet-mapping>
</web-app>

Notice that the value in the servlet-name element within the servlet element must match the value in the servlet-name element within the servlet-mapping element. This tells the web container that the ActionServlet should service all requests having an extension of .do.

4.5.1.1 Mapping requests to servlets

This is a good time to digress for a moment and discuss how the URLs that a user types into a browser are mapped to the correct web application and servlet. When a web application is installed in a container, the container is responsible for assigning a ServletContext to it. There is a single instance of a ServletContext object for each web application deployed in a container.

If the container is distributable and uses more than one JVM, the web application may have a separate ServletContext instance for each JVM.

The ServletContext provides an external view of the web container environment for a servlet. A servlet can use the ServletContext object to gain access to external resources, log events, and store attributes and objects that other servlet instances in the same context can access. It's essentially an application-scope shared resource.

Because a servlet is associated with a specific web application, all requests that begin with a specific request path (known as the context path) are routed to the web application associated with that servlet. Servlets associated with the default application have an empty string ("") as the context path.

When a web container receives a client request, it must determine the correct web application to forward it to. The web container determines this by matching the URL with the longest context path that matches an installed web application.

For example, suppose that there are two web applications installed in a container. One web application is given the name Storefront and is located off the root directory of the container at /storefront. The second web application is called Storefront_demo and is located off the root directory at /storefront_demo.

If a client request arrives at the server with a URL of http://www.somehost.com/storefront_demo/login.do, the server will match it to the web application that has the closest match, which in this case would be the Storefront_demo application. Once the container determines the correct context or web application, it must determine which servlet in the web application should process the request. The web container uses the request URL, minus the context path, to determine the path that will be used to map the request to the correct servlet.

The web container uses the following guidelines to find the first successful match:

1.       The container attempts to locate an exact match of the request path to the path of a servlet.

2.       The container recursively tries to match the longest path prefix. The servlet that contains the longest match, if any, is selected.

3.       If the URL path contains an extension—for example, .do—the servlet container tries to match a servlet that handles requests for that extension. The extension is defined as the part of the segment after the last dot (.).

4.       If none of the previous rules produces a match, the container attempts to use a default servlet, if one is configured. Otherwise, the request returns an error response.

The web container uses case-sensitive string comparisons when checking for a match.

The concept of extension mappings was mentioned in Step 3 of the matching guidelines. There is another type of mapping that can be used, known as path mapping . A servlet-mapping that uses path mapping allows a URL that doesn't contain an extension to match to the servlet. Using the earlier Storefront servlet mapping, the following partial web.xml file illustrates how path mapping is configured:

<web-app>  
 <servlet>
  <servlet-name>storefront</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>storefront</servlet-name>
  <url-pattern>>/action/*</url-pattern>
 </servlet-mapping>
</web-app>

Using path mapping, all requests mapped to this web application that contain the string "/action" in the request URL will be serviced by the Storefront servlet, regardless of what is in place of the * character.

4.5.2 Specifying Multiple Application Modules

As was briefly discussed in Chapter 3, the Struts 1.1 release added the ability to define multiple Struts configuration files, one for each supported application module. In previous versions of the framework, you specified a relative path to the single Struts configuration file using the config initialization parameter. With Version 1.1 and introduction of the concept of application modules, you can now create multiple Struts configuration files and specify them in the web.xml file using multiple config initialization parameters and the application module prefix. The next section discusses the initialization parameters that can be configured for a servlet.

4.5.3 Declaring the Initialization Parameters

Initialization parameters are used to make configuration options available to a servlet. This allows the developer to declaratively affect the runtime environment of the servlet. Initialization parameters are configured within the servlet element using init-param elements, as shown in the following web.xml fragment:

<web-app>  
 <servlet>
  <servlet-name>storefront</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  <init-param>
   <param-name>config</param-name>
   <param-value>/WEB-INF/struts-config.xml</param-value>
  </init-param>
  <init-param>
   <param-name>host</param-name>
   <param-value>localhost</param-value>
  </init-param>
  <init-param>
   <param-name>port</param-name>
   <param-value>7001</param-value>
  </init-param>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>storefront</servlet-name>
  <url-pattern>*.do</url-pattern>
 </servlet-mapping>
</web-app>

You can specify any parameter you need within the init-param element, as long as it's a name/value pair. For example, the previous web deployment descriptor included initialization parameters for a host and port. If you were using EJB, this might be a way to include the server connection information. Zero or more init-param elements are allowed.

There are specific initialization parameters that can be specified for the Struts servlet. In earlier versions of Struts, many of the configuration options that are now in the Struts configuration file were configured by adding init-param elements. Although applications that were built and tested with Version 1.0 will continue to work using Version 1.1, you may want to move some of the initialization parameters that currently are specified in the web deployment descriptor to the proper location in the Struts configuration file. Although the framework includes functionality that allows the previous initialization parameters to work in the web.xml file, we will cover the 1.1 parameters here. Table 4-2 identifies the initialization parameters that can be specified for Struts 1.1.

Table 4-2. Initialization parameters for web.xml using Struts 1.1

Name

Purpose/default value

config

A context-relative path to the default Struts configuration file. The default value is /WEB-INF/struts-config.xml, which serves as the default application.

config/sub1

You can specify additional subapplications by using the value config/ and the prefix of the subapplication. In this example, the init-param name would be config/sub1 and the value might be WEB-INF/struts-sub1-config.xml. This tells the controller to load the subapplication sub1 from the additional Struts configuration file. You can declare as many subapplications as you need.

debug

The debugging detail level for this servlet, which controls how much information is logged. This parameter is optional and defaults to 0 if not specified, which is the least amount of logging information possible.

detail

The debugging detail level for the Digester, which logs information as it parses the configuration files. This parameter is optional and defaults to 0 if not specified, which is the least amount of logging information possible.

convertHack

If this Boolean value is set to true, any ActionForm that uses Java wrapper class types such as java.lang.Integer will be set to null rather than the default value for the class type. This behavior is indicative of Struts 1.0. The flag is optional and the default value is false, which means that properties will be initialized to their Java default values (e.g., Integer to 0, Boolean to false, etc.).

 

If you are supporting a Struts 1.0 application using the 1.1 release, the web.xml file may contain many of the configuration parameters that are now defined in the Struts configuration file. The parameters apply only to the default application and will eventually be removed in future releases. It's better to get used to setting them in the Struts configuration file.

4.5.4 Configuring the Tag Libraries

The Struts framework provides several JSP tag libraries that you must configure in the web application deployment descriptor if you choose to use them. You inform the container of these tag libraries by declaring one or more taglib elements within the web deployment descriptor. The following partial web.xml file illustrates how the tag libraries are configured within the web-app element:

<web-app>
 <servlet>
  <servlet-name>storefront</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  <init-param>
   <param-name>config</param-name>
   <param-value>/WEB-INF/struts-config.xml</param-value>
  </init-param>
  <init-param>
   <param-name>host</param-name>
   <param-value>localhost</param-value>
  </init-param>
  <init-param>
   <param-name>port</param-name>
   <param-value>7001</param-value>
  </init-param>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>storefront</servlet-name>
  <url-pattern>*.do</url-pattern>
 </servlet-mapping>
 
 <taglib>
  <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
  <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
 </taglib>
 
 <taglib>
  <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
  <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
 </taglib>
 
 <taglib>
  <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
  <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
 </taglib>
</web-app>

The taglib element has two subelements: taglib-uri and taglib-location. The taglib-uri element specifies a URI identifying a tag library that is used by the web application. The value may be either a relative or an absolute URI. It must be a valid URI, but here it's used as a unique identifier for the tag library. The taglib-location element specifies the location (as a resource) of the tag library descriptor file.

The Struts tag libraries are not the only ones that can be declared in the web application deployment descriptor. If you create any of your own custom tag libraries, you should create taglib elements for them here as well.

4.5.5 Setting Up the Welcome File List

The welcome-file-list element allows you to configure default resources that should be used when a valid but partial URI is entered for a web application. You can specify multiple welcome files, and they will be used in the order in which they are listed.

Suppose we configured the welcome-file-list element for the Storefront application as in Example 4-1.

Example 4-1. The welcome-file-list element for the Storefront application
<welcome-file-list>
 <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

This indicates that a request to the server for http://www.somehost.com/storefront, which is the root of the Storefront application, should resolve to http://www.somehost.com/storefront/index.jsp. This is beneficial because most containers would, by default, look for index.html or index.htm instead. You can specify multiple welcome-file elements within the welcome-file-list. This might be helpful if, for example, you deployed your application on various types of containers and the first welcome-file resource was not found on the server. The container would continue to try to match the welcome files up to the request URI until it found one on the server and served that resource to the client. The order of the welcome file entries in the deployment descriptor is used for the matching process.

There should be no trailing or leading "/" characters in the welcome-file element. If no welcome files are declared for the web application or the URI entered by a client, the web container may handle the request appropriately—for example, it may return a 404 (File Not Found) error response or a directory listing. It's a good idea to configure a welcome file for at least the root web application.

4.5.5.1 Using a Struts action in the welcome file list

Because the web containers don't use the servlet mappings for resources in the welcome-file-list, you can't directly set up a welcome-file element to use a Struts action.

However, there is an alternate way that allows you to achieve the same results. First, create a global forward in the Struts configuration file for the action that you would like to invoke:

<global-forwards>
 <forward name="welcome" path="viewsignin.do"/>
</global-forwards>

Then create a JSP page called welcome.jsp (the name actually can be anything you want) and use the Struts forward tag to forward to the global forward when the page is loaded. The welcome.jsp page only has to contain:

<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html>
 <body>
  <logic:forward name="welcome"/>
 </body>
</html>

You then need to add a welcome-file element for the welcome.jsp page:

<welcome-file-list>
 <welcome-file>welcome.jsp</welcome-file>   
</welcome-file-list>

When the container uses the welcome.jsp resource, it will automatically forward to the forward named welcome, which was defined in the global-forwards section. The welcome forward in turn invokes the viewsignin.do action and achieves the desired result.

4.5.6 Configuring Error Handling in web.xml

Although the Struts framework provides a suitable error-handling mechanism, there are times that problems slip through the exception-handling crack and users are shown a servlet or JSP exception. To absolutely prevent this from happening, you should use the error-page element available to the web application deployment descriptor. Example 4-2 shows a partial web.xml file that uses the error-page element to prevent users from seeing a 404 or a 500 (Internal Server) error.

Example 4-2. Using the error-page element
<web-app>
 <!-- Other elements go here -->
 
 <error-page>
  <error-code>404</error-code>
  <location>/common/404.jsp</location>
 </error-page>
 
 <error-page>
  <error-code>500</error-code>
  <location>/common/500.jsp</location>
 </error-page>
</web-app>

When an error status code is set in the response, the container consults the list of error-page declarations for the web application. If a match is found, the container returns the resource indicated by the location element. The value of the location element must begin with a "/" character, and it must refer to a resource within the web application.

If you need to refer to a resource outside of the web application, you can use the HTML Refresh meta tag. To do this, refer to a static HTML document in the location element that contains only the following line:

<meta http-equiv="Refresh" content="0;URL=http://www.somehost.com/404.jsp">

When the error occurs, the Refresh meta tag will reload immediately, but it will use the alternate URL provided. This strategy also is a good way to allow users to refer to resources with a static extension, such as .htm, but then reload to a dynamic page, such as a JSP page.

For example, you can use this approach to show a "Still Processing" page. You might want to set the reload time to a value greater than zero. The URL can be a Struts action, and if the processing isn't finished, it will just call the same page again. If processing has completed, it can forward to a completed page.

A servlet also can generate exceptions for which you can declare error pages. Instead of specifying the error-code element, you can specify a fully qualified Java class using the exception-type element. Servlets can throw the following exceptions during processing:

·         RuntimeException or Error

·         ServletException or subclasses

·         IOException or subclasses

The Java exception class declared in the exception-type element must be one of these.

Example 4-3 illustrates how you would substitute the exception-type element for the error-code.

Example 4-3. Using the exception-type instead of the error-code element
<web-app>
 <error-page>
  <exception-type>javax.servlet.ServletException</exception-type>
  <location>/common/system_error.jsp</location>
 </error-page>
</web-app>

For the majority of this chapter, you have been shown partial deployment descriptors. This was done mainly to save space, but also so that we could ease our way into the various supported elements. Now it's time to include a complete example of a web deployment descriptor. Example 4-4 shows the web deployment descriptor for the Storefront application.

Example 4-4. A complete web.xml file configured for Struts 1.1
<?xml version="1.0" encoding="UTF-8"?>
 
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
    
<web-app>  
 <servlet>
  <servlet-name>storefront</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  <init-param>
   <param-name>config</param-name>
   <param-value>/WEB-INF/struts-config.xml</param-value>
  </init-param>    
  <init-param>
   <param-name>debug</param-name>
   <param-value>3</param-value>
  </init-param>
  <init-param>
   <param-name>detail</param-name>
   <param-value>3</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>
  
 <servlet-mapping>
  <servlet-name>storefront</servlet-name>
  <url-pattern>/action/*</url-pattern>
 </servlet-mapping>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>   
 </welcome-file-list>
  
 <error-page>
  <error-code>404</error-code>
  <location>/common/404.jsp</location>
 </error-page>
 <error-page>
  <error-code>500</error-code>
  <location>/common/500.jsp</location>
 </error-page>
 
 <taglib>
  <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
  <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
 </taglib>
 <taglib>
  <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
  <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
 </taglib>
 <taglib>
  <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
  <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
 </taglib>
</web-app>