The Request Processing Engine
Struts uses its request processing engine to perform the processing for all requests received by the ActionServlet. The request processing engine takes each request and breaks its processing down into several small tasks. This approach allows each individual part of the request processing cycle to be customized.
In version 1.3, a new request processing engine was introduced that is built on top of the Jakarta Commons Chain library (http://jakarta.apache.org/commons/chain/). Previous versions of Struts performed all of the request processing in a single class named org. apache.struts.action.RequestProcessor. Both of these request processing methods are described separately in the following sections.
Jakarta Commons Chain-Based Request Processing
The RequestProcessor class-based processing originally used in Struts (and described in the following eponymously named section) provided a nice abstraction for each part of the request processing cycle; however, it had its limitations. The principal limitation was that customization of the request processing cycle required subclassing the RequestProcessor class. This subclassing precluded multiple independent customizations to be created and used together because there was not a way to tie the assorted customizations back together. Because of this, Commons Chain is now being utilized by Struts to further abstract the processing of requests and solve the problem of having multiple customizations.
The Commons Chain library provides an implementation of the Chain of Responsibility (COR) pattern described in the seminal Design Patterns book by the Gang of Four. The COR pattern models a computation as a series of commands that are combined into a chain. Chains represent the entire computation, while commands represent discrete pieces of the computation. Each command in a chain is executed in succession until all commands in the chain have been executed or until a command returns a flag indicating that execution is complete for the chain. This pattern of processing is essentially what was implemented in the Struts RequestProcessor class. However, the RequestProcessor class did not provide a mechanism for introducing new commands into (or removing commands from) its chain. Additionally, the list of steps and the order of the steps of processing in the RequestProcessor class is hard-coded and cannot be changed without subclassing RequestProcessor. Commons Chain allows commands to be easily added or removed by abstracting the definition of chains into an XML configuration file.
In converting to Commons Chain, each of the processing methods of the RequestProcessor class was moved to its own command class and all of the commands were wired together into a chain. The chain definition is stored in the default Struts Chain configuration file, chain-config.xml, that is stored in the Struts Core .jar file (e.g., struts-core-1.3.5.jar) in the org\apache\struts\chain directory. To add or remove commands from the default chain configuration, the Chain configuration file must be modified. Because the Chain configuration file is stored in the Struts Core .jar file, it is cumbersome to update that file. Instead, a new Chain configuration file should be created. The default Chain configuration file can be used as a template and then any changes can be made. Once the new Chain configuration file is created, Struts must be configured to use it as shown in the following example:
<servlet>
<servlet-name>action</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>chainConfig</param-name>
<param-value>/WEB-INF/chain-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Like the Struts configuration file, the Chain configuration file is specified with an initialization parameter to the Struts ActionServlet. The initialization parameter is named chainConfig and its value is the path to the Chain configuration file.
RequestProcessor Class-Based Processing
As stated, in versions of Struts prior to version 1.3, the RequestProcessor class was used to handle all request processing. The RequestProcessor class uses a separate method to carry out each request processing task. Each of the separate methods is aptly named with a prefix of process; for example, processMultipart( ) and processPath( ).
Table 5-1 lists and describes briefly each of the process*( ) methods from the RequestProcessor class (in the order they are executed).
Method | Description |
---|---|
processMultipart( ) | Wraps multipart requests with a special wrapper class. |
processPath( ) | Determines the path that will be used to select an action to which processing is delegated. |
processLocale( ) | Saves the user's locale in session scope. |
processContent( ) | Sets the default content type for the response. |
processNoCache( ) | Sets no-cache HTTP headers for the response if necessary. |
processPreprocess( ) | Provides a hook for subclasses to override. It is used to tell the request processor whether or not to continue processing the request after this method has been called. |
processCachedMessages( ) | Removes cached ActionMessage objects from the session so that they are available only for one request. |
processMapping( ) | Selects the action mapping to use for the request. |
processRoles( ) | Checks if the current user has a role that is allowed to access the requested resource. |
processActionForm( ) | Creates a new Form Bean or retrieves one from the session for the request. |
processPopulate( ) | Populates the Form Bean returned from processActionForm( ) with data from the incoming request. |
processValidate( ) | Invokes the validate( ) method on the Form Bean returned from processActionForm( ) if necessary. |
processForward( ) | Processes the forward for the action mapping matching the current request path, if the matching mapping is specified to be a forward. |
processInclude( ) | Processes the include for the action mapping matching the current request path, if the matching mapping is specified to be an include. |
processActionCreate( ) | Creates or recycles an existing action to process the current request. |
processActionPerform( ) | Invokes the execute( ) method on the action returned from processActionCreate( ). |
processForwardConfig( ) | Forwards to the forward returned from processActionPerform( ). |
By having each phase of the request processing cycle take place in a separate method, request processing can easily be customized. Simply create a custom request processor that extends the base RequestProcessor class and override the methods that need to be customized. For example, a custom request processor can apply a logged-in security check before any action is executed. The RequestProcessor class provides the processPreprocess( ) method hook expressly for this. The processPreprocess( ) method is called before actions are executed. The following example shows how to do this:
package com.jamesholmes.minihr;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.RequestProcessor;
public class LoggedInRequestProcessor extends RequestProcessor
{
protected boolean processPreprocess(
HttpServletRequest request,
HttpServletResponse response)
{
// Check if user is logged in.
// If so return true to continue processing,
// otherwise return false to not continue processing.
return (true);
}
}
To use a custom request processor, you have to configure Struts to use it in the Struts configuration file:
<controller processorClass="com.jamesholmes.minihr.LoggedInRequestProcessor"/>
Note | When using the Struts module feature, each module has its own request processor. Thus, if you want to apply a custom request processor to all modules, you must configure it in each module's Struts configuration file. |
No comments:
Post a Comment