4.7 The org.apache.struts.config Package

The org.apache.struts.config package was added to Struts 1.1. The framework uses JavaBeans at runtime to hold the configuration information it reads from the Struts configuration files. Figure 4-4 shows the main classes from the config package.

Figure 4-4. Class diagram for the org.apache.struts.config package

figs/jstr_0404.gif

Each class in the config package holds information from a specific section of the configuration file. After the configuration file has been validated and parsed, the Struts framework uses instances of these beans to represent in-memory versions of the information that has been declared in the configuration file. These classes act as runtime containers of the configuration information and are used by the framework components as needed.

The org.apache.struts.config.ConfigRuleSet class shown in Figure 4-4 has a slightly different, but related, job—it contains the set of rules that are required to parse a Struts configuration file. Its job is to construct instances of the configuration JavaBeans mentioned in the previous paragraph when the application is started.

4.7.1 The ApplicationConfig Class

The org.apache.struts.config.ApplicationConfig class deserves a special introduction, as it plays a very important role in the framework. As Figure 4-4 indicates, it is central to the entire config package and holds onto the configuration information that describes an entire Struts application. If multiple subapplications are being used, there is one ApplicationConfig object for each subapplication. The ApplicationConfig class will surface throughout the remainder of our discussion of the framework.

4.7.2 The Struts Configuration DTD

As the web application's DTD is used to validate the web.xml file, the Struts DTD is used to validate the Struts configuration file.

A complete struts-config.xfile file is shown later, in Example 4-5. It may help to refer to that example following the discussion of these elements.

The following Struts DTD declaration indicates that the struts-config element is the root element for the XML file and that it has eight child elements:

<!ELEMENT struts-config (data-sources?, form-beans?, global-exceptions?, global-
   forwards?, action-mappings?, controller?, message-resources*, plug-in*)
>
4.7.2.1 The data-sources element

The data-sources element allows you to set up a rudimentary data source that you can use from within the Struts framework. A data source acts as a factory[3] for database connections and provides a single point of control. Many data source implementations use a connection-pooling mechanism to improve performance and scalability.

[3] See the discussion of the Abstract Factory pattern in the Gang of Four's Design Patterns: Elements of Reusable Object-Oriented Software (Addison Wesley).

Many vendors provide their own implementations of data source objects. The Java language provides the javax.sql.DataSource interface, which all implementations must implement. Most application servers and some web containers provide built-in data source components. All of the major database vendors also provide data source implementations.

The data-sources element can contain zero or more data-source elements:

<!ELEMENT data-sources (data-source*)>

The data-source element allows for multiple set-property elements to be specified:

<!ELEMENT data-source (set-property*)>

The set-property element allows you to configure properties that are specific to your data source implementation.

Throughout the discussion of the Struts configuration elements in the rest of this chapter, you will notice a child element called set-property in many of the major elements of the configuration file. The set-property element specifies the name and value of an additional JavaBeans configuration property whose setter method will be called on the object that represents the surrounding element. This element is especially useful for passing additional property information to an extended implementation class. The set-property element is optional, and you will use it only if you need to pass additional properties to a configuration class.

The set-property element defines three attributes, including the id attribute, which is seldom used. The property attribute is the name of the JavaBeans property whose setter method will be called. The value attribute is a string representing the value that will be passed to the setter method after proper conversion. This section provides an example of using the set-property element. The same format is replicated wherever the set-property element is declared.

The attributes for the data-source element are listed in Table 4-3.

Table 4-3. Attributes of the data-source element

Name

Description

id

Not currently used.

className

The implementation class of the configuration bean that will hold the data source information. If specified, it must be a descendant of org.apache.struts.config.DataSourceConfig, which is the default class when no value is specified. This attribute is optional.

key

The servlet context attribute under which this data source will be stored. This attribute is optional; the default value is Action.DATA_SOURCE_KEY.

type

The fully qualified Java class name of the data source implementation class. The class represented by this value must implement javax.sql.DataSource and be configurable from JavaBeans properties. This attribute is optional; the default value is org.apache.struts.util.GenericDataSource.

 

The GenericDataSource class included with the Struts framework has been deprecated in favor of the Database Connection Pool (DBCP) project from Jakarta or an implementation from your container.

The following code illustrates how to configure a data source within the Struts configuration file:

