Our Sites:  Tutorial Buzz  |  How To Tree  |  Recipe Voice  |  Golf Twist  |  DIY Click  |  Movie Lizard  |  Halloween Twist  
Search:
Submit Link
Mail to a Friend
RSS FeedReceive updates via our RSS feed

Apache Struts MVC Design Pattern

A sample from
Beginning Apache Struts: From Novice to Professional

by Arnold Doray

Servlet technology is the primary base on which you can create web applications with Java. JavaServer Pages (JSP) technology is based on servlet technology but extends it by allowing HTML content to be created easily.

Note that JSP technology doesn’t replace servlet technology, but rather builds on it, to address some of its deficiencies. Struts follows this pattern, and builds on servlet and JSP technologies to address their shortcomings. These shortcomings are in two broad areas:

  • Creating a “separation of concerns”: Pieces of code that do different things are bundled separately and given standardized ways of communicating between themselves.
  • An infrastructure for webapps: This includes things like validating user input, handling and reporting errors, and managing flow control.

If these shortcomings are addressed, the very practical problems of building webapps (robustness, maintainability, localization, etc.) become easier to tackle.

One tool that can be used to make some headway in resolving these issues is an organizing principle called the Model-View-Controller (MVC) design pattern.

WHAT ARE DESIGN PATTERNS?

Design patterns are essentially recipes for solving generic coding problems. They are not algorithms but rather organizational principles for software.

The idea of using “design patterns” to solve common software engineering problems first came to prominence with the book Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional, 1995), by, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. The authors credit an earlier work, A Pattern Language for Building and Construction (Oxford University Press, 1977) by the architect Christopher Alexander as the inspiration for the idea of design patterns for software.

The MVC design pattern, which is the subject of this chapter, was first used in an AI language called Smalltalk in the 1980s to solve a problem similar to the one we’re discussing here for webapps. A variation on the pure MVC pattern is also used in Swing, Java’s platform-independent GUI toolkit.

The MVC design pattern calls for a separation of code by their function:

  • Model: Code to control data access and persistence
  • View: Code to handle how data is presented to the user
  • Controller: Code to handle data flow and transformation between Model and View

Figure 5-1 illustrates MVC.


Figure 5-1. The MVC design pattern

In addition to this separation, there are a couple of implicit constraints that the Model, View, and Controller code follow:

  • The View gets data from the Model only through the Controller.
  • The Controller communicates with the View and Model through well-defined, preferably standardized ways. For example, embedding SQL code directly in your Controller code violates this principle of standardized communication. Using Model classes that expose functions for data access would be an example of standardized communication between the Controller and the Model.

It may not be immediately obvious to you how this solves anything, but I hope you’ll come to appreciate the power of the MVC approach as you progress. For now, it is sufficient for you to accept that applying the MVC design pattern helps us achieve the larger goal of separation of concerns, which greatly simplifies the building of web applications.

Our discussion so far has been quite general for a purpose. Any web application framework will use the MVC principle, so it is to your advantage to understand it apart from Struts’ implementation of it.

Later, we’ll discuss how Struts implements the MVC design pattern. But before we do, I’ll give you an example of how to apply the MVC design pattern.

The Registration Webapp
Many web applications have a “user registration” facility. I’m sure you’ve seen this before. Some online news sites, for example, have the annoying requirement that you “subscribe” before you can view their content.

I’ll call this facility the “Registration Webapp.” What I’ll do is specify the requirements of this webapp, and for each requirement, I’ll identify the types of code (Model, View, or Controller) that might be needed.

Requirement 1
The user is asked to specify a user ID (userid) and a password, as well as a password confirmation, as shown in Figure 5-2.


Figure 5-2. The Registration webapp main page

Discussion
Clearly, you need View code to create the form containing the user ID and password fields. The output of the View code would be HTML. The View code itself might be this displayed HTML, or a JSP that is transformed into HTML by the servlet container.

Requirement 2
The form data is validated to check for a malformed user ID or password. The form is also checked to ensure that the same password was entered both times and that it has the right length.

Discussion
You will need Controller code to do the validation. One important point to note is that these checks can be done without referring to a database. This means that you could validate either on the client (the web browser), perhaps using JavaScript, or use Java classes residing on the server.

