Page 2 of 4
Error categorization
Problem
Error handling becomes complex for an n-tiered application. In a browser-based application, the errors can be handled in the client layer using JavaScript and in the Web tier or EJB (Enterprise JavaBeans) tier using custom Java methods. Building an infrastructure for consistent error reporting proves more difficult than error handling. Struts provides the ActionMessages/ActionErrorsclasses for maintaining a stack of error messages to be reported, which can be used with JSP tags like <html: error> to display these error messages to the user. The problem is reporting a different category/severity of the message in a different manner (like error, warning, or information). To do that, the following tasks are required:
Register the errors under the appropriate category
Identify these messages and show them consistently
Struts best practice
Struts' ActionErrors class comes in handy in resolving the first issue of stacking messages of different categories. To display the error messages of different categories, define these categories such as FATAL, ERROR, WARNING, or INFO, in an interface. Then, in the Action or form-bean class, you can use:
errors.add("fatal", new ActionError("....")); or
errors.add("error", new ActionError("....")); or
errors.add("warning", new ActionError("....")); or
errors.add("information", new ActionError("...."));
saveErrors(request,errors);
Having stacked the messages according to their category, to display them according to those categories, use the following code:
<logic:messagePresent property="error">
<html:messages property="error" id="errMsg" >
<bean:write name="errMsg"/>
</html:messages>
</logic:messagePresent >
Or use:
<logic:messagePresent property="error">
<html:messages property="error" id="errMsg" >
showError('<bean:write name="errMsg"/>'); // JavaScript Function
</html:messages>
</logic:messagePresent >
Validation of service requester: Login-check
Problem
Authentication in a Web-based application can be done in any class, depending upon whether an SSO-based (single sign-on) or a JAAS-based (Java Authentication and Authorization Service) mechanism is being used. The challenge is identifying the placeholder for checking the service requester's authenticity and the user session's validity.
Struts best practice
Usual practice is to store user credentials in HttpSession after authentication. Subsequent calls check credentials' existence in session context. The question is where to place these checks. Some options are listed below, but they must be rationalized on the basis of performance overhead, possibility of future changes, and application manageability:
Authenticate against the session context before doing any operation (as done in Struts-example.war's CheckLoginTag.java)
Authenticate against session context in the Action class
Write servlet request filters that perform authentication
Extend RequestProcessor
The first two options require every JSP page or the Action class to perform the authentication against the session context. Change in the interface mandates change in all these JPS pages and classes. The third option is efficient, but overkill for the problem at hand.
The best practice is to extend the RequestProcessor class and perform authentication in methods such as processActionPerform() or processRoles().
Application security
Problem
The usual demand in Web-based applications is to have screen-level, function-level, data-row-level, and field-level security. If not suitably designed, incorporation of these security levels in an application may cause not only performance overheads, but also maintenance nightmares.
For all the security types mentioned above, the preferred approach is to place the security check in one class instead of in every component—i.e., in every JSP page or Action class.
Struts has a method processRoles() for screen- and function-level security checks, however nothing is provisioned for field- and column-level security types, making it the most challenging for most Struts users.
Struts best practice
Irrespective of where the security realm is set up (database or directory service), the best practices for the various security levels are described below:
For screen- and function-level security, extend RequestProcessor and override the method processRoles() to perform the check against a HashMap that stores a mapping of roles and screen IDs/function IDs
Row-level security is best implemented in the application's object relational mappings
For field-level security, tag libraries are extended to perform the check against the field ID