<data-sources>
 <data-source>
   <set-property property="autoCommit" value="true"/>
   <set-property property="description" value="MySql Data Source"/>
   <set-property property="driverClass" value="com.caucho.jdbc.mysql.Driver"/>
   <set-property property="maxCount" value="10"/>
   <set-property property="minCount" value="2"/>
   <set-property property="user" value="admin"/>
   <set-property property="password" value="admin"/>
   <set-property property="url" 
                 value="jdbc:mysql-caucho://localhost:3306/storefront"/>
 </data-source>
</data-sources>

This code illustrates a data-source element configured to connect to a MySQL database using a JDBC driver from Caucho Technology, the developers of the Resin™ servlet/EJB container.

You can specify multiple data sources within the configuration file, assign each one a unique key, and access a particular data source in the framework by its key. This gives you the ability to access multiple databases if necessary.

Although the default data source functionality provided by the framework does work, your application may require a more robust data source implementation. There are several other popular data source implementations you can use. Table 4-4 lists a few of the more popular alternative implementations.

Table 4-4. Alternative data source implementations

Name

Vendor

URL

Poolman

Open source

http://sourceforge.net/projects/poolman/

Expresso

Jcorporate

http://www.jcorporate.com

JDBC Pool

Open source

http://www.bitmechanic.com/projects/jdbcpool/

DBCP

Jakarta

http://jakarta.apache.org/commons/index.html

 

The creator of the Poolman open source libraries is no longer supporting it. Although it works well and still is available on SourceForge.net, it has not been updated for quite some time. Of course, since it's open source, you can make necessary fixes and changes yourself.

4.7.2.2 The form-beans element

The form-beans element allows you to configure multiple ActionForm classes that are used by the views. Within the form-beans section, you can configure zero or more form-bean child elements. Each form-bean element also has several child elements.

<!ELEMENT form-bean (icon?, display-name?, description?, set-property*, form-
   property*)
>

Each form-bean element also has four attributes that you can specify. Table 4-5 lists the attributes.

Table 4-5. Attributes of the form-bean element

Name

Description

className

If you don't want to use the standard configuration bean org.apache.struts.config.FormBeanConfig, you can specify your own class here. It must extend the FormBeanConfig class. This attribute is optional; the framework will use an instance of the FormBeanConfig class if it's not specified.

dynamic

If the class identified by the type attribute is an instance of org.apache.struts.action.DynaActionForm or a subclass, this value should be set to true. Otherwise, this value is false. This attribute is optional; the default value is false. This has been deprecated and the framework will not determine this automatically.

name

A unique identifier for this bean, which is used to reference it throughout the framework. This value is required and must be unique within a subapplication.

type

The fully qualified name of a Java class that extends the Struts ActionForm class. If this value is specified as org.apache.struts.action.DynaActionForm, Struts will dynamically generate an instance of the DynaActionForm. This attribute is required.

 

Be careful when configuring the value for the type attribute. It must be the fully qualified name of the ActionForm implementation class. If you misspell the name, it can be very hard to debug this problem.

As mentioned in Chapter 3, a form bean is a JavaBeans class that extends the org.apache.struts.action.ActionForm class. The following code shows how the form-beans element can be configured in the Struts configuration file:

<struts-config>
 <form-beans>
  <form-bean 
    name="loginForm"
    type="org.apache.struts.action.DynaActionForm">
      <form-property name="username" type="java.lang.String"/>
      <form-property name="password" type="java.lang.String"/>
  </form-bean>
   
  <form-bean 
    name="shoppingCartForm"
    type="com.oreilly.struts.order.ShoppingCartForm"/>
  </form-beans>
</struts-config>

One of the form-bean elements in this code uses a feature new in Struts 1.1, called dynamic action forms. Dynamic action forms were discussed briefly in Chapter 3 and will be discussed in detail in Chapter 7.

You can pass one or more dynamic properties to an instance of the org.apache.struts.action.DynaActionForm class using the form-property element. It is supported only when the type attribute of the surrounding form-bean element is org.apache.struts.action.DynaActionForm, or a descendant class.

Each form-property element also has four attributes that you can specify. Table 4-6 lists the attributes allowed in the form-property element.

Table 4-6. Attributes of the form-property element

Name

Description

className

If you don't want to use the standard configuration bean org.apache.struts.config.FormPropertyConfig, you can specify your own class here. This attribute is not required.

initial

A string representation of the initial value for this property. If not specified, primitives will be initialized to zero and objects to null. This attribute is not required.

