Earlier in this chapter, we saw that the validate( ) method returned an ActionErrors object. The ActionErrors class encapsulates one or more errors that have been discovered by the application. Each problem discovered is represented by an instance of org.apache.struts.action.ActionError.
An ActionErrors object has request scope. Once an instance is created and populated by the validate( ) method, it is stored into the request. Later, the JSP page can retrieve the object from the request and use the ActionError objects contained within it to display error messages to the user.
|
An instance of ActionErrors can be instantiated in the validate( ) method and populated by adding instances of the ActionError class to it. The LoginForm from Example 7-2 demonstrated this and is illustrated again here for convenience:
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request){
ActionErrors errors = new ActionErrors( );
if( getEmail() == null || getEmail().length( ) < 1 ){
errors.add("email", new ActionError("security.error.email.required"));
}
if( getPassword() == null || getPassword().length( ) < 1 ){
errors.add("password", new ActionError("security.error.password.required"));
}
return errors;
}
The validate( ) method in this fragment checks to make sure that the email and password fields have been set with values other than an empty string. If not, ActionError objects are added to the ActionErrors instance.
The ActionError class contains several useful constructors; a few are listed here:
public ActionError(String key);
public ActionError(String key, Object value0);
public ActionError(String key, Object value0, Object value1);
public ActionError(String key, Object[] values);
The key argument is a String value that corresponds to a key from one of the application's resource bundles. The custom tag ErrorsTag uses this value to look up the message to display to the user. The remaining arguments are used as parametric replacement values for the message. For example, if you had a bundle message defined like this:
global.error.login.requiredfield=The {0} field is required for login
you could create an instance of an ActionError like this:
ActionError error = new ActionError("global.error.login.requiredfield", "Email");
The message displayed to the user after substituting in the "Email" string would be:
The Email field is required for login
When adding instances of the ActionError class to the ActionErrors object, the first argument in the add( ) method is a property that can be used to retrieve a specific ActionError instance. For example, if you have a login input field and a password field and you want to display a particular message next to each corresponding field, you could do:
errors.add("login",
new ActionError("security.error.login.required"));
errors.add("password",
new ActionError("security.error.password.required"));
By associating a specific name with each error, you can retrieve the respective error in the JSP page using the ErrorsTag tag, which we'll discuss in the next chapter.
If instead you want to show all of the errors at the top of the page, you can use the constant ActionErrors.GLOBAL_ERROR, like this:
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("security.error.password.required"));
In Struts 1.1, a new message class was added that also can be used to display messages to a user. The org.apache.struts.action.ActionMessage class operates in the same manner that the ActionError class does—in fact, it was added as the superclass to the ActionError class.
The main reason that the ActionMessage class was added to the framework was that the name ActionError implies that it shouldn't be used for general-purpose informational or warning messages, although it is used that way by many developers. A more general-purpose message class made sense.
The ActionMessage is used exactly like the ActionError class, except that it can represent a less severe message that needs to be displayed to the user. Instances of this class are created the same way and added to an ActionMessages object instead of an ActionErrors object. Because ActionError is just a specialized message, it extends the ActionMessage class. Figure 7-5 illustrates the relationship between these classes.
The ActionForm is not the only place that you can create ActionMessages or ActionErrors. You also can create them in other parts of the framework. If, for example, a business operation called from an Action raised an exception and you wanted to insert an error message informing the user, you could create an ActionError from the Action class itself. The Struts Action class includes functionality to support this.
When the business operation throws the exception, the Action class catches it and takes the appropriate steps—usually returning to the previous page and displaying an error message to the user. Returning to the previous state can be accomplished by returning the appropriate ActionForward, but the ActionError needs to be put in the request before the forward occurs.
|
Example 7-4 illustrates how to put the ActionError into the request using the LoginAction class.
public ActionForward execute( ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response )
throws Exception{
/**
* Get the user's email and password, which should already have been
* validated by the ActionForm.
*/
String email = ((LoginForm)form).getEmail( );
String password = ((LoginForm)form).getPassword( );
// Log in through the security service
IStorefrontService serviceImpl = getStorefrontService( );
UserView userView = null;
try{
userView = serviceImpl.authenticate(email, password);
}catch( InvalidLoginException ex ){
ActionErrors errors = new ActionErrors( );
ActionError newError = new ActionError( "security.login.failed" );
errors.add( ActionErrors.GLOBAL_ERROR, newError );
saveErrors( request, errors );
// Return back to the previous state
return mapping.findForward( mapping.getInput( ) );
}
// Authenticate was successful
UserContainer existingContainer = null;
HttpSession session = request.getSession(false);
if ( session != null ){
existingContainer = getUserContainer(request);
session.invalidate( );
}else{
existingContainer = new UserContainer( );
}
// Create a new session for the user
session = request.getSession(true);
existingContainer.setUserView(userView);
session.setAttribute(IConstants.USER_CONTAINER_KEY, existingContainer);
return mapping.findForward(IConstants.SUCCESS_KEY);
}
}
In Example 7-4, when an InvalidLoginException is thrown by the authenticate( ) method, the exception is caught and an ActionError is created. The saveErrors( ) method exists in the Struts base Action class and stores the ActionErrors object into the request. A corresponding saveMessages( ) method also exists for a similar purpose.
Once the ActionError or ActionMessage is stored in the request and control is forwarded to a JSP page, one of the framework's JSP custom tags can be used to print out the messages to the user. These tags are discussed in the next chapter.