The first option would bend the MVC rule of strict separation between View and Controller because the JavaScript would have to be placed in the HTML or JSP code in Requirement 1. Even if you factored out the JavaScript validators into a separate .js file, you’d still need Controller code on the HTML/JSP View code to transfer the form values to the JavaScript validators. Don’t get me wrong; I’m not saying that client-side JavaScript is an evil that crawls out from the bowels of Hell. I’m simply saying that hand-coded clientside JavaScript to perform validation violates MVC.

Violations of MVC, no matter how well justified, come at the cost of reduced maintainability.

Fortunately, it is possible to have your cake and eat it too. Instead of using hand-coded client-side JavaScript, Struts gives you the option of autogenerating client-side JavaScript. This would greatly reduce Controller/View overlap. You’ll see this in action when we cover the Validator framework in Chapter 15.

Or, we could simply cut the Gordian knot and do all validations on the server. Unfortunately, this isn’t always an option, especially if the client-server connection is slow.

Requirement 3
The data is further checked to ensure that there are no other users with that user ID.

Discussion
As in Requirement 2, we obviously need Controller code to run the validation. Unlike Requirement 2, a client-side validation is less feasible, because we might need to check with a database in order to find out if the given user ID exists.

This also implies we need Model code to read user IDs off the database. The Model code has a function like this:

public boolean exists(String userid)

to run the user ID check. Our Controller code would use this function to run the validation.

Requirement 4
If at any stage there is an error, the user is presented with the same start page, with an appropriate error message (see Figure 5-3). Otherwise, the user’s user ID and password are stored.


Figure 5-3. Signaling errors to the user

Discussion
You’ll need a Controller to decide what to do if there’s an error: display the error page or save the data?

You’ll also need a View to display the error message. Here’s where enforcing strict MVC separation makes things complicated. For example, do you need to duplicate View code from Requirement 1 to redisplay the form data? How about re-populating the previously keyed-in form data? In Figure 5-3, the user ID field isn’t blank—it contains the previously keyed-in user ID.

In fact, we could handle errors from Requirement 2 if we threw out MVC and mixed Controller and View code, as I described in the discussion to Requirement 2. Although this still wouldn’t solve the same display issues arising from Requirement 3, we might be able to hack a solution by merging Model and Controller code with our View code by embedding scriptlets in our JSP View code.

These complications illustrate the need for a web application framework like Struts. You need Struts to help you enforce MVC. Without Struts (or a web application framework), it is probably impossible to cleanly enforce MVC separation on your webapp code.

Note that I’m only saying that Struts (or a webapp framework) makes MVC possible. Don’t take this to mean that Struts makes bad code impossible! You can cheerfully violate MVC even if you’re using Struts.

Lastly, you’d also need Model code to save the user ID and password pair. Listing 5-1 outlines how the Java class for your Model code would look.

Listing 5-1. Skeleton for the Registration Webapp Model

public class User{
   
    protected String _userId = null;
    protected String _password = null;
   
    /* Bean-like getters and setters */
    public String getUserId(){
        return _userId;
    }
   
    public String setUserId(String userId){
        _userId = userId;
    }
   
    public String getPassword(){
        return _password;
    }
   
    public String setPassword(String password){
        _password = password;
    }
   
    /**
    * Checks if the userid exists.
    */
    public static boolean exists(String userid){
        //implementation omitted
    }
   
    /**
    * Saves the _userid and _password pair
    */
    public void save() throws Exception{
        //implementation omitted
    }
}

Requirement 5
If the registration is successful, the new user gets a “You are registered” web page (see Figure 5-4).


Figure 5-4. Successful registration

Discussion
You’ll need View code to display the page. Plain ol’ HTML would do, unless you’re embedding this message within a larger page, as is often the case in real life. Like Requirement 4, this latter possibility also complicates strict MVC enforcement.

But again, Struts comes to your rescue. As you’ll see in Part 2 of this book, Struts has an extension (“plug-in” in Struts-speak) to give you just this functionality.

I hope this simple example gives you a good idea how to classify your code with the MVC worldview. I also hope it gives you an idea of why you’d need a framework to help you actually enforce MVC. To give you a little more practice, try the following quiz.

Lab 5: MVC Quiz
LILLDEP (Little Data Entry Program) is a simple data entry program for storing and managing a database of contacts. It’s a common type of web application used in many SMEs (Small Medium Enterprises). Figure 5-5 shows the basic LILLDEP main page.