name

The JavaBeans property name of the property being described by this element. This attribute is required.

type

The fully qualified Java class name of the implementation class of this bean property, optionally followed by "[ ]" to indicate that this property is indexed. This attribute is required.

The following form-bean fragment illustrates the use of the form-property element:

<form-bean
  name="checkoutForm"
    type="org.apache.struts.action.DynaActionForm">
    <form-property name="firstName" type="java.lang.String"/>
    <form-property name="lastName" type="java.lang.String"/>     
    <form-property name="age" type="java.lang.Integer" initial="18"/>    
  </form-bean>
4.7.2.3 The global-exceptions element

The global-exceptions section allows you to configure exception handlers declaratively. The global-exceptions element can contain zero or more exception elements:

<!ELEMENT global-exceptions (exception*)>

Later in this chapter, when action mappings are discussed, you will see that the exception element also can be specified in the action element. If an exception element is configured for the same type of exception both in the global-exceptions element and in the action element, the action level will take precedence. If no exception element mapping is found at the action level, the framework will look for exception mappings defined for the exception's parent class. Eventually, if a handler is not found, a ServletException or IOException will be thrown, depending on the type of the original exception. Chapter 10 deals with both declarative and programmatic exception handling in detail. This section illustrates how to configure declarative exception handling for your applications.

The exception element describes a mapping between a Java exception that may occur during processing of a request and an instance of org.apache.struts.action.ExceptionHandler that is responsible for dealing with the thrown exception. The declaration of the exception element illustrates that it also has several child elements:

<!ELEMENT exception (icon? display-name? description? set-property*)>

Probably more important than the child elements are the attributes that can be specified in the exception element. The attributes are listed in Table 4-7.

Table 4-7. Attributes of the exception element

Name

Description

className

The implementation class of the configuration bean that will hold the exception information. If specified, it must be a descendant of org.apache.struts.config.ExceptionConfig, which is the default class when no value is specified.

handler

The fully qualified Java class name of the exception handler that will process the exception. If no value is specified, the default class org.apache.struts.action.ExceptionHandler will be used. If a class is specified for this attribute, it must be a descendant of the ExceptionHandler class.

key

A message key that is specified in the resource bundle for this subapplication. This value is used by the ActionError instance.

path

The application-relative path of the resource to forward to if this exception occurs. This attribute is optional; the framework will default to the input attribute for the action mapping if no value is specified here.

scope

The identifier of the scope level where the ActionError instance should be stored. The attribute value must be either request or session. This attribute is optional and will default to request if not specified.

type

The fully qualified Java class name of the exception that is to be handled. This attribute is required because it identifies the exception, which can't be assumed by the framework.

bundle

The ServletContext attribute that identifies a resource bundle from which the key attribute of this element should come.

The following is an example of a global-exception element:

<global-exceptions>
  <exception
    key="global.error.invalidlogin"
    path="/security/signin.jsp"
    scope="request"
    type="com.oreilly.struts.framework.exceptions.InvalidLoginException"/>  
</global-exceptions>
4.7.2.4 The global-forwards element

Every action that is executed finishes by forwarding or redirecting to a view. This view is a JSP page or static HTML page, but might be another type of resource. Instead of referring to the view directly, the Struts framework uses the concept of a forward to associate a logical name with the resource. So, instead of referring to login.jsp directly, a Struts application may refer to this resource as the login forward, for example.

The global-forwards section allows you to configure forwards that can be used by all actions within an application. The global-forwards section consists of zero or more forward elements:

<!ELEMENT global-forwards (forward*)>

The forward element maps a logical name to an application-relative URI. The application can then perform a forward or redirect, using the logical name rather than the literal URI. This helps to decouple the controller and model logic from the view. The forward element can be defined in both the global-forwards and action elements. If a forward with the same name is defined in both places, the action level will take precedence.

The declaration of the forward element illustrates that it also has several child elements:

<!ELEMENT forward(icon?, display-name?, description, set-property*)>

As with the exception element, the attributes probably are more interesting than the child elements. The attributes for the forward element are shown in Table 4-8.

Table 4-8. Attributes of the forward element

Name

Description

className

The implementation class of the configuration bean that will hold the forward information. The default class is org.apache.struts.action.ActionForward when no value is specified. This attribute is not required.

contextRelative

