ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


JSP and Servlets Learning the New Jakarta Struts 1.1, Part 2

by Sue Spielman
11/13/2002

Editor's Note: This is part two of a two-part series on Jakarta Struts 1.1. The first part is available here. Portions of this article are excerpted from Sue Spielman's book, The Struts Framework: Practical Guide for Java Programmers (Morgan-Kaufmann), one of the first books on the market covering Struts 1.1 in detail. You can reach Sue at .

Nested Tag Library

The whole point of having nested tags is that the tags can relate to each other and describe the structure of the model they're managing. The assumptions made by the tags simplify the necessary coding. Struts 1.0 developers can heave a sigh of relief knowing that they won't have to mangle code any longer to render a display of a list within a list.

The Struts nested tag library was introduced in Struts 1.1. Almost all of the tags in this library extend the base Struts tags that we've already talked about. This includes tags from the Html and Logic libraries, except they are prefixed with a nested namespace. So, for example, if we are nesting an <html:link> tag, we would use <nested:link> instead. There are also tags new to the nested tag library. The new tags include <nested:root> and <nested:nest>. The <nested:root> tag is used to indicate that you are starting a nested scope. This tag is used if <html:form> is not being used. The <html:form> (for backwards compatibility) or <nested:form> tags will automatically start a scope for you.

The difference between using non-nested tags as opposed to those from the nested library is that using the nested version allows the tags to relate to each other in a nested hierarchy. The fundamental logic of the original tags doesn't change, except that all references to beans and bean properties will be managed in a nested context using the dot notation that we have already seen when using properties. When building complex pages, it is highly likely that you will want to use the nested features. This makes pages much easier to write and maintain, since it allows for the logical flow to be maintained without having to do work-arounds, as was required before the 1.1 release.

Related Reading

Programming Jakarta Struts
By Chuck Cavaness

Validator

The Validator framework is now part of the Struts package structure and can be found in org.apache.struts.validator. Why use the Validator framework? Validator makes life a bit easier when you have to deal with required fields; determining matches to a regular expression; email, credit card, and date validation; and server-side type checking. This framework is based on the Commons Validator that can be found at jakarta.apache.org/commons.

The purpose is to perform server-side validations based on validation rules located in validation.xml. It is possible to add custom validations to this file. Rules can be defined for different locales. It's possible to store your specific Validator rules in a separate file. This is accomplished by setting the config-rules parameter in the ValidatorServlet contained in the web.xml file. The standard file is available in the Struts dist directory and is called validator-rules.xml.

Using this framework requires adding the ValidatorServlet to your web.xml file with its appropriate configuration parameters and then extending org.apache.struts.validator.action.ValidatorForm instead of org.apache.struts.action.ActionForm.

Validator is the first component to implement the new PlugIn interface in Struts 1.1, which we'll talk about next.

You can also add pluggable Validators by adding a validation method signature to your ValidatorAction class. For more details, see the org.apache.struts.validator.util.StrutsValidator class.

PlugIn API

A new feature of Struts 1.1 is the ablity to define a PlugIn. A PlugIn is a configuration wrapper for an application-specific module or service that must be notified about application startup and application shutdown events. These events correspond to the container calls init() and destroy() on the corresponding ActionServlet instance, which allows a module to be called without the need to subclass ActionServlet for simple Servlet lifecycle activities.

PlugIn modules can be configured in the struts-config.xml file, using the <plug-in> element. Classes that implement the PlugIn interface must supply a zero-argument constructor for use by ActionServlet. Configuration can be accomplished by providing standard JavaBeans property setter methods that will all have been called before the init() method was invoked. An instance of the specified class is created for each element, and can be configured with nested set-property elements. For example, in struts-config.xml we might have the last entry defined as:

<plug-in className="org.apache.struts.validator.action.ValidatorPlugIn">
   <set-property property="pathname" value="/WEB-INF/validator-rules.xml"/>
   <set-property property="pathname" value="/WEB-INF/validation.xml"/>
</plug-in>

This means that two instances of the ValidatorPlugIn will be created, each setting the property pathname to the appropriate value. By supporting the init() and destroy() methods of PlugIn, the ValidatorPlugin is notified about application startup and shutdown events without having to be concerned with extending ActionServlet code. PlugIns are configured in the struts-config.xml file by setting the plug-in element.

Declarative Exception Handling

Declarative exception handling allows for Actions to propagate exceptions. This feature is the very reason that the perform() method signature changed from throwing IOException and ServletException to just Exception. This is also why we see the execute() method of an Action called by the ActionServlet. One reason for going this route is so your Actions don't have to think about each and every exception that might be thrown from your business logic. It also allows exceptions to be configured within the struts-config.xml file.

Declarative exception handling is accomplished in two ways. One is by configuring <global-exceptions> in the struts-config.xml file. The other is by using the exception element of <action>, which describes a mapping of an exception that may occur during Action delegation.

The way that the exceptions are declared is very similar to the way that <global-forwards> and <forwards> are declared. A <global-exceptions> configures the global handling of exceptions thrown by Actions to mappable resources using an application-relative URI path. This can be a specific page designed to handle this exception.