Figure 5-5. The LILLDEP main page

Have a look at the three requirements that follow and try to identify the Model-View- Controller parts that might be relevant. Imagine a possible implementation for each, as I did in the previous section, and identify where you might need help to enforce strict MVC code separation.

  • Requirement 1: A page to collect information about a contact
  • Requirement 2: Code to check contact details (postal code, email, or required fields) after submission and display errors
  • Requirement 3: Code to store and retrieve data into a database

Which Comes First?
When you develop your webapp with the MVC design pattern, which portion (Model/ View/Controller) would you specify and design first? Why?

Close the book and give yourself a few minutes to answer this before reading the following discussion.

There’s no “right” answer to this one, but most people start with either View code or Model code. Rarely would you start with a design for the Controller since it depends on View and Model components.

My personal preference is to specify and design Model code first. This means defining at an early stage what data to store and how to expose data with data access methods (like the exists() method in Listing 5-1) to other code. Here are my reasons for holding this position:

  • Without a clear specification of what data to store, you can’t design the rest of the application.
  • Without a specification of how to access data, a clear separation between Model and Controller is difficult to achieve. For example, if you’re using a relational database, you might end up with SQL code in the Controller. This violates the MVC principle of well-defined interfaces.

Many people (especially new developers) prefer to design View code first, possibly because this helps them understand the application’s inputs and control flow. In this approach, View comes first, then Controller, and Model last. Though it’s perfectly valid, I believe this approach is prone to certain pitfalls:

  • Redundant information being stored in the database. Like the proverbial three blind men describing the elephant, using View code to drive Model design is bad because you lack a global view of the application’s data requirements. This is especially so in complex applications, where you could store the same information twice, in two different tables.
  • Poorly organized database tables, because the Model code and data organization is designed to conform to View requirements, which may not reflect the natural relationships between Model elements.
  • Less future-proof code, because a change in the View code may necessitate a revamp of Model code and the database design. Essentially, Model code is too strongly coupled to View code.

All these stem from the fact that those who take the “View first” approach use View code or mockups to indirectly educate them about Model requirements.

Having said that, there are many situations where a “Model first” approach may seem impractical. For example, in many corporate IT departments, developers don’t have a full understanding of the problem domain. Instead, they have to rely on and frequently communicate with non-IT personnel like managers or admin staff (“domain experts”) in order to understand the system’s requirements.

In this scenario, the application is naturally View driven because mockups are used as a communication tool between developers and domain experts. My advice to those in such a situation is to incrementally build a picture of the Model code and data immediately after each discussion with domain experts. Don’t leave Model design to the last.

Whichever way you choose, Model-first or View-first, I believe it’s important to understand why you do things the way you do, simply because this helps you become a better programmer.

In the following section, I’ll describe how Struts fits into the MVC design pattern.

Struts and MVC
In Struts, Model code consists of plain old Java objects (POJOs).

In other words, Struts places no restrictions on how you code the Model portion of your webapp. You should encapsulate data access/persistence into Model classes, but Struts does not force you to do this. Remember, Struts is here to help you achieve MVC nirvana
as easily as possible. Apparently, you don’t really need help to separate Model from View and Controller.

View code consists of JSPs and a set of custom tags supplied by Struts. These custom tags enable you to separate View from Controller, because they address all the issues I raised earlier when I tried to apply MVC to the Registration webapp.

With Struts, Controller code falls into three broad categories:

  • Simple validations are performed by your subclasses of the Struts base class called ActionForm. Checks for password length or email address format are examples of this. Later in this book, you’ll see how Struts greatly simplifies validation with the Validator framework.
  • Complex validations and business logic are done in your subclasses of the Struts base class called Action. The check for the duplicate user ID for the Registration webapp is an example of complex validation. An example of business logic is calculating the total amount due after a purchase in a shopping cart webapp.
  • Flow control is also decided by your Action subclasses, restricted to paths declared in the Struts configuration file called struts-config.xml.

You’ll learn more about ActionForm, Action, and struts-config.xml as this book progresses. At this stage, you should simply understand how MVC maps into Struts. Figure 5-6 depicts this mapping.


Figure 5-6. How MVC maps into Struts

Lifecycle of a Struts Request
The three categories of processing (simple/complex validation, business logic, and flow control) come into play when an incoming HTTP request is generated by a user submitting form data.