Set to true to indicate that the resource specified in the path attribute should be interpreted as application-relative if the path starts with a "/" character. This is so the resource specified by the path attribute can reside in another subapplication. This attribute is not required; the default value is false.

name

A unique value that is used to reference this forward in the application. This attribute is required.

path

An application-relative (if the contextRelative attribute is false) or context-relative (if the contextRelative attribute is true) URI to which control should be forwarded or redirected. This attribute is required and must begin with a "/" character.

redirect

A Boolean value that determines whether the RequestProcessor should perform a forward or a redirect when using this forward mapping. This attribute is not required; the default value is false, which means that a forward will be performed.

The following is an example of a global-forwards element from the Storefront application:

<global-forwards>
 <forward name="Login" path="/security/signin.jsp" redirect="true"/>
 <forward name="SystemFailure" path="/common/systemerror.jsp"/>
 <forward name="SessionTimeOut" path="/common/sessiontimeout.jsp" redirect="true"/> 
 <forward name="Welcome" path="viewsignin"/>
</global-forwards>

The org.apache.struts.action.ActionForward class is used to hold the information configured in the controller element (discussed later). The ActionForward class now extends org.apache.struts.config.ForwardConfig for backward compatibility.

4.7.2.5 The action-mappings element

The action-mappings element contains a set of zero or more action elements for a Struts application:

<!ELEMENT action-mappings (action*)>

The action element describes a mapping from a specific request path to a corresponding Action class. The controller selects a particular mapping by matching the URI path in the request with the path attribute in one of the action elements. The action element contains the following child elements:

<!ELEMENT action (icon?, display-name?, description, set-property*, exception*, forward*)>

Two child elements should stand out in the list of children for the action element, because you've already seen them earlier in this chapter: exception and forward.

We talked about the exception element when we discussed the global-exceptions element. We mentioned then that exception elements could be defined at the global or at the action level. The exception elements defined within the action element take precedence over any of the same type defined at the global level. The syntax and attributes are the same, regardless of where they are defined.

We introduced the forward element when we discussed the global-forwards element. As with exception elements, a forward element can be defined both at the global level and at the action level. The action level takes precedence if the same forward is defined in both locations. The action element contains quite a few attributes, shown in Table 4-9.

Table 4-9. Attributes of the action element

Name

Description

attribute

The name of the request- or session-scope attribute under which the form bean for this action can be accessed. A value is allowed here only if there is a form bean specified in the name attribute. This attribute is optional and has no default value. If both this attribute and the name attribute contain a value, this attribute will take precedence.

className

The implementation class of the configuration bean that will hold the action information. The org.apache.struts.action.ActionMapping class is the default class when no value is specified. This attribute is optional.

forward

The application-relative path to a servlet or JSP resource that will be forwarded to, instead of instantiating and calling the Action class. The attributes forward, include, and type are mutually exclusive, and exactly one must be specified. This attribute is optional. org.apache.struts.actions.ForwardAction can be used to achieve the same behavior. This action is discussed in Chapter 5.

include

The application-relative path to a servlet or JSP resource that will be included with the response, instead of instantiating and calling the Action class. The attributes forward, include, and type are mutually exclusive, and exactly one must be specified. This attribute is optional. org.apache.struts.actions.IncludeAction can be used to achieve the same behavior. This action is discussed in Chapter 5.

input

The application-relative path to the input form to which control should be returned if a validation error is encountered. Required if the name attribute is specified. Not allowed if the name attribute is not specified.

name

The name of the form bean associated with this action. This value must be the name attribute from one of the form-bean elements defined earlier. This attribute is optional and has no default value.

path

The application-relative path to the submitted request, starting with a "/" character and without the filename extension if extension mapping is used. In other words, this is the name of the action—for example, /addToShoppingCart. This value is required. This attribute probably should have been called "name" because it really is the name of the action.

parameter

A general-purpose configuration parameter that can be used to pass extra information to the action instance selected by this action mapping. The core framework does not use this value. If you provide a value here, you can obtain it in your Action by calling the getParameter( ) method on the ActionMapping passed to the execute( ) method.

prefix

Used to match request parameter names to form bean property names. For example, if all of the properties in a form bean begin with "pre_", you can set the prefix attribute so the request parameters will match to the ActionForm properties. You can provide a value here only if the name attribute is specified.

roles

A comma-delimited list of security role names allowed to invoke this Action. When a request is processed, the RequestProcessor verifies that the user has at least one of the roles identified within this attribute. This attribute is optional.