It is also possible to override an exception handler declared in the global setting by using the exception element in the action, which uses the same type attribute as defined in the global setting. You can specify the className attribute, which indicates the implementation subclass of the standard configuration bean. The default class is:

org.apache.struts.config.ExceptionConfig

The handler attribute is the fully-qualified Java class name of the exception handler that should handle this exception. The default is org.apache.struts.action.ExceptionHandler. The key attribute is the message resources key specifying the error message associated with this exception. This is helpful in keeping your errors friendly when your application is internationalized.

The path attribute is the application-relative path of the resource to forward to if this exception occurs. The scope attribute can be set to either request or session, and indicates where the ActionError will be made available. Last but not least is the type attribute. This is the fully-qualified Java class name of the exception to be handled. (What a mouthful.) Here's a sample:

In struts-config.xml, we first declare our <global-exceptions> in the following format:

<global-exceptions> 
   <exception key="error.required" type="org.apache.struts.util.AppException"
              path="/appError.jsp"/>
</global-exceptions>

Here we are declaring that any Action (or business logic) that throws the AppException will be sent to appError.jsp. We are associating the error.required message string from our ApplicationResource file with this exception. The ApplicationResource file is discussed in detail in Chapter Nine of my book, The Struts Framework: Practical Guide for Java Programmers (2002, Morgan-Kaufman), when we talk about internationalization. If you view the mainMenu.jsp file in our sample application, there is a link to force an application exception. This makes it easier for you to quickly force an error exception and to follow the flow in the ForceErrorAction.java file. You can add as many <exception> elements to the <global-exceptions> as you like.

Next we'll look at a specific Action exception declaration.

<action   path="/insert"
  ...
  <exception
     key="error.required"
     type="cdmanager.exceptions.MissingValueException"
     path="/insertError.jsp"/>
</action>

In this case, we are declaring that if the InsertAction (or business logic used by the InsertAction) throws the application-specific exception MissingValueException, then send the exception to insertError.jsp. Note that in this example, we have defined a specific application exception. This is helpful if you want to wrap other, less helpful exceptions. For example, you might want to catch SQLExceptions and re-throw them as application-specific exceptions with a more meaningful message to the user.

It is also worth pointing out that matching exceptions to exception handlers takes inheritance into account (i.e., you can declare a handler for a superclass and handle all of the exceptions for subclasses of that exception class as well.) The matching algorithm works identically to the one used by the servlet container to select <error-page> matches for exceptions.

Upgrading From Struts 1.0.2

If you are upgrading an existing Struts application to v1.1, you should not have that many worries. The development team did a very good job of keeping Struts backwards-compatible. For all intents and purposes, you should have little trouble upgrading to v1.1. While each application is different, here are some general rules of thumb to use when evaluating your application.

Related Reading

JavaServer Pages
By Hans Bergsten

Package Names

Many of the Struts util packages have been moved to Jakarta Commons, so you may need to adjust some package names in your code. This should be as simple as a global find and replace.

Request Routing

In order for this sub-app feature to work, any request for a presentation page that uses elements from the configuration file, including ActionForms, Forwards, and Action Mappings, must be routed through the controller. This allows the controller to make the appropriate configuration available for a given page. Having requests pass through the controller is not new to Struts 1.1. While it might have been possible to bypass this by having direct linking to pages, it is good design practice to make sure everything flows through the controller. When using the MVC model, this is the way it should be, anyway. Many other features in advanced applications, including security and logging, are easier to implement when everything passes through the controller.

Perform Vs. Execute Methods

In Struts 1.x, Action.perform() is the method called by the ActionServlet. This is typically where your business logic resides, or at least the flow control to your JavaBeans and EJBs that handle your business logic. As we already mentioned, to support declarative exception handling, the method signature changed in perform. Now execute just throws Exception. Action.perform() is now deprecated; however, the Struts v1.1 ActionServlet is smart enough to know whether or not it should call perform or execute in the Action, depending on which one is available.

Changes to Build Files

If you are building with ANT, you might need to adjust your build.xml to include the Jakarta Commons library files. To make sure you don't run into classloader issues, check the struts-user mailing list if your container is having problems.

Other Things to Watch For

I've taken Struts v1.x applications and run them within minutes on Struts v1.1. However, there are a couple of things that you should be aware of if you've taken advantange of some of the more advanced features. For example, the ApplicationConfig object is used now to handle Servlet context attributes per sub-application. This means that if you are using information from any of the various objects in Struts that handle your application collections, like ActionFormBeans, ActionForwards, or ActionMappings, you'll need to reference them through ApplicationConfig. Also, if you have done any ActionServlet-specific work for your ActionServlet, you might want to take a look at the changes that have taken place regarding the RequestProcessor class.

Conclusion

Struts v1.1 offers us some new and exciting features for Web application development. You should be able to start taking advantage of them as soon as you're done with this article.

Sue Spielman is an associate editor for ONJava.com, covering JSP and Servlets technologies. She is also President and Senior Consulting Engineer for Switchback Software LLC.


Read more JSP and Servlets columns.

Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.