With servlet technology all such processing is done by servlets. As I mentioned in Chapter 2, Servlets are just Java objects, usually your subclasses of HttpServlet.

Even JSP pages are converted at runtime into servlet classes—actual .java source files. These autogenerated Java source files are later compiled.

Since Struts is built on servlet technology, it is no exception to this rule. All submissions of form data to a Struts application are intercepted by a single “master” servlet, an instance of ActionServlet, which is a part of Struts.

This master servlet is responsible for delegating the actual work of your application to your subclasses of ActionForm and Action (see Figure 5-6).

USUALLY?

Servlet technology is quite generic, meaning it is not at all tied to processing HTTP requests, although this is by far the most common use.

This is because servlets solve a number of generic problems that stem from client-server communication, such as object pooling and session management. Your servlet classes could implement the basic Servlet interface from scratch, or subclass the GenericServlet base class. You’d do this if you wanted to take advantage of servlet technology’s solutions to these generic problems.

If you’re primarily concerned with processing and displaying web pages, HttpServlet is the base class you’d subclass.


Note In addition to this, ActionServlet and its helper classed are responsible for many other behindthe-scenes things like pooling Action subclasses for efficiency, reading configuration data, or initializing Struts extensions called plug-ins. These activities are invisible to Struts developers, and are one good reason why Struts is so easy to use. You don’t have to know how the clock works to tell the time!

The incoming form data is processed in stages:

  • Data transfer: Form data is transferred to your ActionForm subclass.
  • Simple validation: The form data in this subclass is passed through simple validation.If simple validation fails, then the user is automatically presented with the form with the error messages detailing the errors. This is a typical scenario, but the details would depend on how you configured Struts. We’ll go through the mechanics of simple validation in Chapter 6 and tackle configuration in Chapter 9.
  • Further processing: Form data is next sent to your Action subclass for complex validation and the processing of business logic. We’ll discuss this in Chapter 7.

Your Action subclass also specifies the “next” page to be displayed, and this ends the processing of a single request.

Frameworks for the Model
In a previous section, I sang the joys of designing the Model portions of your webapp first, so Struts’ lack in this area might come as a bit of a letdown.

One reason for this glaring deficiency in Struts is because there are already several frameworks to help you with data access and persistence. These go under the monikers “ persistence framework/layer” or “object/relational (O/R) persistence service.” The reason these frameworks exist is to persist data, and do it well. You may use any one of these in conjunction with Struts. So you see, it isn’t a deficiency at all but just good design.

There are two different approaches to data persistence:

  • Persist the classes: This approach lets you store and retrieve any Java object to/from a relational database. You are provided with a set of classes, which you must use to persist and retrieve your own Java classes. An example of this approach is Hibernate, from Apache.
  • Classes that persist: In this approach, you specify a description for your database tables and their interrelationships. The persistence framework autogenerates Java classes (source code), which have mappings to your database tables. These autogenerated classes have save(), select(), and delete() functions to allow persistence and retrieval of data objects. A prime example of this approach is Torque, also from Apache.

The “persist the classes” approach is by far the more flexible of the two, since you could potentially persist any Java class, including legacy ones, or third-party classes. The “classes that persist” approach, on the other hand, lacks this capability but produces a cleaner separation between Model and Controller.

I should warn you that while this comparison between approaches is valid, you can’t use it to choose between products like Hibernate and Torque. Hibernate, for example, provides many features beyond what I’ve described here. These extra features are what you’d want to consider when choosing a persistence framework.

In Appendix A, I give you simple examples of how to use Hibernate and Torque, and also (shameless plug) a simple, open source, “classes that persist” framework called Lisptorq, developed by the company I work for.

Useful Links

Summary

  • The Model-View-Controller (MVC) design pattern brings many benefits to the webapp that implements it.
  • Implementing MVC is difficult, which is why you need a web application framework like Struts.
  • Struts only places restrictions on the View and Controller. You are free to implement the Model portion in any way you wish.
  • Two very popular persistence frameworks are Hibernate and Torque.

Copyright © 2006 by Arnold Doray

Home  |  News  |  Source Code  |  Tutorials  |  Components  |  Tools  |  Books  |  Free Magazines  |  Jobs  |  Gear  |  Hosting  |  Links
 
Copyright © 2000 - 2006 Code Beach  |    |  Privacy Policy
 
Free thumbnail preview by Thumbshots.org