scope

Used to identify the scope in which the form bean is placed—either request or session. This attribute can be specified only if the name attribute is present. The default value is session.

suffix

Used to match request parameter names to form bean property names. For example, if all of the properties in a form bean end with "_foo", you can set the suffix attribute so the request parameters will match to the ActionForm properties. You can provide a value here only if the name attribute is specified.

type

A fully qualified Java class name that extends the org.apache.struts.action.Action class. This attribute is used to process the request if the forward and include attributes are not specified. The attributes forward, include, and type are mutually exclusive, and exactly one must be specified.

unknown

A Boolean value indicating whether this action should be configured as the default for this application. If this attribute is set to true, this action will handle any request that is not handled by another action. Only one action mapping per application can have this value set to true. This attribute is optional and defaults to false. This is a good place to set up a default action that will catch any invalid action URL entered by the user. The name of this attribute would have been better as "default".

validate

A Boolean value indicating whether the validate( ) method of the form bean, specified by the name attribute, should be called prior to calling the execute( ) method of this action. This attribute is optional and defaults to true.

The following is an example of the "signin" action element from the Storefront application:

<action
  path="/signin"
  type="com.oreilly.struts.storefront.security.LoginAction"
  scope="request"
  name="loginForm"
  validate="true"
  input="/security/signin.jsp">
  <forward name="Success" path="/index.jsp" redirect="true"/>
  <forward name="Failure" path="/security/signin.jsp" redirect="true"/>
 </action>

The org.apache.struts.action.ActionMapping class is used to represent the information configured in the action element. The ActionMapping class extends org.apache.struts.config.ActionConfig for backward compatibility.

4.7.2.6 The controller element

The controller element is new to Struts 1.1. Prior to Version 1.1, the ActionServlet contained the controller functionality, and you had to extend that class to override the functionality. In Version 1.1, however, Struts has moved most of the controller functionality to the RequestProcessor class. The ActionServlet still receives the requests, but it delegates the request handling to an instance of the RequestProcessor. This allows you to declaratively assign the processor class and modify its functionality.

If you're familiar with Version 1.0, you'll notice that many of the parameters that were configured in the web.xml file for the controller servlet now are configured using the controller element. Because the controller and its attributes are defined in the struts-config.xml file, you can define a separate controller element for each subapplication. The controller element has a single child element:

<!ELEMENT controller (set-property*)>

The controller element can contain zero or more set-property elements and many different attributes. The attributes are shown in Table 4-10.

Table 4-10. Attributes of the controller element

Name

Description

bufferSize

The size of the input buffer used when processing file uploads. This attribute is optional; the default value is 4096.

className

The implementation class of the configuration bean that will hold the controller information. If specified, it must be a descendant of org.apache.struts.config.ControllerConfig, which is the default class when no value is specified. This attribute is not required.

contentType

The default content type and optional character encoding that gets set for each response. This attribute is not required; the default value is text/html. Even when a value is specified here, an action or a JSP page may override it.

debug

The debugging level for this application. The value is used throughout the framework to determine how verbose the logging information should be for events that take place internally. The larger the value, the more verbose the logging is. This attribute is not required; the default value is 0, which causes little or no logging information to be written out.

forwardPattern

A replacement pattern defining how the path attribute of a forward element is mapped to a context-relative URL when it starts with a slash (and when the contextRelative property is false). This value may consist of any combination of the following:

·         $A—Replaced by the application prefix of this subapplication

·         $P—Replaced by the path attribute of the selected forward element

·         $$—Causes a literal dollar sign to be rendered

·         $x (where x is any character not defined above)—Silently swallowed, reserved for future use

If not specified, the default forwardPattern is $A$P, which is consistent with previous hardcoded behavior of forwards.

inputForward

Set to true if you want the input parameters of action elements to be the names of local or global forward elements used to calculate the ultimate URLs. Set to false (the default) to treat the input parameters of action elements as subapplication-relative paths to the resources used for the input form.

locale

A Boolean value indicating whether the user's preferred locale is stored in the user's session if not already present. This attribute is not required; the default value is false.

maxFileSize

The maximum size (in bytes) of a file to be accepted as a file upload. This value can be expressed as a number followed by "K", "M", or "G" (interpreted to mean kilobytes, megabytes, or gigabytes, respectively). This attribute is not required; the default value is 250M.

