Data transfer object implementation
Usually a data transfer object (DTO) is used for shuttling data between the Web and EJB tiers. It is not a good idea to pass the view-helper class (form bean, in the case of Struts), to the EJB tier, primarily because all of the form bean's fields are of type string. A separate class should be used as the data transfer object. The problem is how to transfer the data from the form bean to the DTO.
Struts best practice
Two options are available for populating the data transfer object:
- Create the transfer object and copy the data from the form bean to the transfer object. Data-type conversions must be handled before data copying. Similarly, on the way back, you must repeat the same exercise of copying the data from the DTO to the form bean.
- Use Commons'
BeanUtilsclass, which uses the Reflection API to achieve its objectives.
Developers frequently use the first option, which is not problematic except that the mundane exercise is repeated every time, resulting in bulky and ugly code. While copying data, suitable data-type conversion must be hand-coded in the DTO's setter methods, so that when data is copied from the form bean to the DTO, it converts to the appropriate business type. All the attributes of type string in the form beans are the primary reasons for data-type conversions.
You can avoid all this coding by using
copyProperties() method. The method copies the data from one bean to another, provided the variable names of the business attributes in the value/transfer object are the same as the ones in the form bean. The method also relieves you from data-type conversion by transparently converting source-bean attribute types to destination-bean attribute types.
As a generic principle, errors should be caught right where they occur to display meaningful error messages. To implement this principle, programmers must write their own custom exception classes, wrap the actual exception into these custom classes, and throw them back to the place where they are handled. In a Struts-based application, the exceptions thrown from the EJB/Web tier are handled either in the
Action class or the form bean. The usual practice involves writing a try-catch block to catch these exceptions in the
Action class or the form bean, and creating an
ActionError object with user-friendly messages derived from the application property file. The decision to direct these error messages to the screen is coded in the action classes, using the
You must code all this exception-handling code in the
Action class as well as the decision to direct the message to the screen. If the error-handling strategy changes, then every
Action or form bean requires changes.
Struts best practice
Struts deals with the issue of exception handling in a competent way, using declarative exception handling. This, as opposed to programmatic exception handling (as explained above) handles issues using the
processException() method and a Struts configuration file. To use declarative exception handling, you must do the following:
- Create custom application exception classes. You can design them so they hold more than one exception
- In the EJB/Web tier, trap application errors and wrap them into a custom exception class and throw them back
- In the
struts-config.xmlfile, add the localized exception against an action-mapping or define a global exception (as shown below):
A clear strategy for the relationship between JSP pages and
Action classes in an application should be defined; i.e., how many JSP pages should be associated with an
For clarity and easy maintenance, the strategy for large applications should be to have one-to-one mapping between JSP pages and
Action classes. With such a guideline in place, a prospective problem of duplicated code in the
Action classes could result. To avoid logic duplication, you need some way to call an
Action class's method from another
Action class. Moreover for criss-cross page flow, you often need action chaining, or, to summarize, an implementation of the Chain of Responsibility design pattern.
Struts best practice
Possible solutions follow below:
ActionForwardspoint to a fresh request in the same application to invoke the method of another
HashMapthat stores all the instances of
Actionclasses for that module. Extend the
RequestProcessorclass and provide getter methods for this
HashMap. Provide a utility method in the application's parent
Actionclass, which can invoke the methods of other
Actionclasses within the same module. This utility method will use the Reflection API to achieve this.
The second approach is the best practice for large applications because if some change is required in exception handling, no code change will be required.
Large applications built using the above recommendations have been benchmarked for excellent performance.
As indicated by the Struts roadmap (featured on the Struts Website), features and extensions developed on sourceforge.net and those commonly used by the Struts community are candidates for inclusion into Struts per se. All these are worth reading about before you make critical decisions about your application.