multipartClass

The fully qualified Java class name of the multipart request-handler class to be used. This is used when uploading files from a user's local filesystem to the server. This attribute is not required; the default value is the DiskMultipartRequestHandler class in the org.apache.struts.upload package.

nocache

A Boolean value indicating whether the framework should set nocache HTTP headers in every response. This attribute is not required; the default value is false. Note that the letter "c" in nocache is lowercase. To be consistent with the other attributes shown here, it should have been noCache, but it's not.

pagePattern

A replacement pattern defining how the page attributes of custom tags using it are mapped to context-relative URLs of the corresponding resources. This value may consist of any combination of the following:

·         $A—Replaced by the application prefix of this subapplication

·         $P—Replaced by the value of the page attribute

·         $$—Causes a literal dollar sign to be rendered

·         $x (where x is any character not defined above)—Silently swallowed, reserved for future use

If not specified, the default forwardPattern is $A$P, which is consistent with previous hardcoded behavior of URL evaluation for page attributes.

processorClass

The fully qualified Java class name of the request-processor class to be used to process requests. The value specified here should be a descendant of org.apache.struts.action.RequestProcessor, which is the default value. This attribute is not required.

tempDir

Specifies the temporary working directory that is used when processing file uploads. This attribute is not required; the servlet container will assign a default value for each web application.

The org.apache.struts.config.ControllerConfig class is used to represent the information configured in the controller element in memory. The following fragment shows an example of how to configure the controller element:

<controller 
  contentType="text/html;charset=UTF-8"
  debug="3"
  locale="true"
  nocache="true"
  processorClass="com.oreilly.struts.framework.CustomRequestProcessor"/>
4.7.2.7 The message-resources element

The message-resources element specifies characteristics of the message resource bundles that contain the localized messages for an application. Each Struts configuration file can define one or more message resource bundles; therefore, each subapplication can define its own bundles. The message-resources element contains only a set-property element:

<!ELEMENT message-resources (set-property*)>

Table 4-11 lists the attributes supported by the message-resources element.

Table 4-11. Attributes of the message-resources element

Name

Description

className

The implementation class of the configuration bean that will hold the message-resources information. If specified, it must be a descendant of org.apache.struts.config.MessageResourcesConfig, which is the default class when no value is specified. This attribute is optional.

factory

The fully qualified Java class name of the MessageResourcesFactory class that should be used. This attribute is optional. The PropertyMessageResources class of the package org.apache.struts.util is the default.

key

The servlet context attribute with which this message resource bundle will be stored. This attribute is optional. The default value is specified by the string constant Action.MESSAGES_KEY. Only one resource bundle can be the default bundle.

null

A Boolean value indicating how the MessageResources subclass should handle the case when an unknown message key is used. If this value is set to true, an empty string will be returned. If set to false, a message that looks something like "???global.label.missing???" will be returned. The actual message will contain the bad key. This attribute is optional. The default value is true.

parameter

The base name of the resource bundle. For example, if the name of your resource bundle is ApplicationResources.properties, you should set the parameter value to ApplicationResources. This attribute is required. If your resource bundle is within a package, you must provide the fully qualified name in this attribute.

The following example shows how to configure multiple message-resources elements for a single application. Notice that the second element had to specify the key attribute, because only one can be stored with the default key:

<message-resources 
  null="false"
  parameter="StorefrontMessageResources"/>
<message-resources 
  key="IMAGE_RESOURCE_KEY" 
  null="false"
  parameter="StorefrontImageResources"/>
4.7.2.8 The plug-in element

The concept of a plug-in was added in Struts 1.1. This powerful feature allows your Struts applications to discover resources dynamically at startup. For example, if you need to create a connection to a remote system at startup and you didn't want to hardcode this functionality into the application, you can use a plug-in, and the Struts application will discover it dynamically. To use a plug-in, create a Java class that implements the org.apache.struts.action.PlugIn interface and add a plug-in element to the configuration file. The PlugIn mechanism itself will be discussed further in Chapter 9.

The plug-in element specifies a fully qualified class name of a general-purpose application plug-in module that receives notification of application startup and shutdown events. An instance of the specified class is created for each element; the init( ) method is called when the application is started, and the destroy( ) method is called when the application is stopped. The class specified here must implement the org.apache.struts.action.PlugIn interface and implement the init( ) and destroy( ) methods.

The plug-in element may contain zero or more set-property elements, so that extra configuration information may be passed to your PlugIn class:

<!ELEMENT plug-in (set-property*)>

The allowed attribute for the plug-in element is shown in Table 4-12.

Table 4-12. Attributes of the plug-in element

Name

Description

className

The fully qualified Java class name of the PlugIn class. It must implement the PlugIn interface.

The following fragment shows two plug-in elements being used:

<plug-in
  className="com.oreilly.struts.storefront.service.StorefrontServiceFactory"/>  
 
<plug-in 
  className="org.apache.struts.validator.ValidatorPlugIn">
  <set-property 
    property="pathnames" 
    value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>

The ValidatorPlugIn shown in the second plug-in element shows how the Struts framework initializes the Validator. The Validator framework is discussed in Chapter 11.

4.7.3 A Complete struts-config.xml File

Up to this point, you haven't seen a complete example of a Struts configuration file. Example 4-5 provides a complete listing.

Example 4-5. A complete Struts configuration file
<?xml version="1.0" encoding="UTF-8" ?>         
<!DOCTYPE struts-config PUBLIC
       "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
       "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">          
         
<struts-config>
 
 <data-sources>
  <data-source>
   <set-property property="autoCommit" value="true"/>
   <set-property property="description" value="Resin Data Source"/>
   <set-property property="driverClass" value="com.caucho.jdbc.mysql.Driver"/>
   <set-property property="maxCount" value="10"/>
   <set-property property="minCount" value="2"/>
   <set-property property="user" value="admin"/>  
   <set-property property="password" value="admin"/>
   <set-property 
     property="url" 
     value="jdbc:mysqlcaucho://localhost:3306/storefront"/>  
  </data-source>
 </data-sources>
 
 <form-beans> 
  <form-bean 
    name="loginForm" 
    type="com.oreilly.struts.storefront.security.LoginForm"/>        
  <form-bean 
      name="itemDetailForm"
      type="org.apache.struts.action.DynaActionForm">
      <form-property name="view" type="com.oreilly.struts.catalog.view.ItemView"/>        
  </form-bean>
 </form-beans>
 
 <global-exceptions>
  <exception 
   key="global.error.invalidlogin"
   path="/security/signin.jsp"
   scope="request"
   type="com.oreilly.struts.framework.exceptions.InvalidLoginException"/>  
 </global-exceptions>
 
 <global-forwards>
  <forward name="Login" path="/security/signin.jsp" redirect="true"/>
  <forward name="SystemFailure" path="/common/systemerror.jsp"/>
  <forward 
   name="SessionTimeOut" 
   path="/common/sessiontimeout.jsp" 
   redirect="true"/>
 </global-forwards>
 
 <action-mappings>
  <action
   path="/viewsignin"
   parameter="/security/signin.jsp"
   type="org.apache.struts.actions.ForwardAction"   
   scope="request"   
   name="loginForm"
   validate="false"
   input="/index.jsp">   
  </action>  
  <action
   path="/signin"
   type="com.oreilly.struts.storefront.security.LoginAction"
   scope="request"
   name="loginForm"
   validate="true"
   input="/security/signin.jsp">
   <forward name="Success" path="/index.jsp" redirect="true"/>
   <forward name="Failure" path="/security/signin.jsp" redirect="true"/>
  </action>   
  <action
   path="/signoff"
   type="com.oreilly.struts.storefront.security.LogoutAction"
   scope="request"   
   validate="false"
   input="/security/signin.jsp">
   <forward name="Success" path="/index.jsp" redirect="true"/>   
  </action>
  <action
   path="/home"
   parameter="/index.jsp"
   type="org.apache.struts.actions.ForwardAction"   
   scope="request"      
   validate="false">   
  </action>  
  <action
   path="/viewcart"
   parameter="/order/shoppingcart.jsp"
   type="org.apache.struts.actions.ForwardAction"   
   scope="request"      
   validate="false">   
  </action> 
  <action path="/cart"
   type="com.oreilly.struts.storefront.order.ShoppingCartActions"   
   scope="request"
   input="/order/shoppingcart.jsp"
   validate="false"
   parameter="method">
   <forward name="Success" path="/action/viewcart" redirect="true"/>
  </action> 
   <action
    path="/viewitemdetail"
    name="itemDetailForm"
    input="/index.jsp"
    type="com.oreilly.struts.storefront.catalog.GetItemDetailAction"   
    scope="request"      
    validate="false">   
    <forward name="Success" path="/catalog/itemdetail.jsp"/>
   </action> 
   <action
     path="/begincheckout"     
     input="/order/shoppingcart.jsp"
     type="com.oreilly.struts.storefront.order.CheckoutAction"   
     scope="request"
     validate="false">
     <forward name="Success" path="/order/checkout.jsp"/>
   </action>  
   <action
     path="/getorderhistory"     
     input="/order/orderhistory.jsp"
     type="com.oreilly.struts.storefront.order.GetOrderHistoryAction"   
     scope="request"
     validate="false">
     <forward name="Success" path="/order/orderhistory.jsp"/>
   </action>  
  </action-mappings>
  
 <controller 
  contentType="text/html;charset=UTF-8"
  debug="3"
  locale="true"
  nocache="true"
  processorClass="com.oreilly.struts.framework.CustomRequestProcessor"/>
  
 <message-resources 
  parameter="StorefrontMessageResources" 
  null="false"/>
 <message-resources 
  key="IMAGE_RESOURCE_KEY" 
  parameter="StorefrontImageResources" 
  null="false"/> 
 <plug-in
  className="com.oreilly.struts.storefront.service.StorefrontServiceFactory"/>  
 <plug-in
  className="org.apache.struts.validator.ValidatorPlugIn">
   <set-property 
     property="pathnames" 
     value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
 </plug-in>
</struts-config> 
 

4.7.4 Using Multiple Application Modules

Now that you've seen how to configure the default application for Struts, the last step is to discuss how you include multiple application modules. With Struts 1.1, you have the ability to set up multiple Struts configuration files. Although the application modules are part of the same web application, they act independently of one another. You also can switch back and forth between subapplications if you like.

Using multiple application modules allows for better organization of the components within a web application. For example, you can assemble and configure one application module for everything that deals with catalogs and items, while another module can be organized with the configuration information for a shopping cart and ordering. Separating an application into components in this way facilitates parallel development.

The first step is to create the additional Struts configuration files. Suppose we created a second configuration file named struts-order-config.xml. We must modify the web.xml file for the application and add an additional init-param element for the new module. This was shown earlier in the chapter, but it's repeated here for convenience. Example 4-6 shows the servlet instance mapping from before with an additional init-param for the second Struts configuration file.

Example 4-6. A partial web.xml file that illustrates how to configure multiple subapplications
<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>config/order</param-name>
   <param-value>/WEB-INF/struts-order-config.xml</param-value>
  </init-param>
 
  <load-on-startup>1</load-on-startup>
 </servlet>

Notice that the param-name value for the nondefault application module in Example 4-6 begins with config/. All nondefault application modules' param-name elements must begin with config/; the default application's param-name element contains the config value alone. The part that comes after config/ is known as the application module prefix and is used throughout the framework for intercepting requests and returning the correct resources.

With the current version of the Struts framework, only extension mapping is supported when using multiple application modules. Path mapping is not yet supported.

Pay special attention to the configuration attributes available in the various Struts XML elements. Some of them, as mentioned in this chapter, have a profound effect on how an application operates in a multiapplication module environment.

4.7.5 Specifying a DOCTYPE Element

To ensure that your Struts configuration file is valid, it can and should be validated against the Struts DTD. To do this, you must include the DOCTYPE element at the beginning of your Struts configuration XML file:

<?xml version="1.0" encoding="ISO-8859-1" ?>
 
<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

In earlier versions of the framework, there were some issues with applications not being able to start up if they couldn't get to the Jakarta site and access the DTD from there. This is no longer the case, as Struts now provides local copies of the DTDs.

Some users prefer to specify a SYSTEM DOCTYPE tag, rather than a PUBLIC one. This allows you to specify an absolute path instead of a relative one. Although this may solve a short-term problem, it creates more long-term ones. You can't always guarantee the directory structure from one target environment to another. Also, different containers act differently when using a SYSTEM DOCTYPE tag. You probably are better off not using it. However, if you decide that you need to do so, it should look something like the following:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config SYSTEM "file:///c:/dtds/struts-config_1_1.dtd">
 
<struts-config>
  <!--The rest of the struts configuration file goes next -->

As you can see, the location of the DTD is an absolute path. If the path of the target environment is not the same, you'll have to modify the XML file. This is why this approach is not recommended.