Like most standard e-business applications, Go-ForIt is built on a logical three-tier architecture, as described below.
- First tier
- Includes Web pages and the user's Web browser.
- Middle tier
- Resides on a WebSphere Application Server, and has servlets, JavaServer Pages (JSPs), and some specialized JavaBeans components.
- Third tier
- Includes our business objects for processing transactions and storing persistent data, Enterprise JavaBeans (EJB) components, and a DB2 database.
This three-tier architecture is a good example of a model view controller (MVC) design. Here at the Go-ForIt project, we are MVC zealots. MVC is a fancy way of describing an application design that is multi-tier with clearly defined functional layers, as follows.
- Model layer
- Your back-end data or transactional processes. In our application, EJB components act as our model.
- View
- What an end-user sees, such as a JSP or HTML page.
- Controller
- A servlet in our application, it's the layer that acts as a traffic cop, mediating user interactions with our back-end components.
One of the best reasons to follow the MVC design philosophy is to ensure that a diverse development team can cleanly define and separate roles. Web developers work on the look and feel of JSP and HTML pages without touching the application's business logic. At the same time, the Java developers can focus on creating the application's business logic, without touching the look and feel. By letting the different developers excel in their own areas, we don't have mucked-up code or a look and feel with a serious case of the uglies.
Consistent interfaces between the layers, or tiers, make wiring the components together simple and requires little knowledge of a component you didn't write yourself.
In the MVC example below, a user submits a form from an HTML page. A servlet receives the request and calls the appropriate back-end components, such as EJBs, required to fulfill the request. The back-end components return a JavaBeans component that encapsulates the result set. The servlet then calls the appropriate JSP component, which retrieves the results from the result bean. The JSP integrates the dynamic results data with static template data and returns the page to the user. Each layer performs a clearly defined role that allows for easy separation of concerns, and work, among our team members.
Model view controller example

MVC sounds great, right? In reality, it can be tough to completely separate the layers, especially when it comes to the view. Often the view, especially when you're handling form data, demands some logic to display the right thing based on user actions and certain conditions. Yet MVC requires that view components, such as JSPs, be free of logic. We faced this dilemma almost immediately with the Go-ForIt project.
As with many applications, a Go-ForIt user must first register. Our registration JSP includes a form that collects the required information. The page does some client-side validation using JavaScript, then submits the form for processing. A successful registration will return a confirmation message and redirect the user to the appropriate menu page.
What about when something goes wrong with the form processing? Let's say a user tries to register with a duplicate user ID. For such problems during the form processing, we wanted a couple of things to happen:
- Return the user to the Registration page with a detailed error message at the top of the page.
- Pre-fill the form with data that was already entered, so the user doesn't have to reenter each and every data item.
All HTML form fields are not created equal. A little logic is necessary to prefill some types of fields after a form has been submitted and returned for error corrections. In our case, we had several drop-down list boxes, as well as checkboxes, that would require some logic to prefill the data. At first, we started down a precarious path of putting "if...else" statements into our JSP. But when our Lead Architect overheard our innocent conversation about how to code all of this presentation logic in the JSP, he said: "No Java code in the JSPs!" Our resident MVC militant had issued an edict.
With the edict in mind, we went back to the drawing board. View beans, we decided, were the solution to "No Java code in the JSPs!". View beans are simple JavaBeans that encapsulate the presentation logic needed in a JSP. They keep Java code out of our JSP, preserving it as a simple template for look and feel. View beans also let us separate presentation logic from our business logic, keeping HTML code out of our servlets and other control and model objects. They are reusable, easy to use, and make testing and debugging easier.
View beans are JavaBeans implementations, so are designed to be simple and reusable. As we develop our application, we can use the same view beans on different JSPs. For instance, one of the view beans we used encapsulates the presentation logic for reporting errors back to a user. It contains the logic to retrieve the correct error message and display it back to the user in a meaningful way. We can call this bean on any page and have it print an error message at just the spot we want it.
Any Java programmer familiar with the JavaBeans specification can probably write one while simultaneously winning the company foosball challenge with one hand tied behind his back. View beans are also incredibly easy for Web developers to use. They can simply add a JSP useBean tag to the pages where they need to call the view bean. Simple JSP getProperty and setProperty tags will then let a Web developer set and retrieve properties on a bean as needed.
A JSP is not compiled until the page is requested. When a JSP is requested, the application server translates the JSP into an HTTPServlet, compiles it, and executes it. This model works well when your JSP code is error-free. However, if your JSP has bugs, the JSP execution model makes testing and debugging difficult because the page has to be re-translated into a servlet and recompiled with each change you make. You can try debugging the JSP's generated servlet code, but this code is notoriously convoluted and unfriendly to human readers. Plus, you'll still have to determine how the problem in the generated servlet code translates to a fix in the JSP itself.
By removing the Java code from our JSP, however, we can significantly reduce the possibility for bugs within our JSP file. The bugs will more likely occur in the Java components we are calling from the JSP because all of our logic is encapsulated in these components. We can take advantage of powerful Integrated Development Environments (IDEs) that will let us compile, test, and debug the Java code. On our project, we used IBM VisualAge for Java Enterprise Edition Version 3.5. VisualAge includes a robust, integrated debugger and a WebSphere Test Environment for testing applications that will be deployed to WebSphere Application Server. VisualAge also incrementally compiles code, so you know instantly if you have a compile error. We used VisualAge to develop, test, and debug all of our Java components, including our view beans.
When a user registers at the Go-ForIt site and an error condition is caught during the server-side processing, we wanted to return the user to the registration form with an error message at the top, and all of the data they had entered prefilled in the form. We used view beans to provide this function while still maintaining the integrity of our MVC design. Let's look at the actual components involved and the relevant code.
The following figures show the flow of our application before and after we added view beans to the architecture.
Application flow of "user registers" before view beans

Application flow of "user registers" with view beans

As shown in the "after" figure above, we used two view beans in the "user registers" story: PrefillsRegistrationJSPViewBean and ErrorViewBean. Each bean encapsulates a specific piece of presentation logic for our JSP. You might be thinking that the view beans add complexity, based on the figures above. However, while they do add more components to our design, the encapsulation they bring will save us time when it comes to maintenance, testing, and reuse.
The role of PrefillsRegistrationJSPView
The PrefillsRegistrationJSPView bean (say that three times, fast!) encapsulates the logic to capture the data (set methods) the user has already entered into certain form fields, and to prefill the values (get methods) in the form when the user is directed back to the page. With this design, a user who encounters an error such as a duplicate user ID will be returned to the form and will only have to change the user ID, rather than reenter the entire form. The following code is an excerpt from PrefillsRegistrationJSPView.java. This code doesn't show the entire class definition, but shows the field declarations and the getter and setter methods for one check box property (customer) and one list box property (title). There is quite a bit of logic required to prefill a little list-box and check box.
\** This is an excerpt from PrefillsRegistrationJSPView **\
public class PrefillRegistrationJSPView {
private String _prefillTypeCustomer = null;
private java.lang.String _prefillTitle = null;
private java.lang.String[] _titles = {
"", "Mr.", "Mrs.", "Ms.", "Miss"
};
. . .
};
public String getCustomerChecked() {
if (_prefillTypeCustomer != null)
return "checked";
else
return null;
}
public java.lang.String getTitleSelect() {
StringBuffer list = new StringBuffer();
list.append("<SELECT size=\"1\" name=\"title\">\n");
//Nothing prefilled. Use 1st option as the default
if((this._prefillTitle == null) || (this._prefillTitle.equals("")))
{
for (int i = 0; i < _titles.length; i++) {
list.append("<OPTION");
if (i == 0) {
list.append(" SELECTED>" + _titles[0]);
}
else {
list.append(">" + _titles[i]);
}
list.append("</OPTION>\n");
}
}
else {
// Prefill previously selected value
for (int i = 0; i < _titles.length; i++) {
list.append("<OPTION");
if (_titles[i].equals(_prefillTitle)) {
list.append(" SELECTED>" + _titles[i]);
}
else {
list.append(">" + _titles[i]);
}
list.append("</OPTION>\n");
}
}
list.append("</SELECT>");
return list.toString();
}
public void setCustomerChecked(String val) {
_prefillTypeCustomer = val;
}
public void setInitialTitle(java.lang.String prefillTitle) {
_prefillTitle = prefillTitle;
}
}
|
The ErrorViewBean encapsulates the logic to display an error message from errors found during server-side processing. For instance, when a user enters a duplicate user ID, a DuplicateUserException is thrown by our User EJB. If a DuplicateUserException is thrown, the RegistrationServlet will then catch the exception and instantiate an ErrorView bean with the error message from DuplicateUserException. The ErrorBean instance is stored in the user's session (for more about sessions, see Jeff Wilson's article, The GoFor-It Chronicles Part 3: Session management, servlets, and maintaining state). The following code is the entire class definition of ErrorView.
\** This is the code for ErrorView.java **\
public class ErrorView {
private java.lang.String _fieldMessage = new String();
public ErrorView() {
super();
}
public ErrorView(String message) {
setMessage(message);
}
public java.lang.String getMessage() {
return _fieldMessage;
}
public void setMessage(java.lang.String message) {
_fieldMessage = message;
}
}
|
Other important Java components
There are a few other components that are part of the "user registers" story. When a user registers, not only are the JSP and view beans called upon, but several other server-side components participate as well.
The UserDataBean is a JavaBeans bean that represents user data required on the client-side for multiple requests. (For more information about client-side beans and our UserDataBean, check out the last article in our series: "Bean" There, Done That: Using Client-Side Beans for Component Independence by Sandeep Desai.) When a user submits the registration form, the RegistrationServlet instantiates a UserDataBean and populates it with the data from the form. The UserDataBean is then stored in the user's session.
If an error occurs when the User EJB tries to add the user to the database, the servlet redirects the browser back to Register.jsp, which uses the UserDataBean to retrieve values for the simple text fields on the form. These text fields don't require any logic to prefill, just a simple getProperty call from the JSP to the UserDataBean.
The RegistrationServlet is the interaction controller in our "user registers" scenario. When the user submits the registration form, the RegistrationServlet is called. The servlet instantiates a new UserDataBean and populates it with data from the form. The servlet then calls the appropriate objects to handle the method calls against back-end objects, passing the UserDataBean as a parameter.
If the EJB successfully adds the user to the database, the servlet redirects the user's browser to a new page with a confirmation message. If, however, an error is encountered when the EJB processes the request, the servlet will catch the exception thrown by the EJB and instantiate an ErrorBean to encapsulate the error message. The servlet will then redirect the browser back to Register.jsp with the error message displayed and the form prefilled based on the values stored in PrefillsRegistrationJSPView and UserDataBean.
As the controller, it is the servlet's job to call the appropriate objects to fulfill the user's request. Our application uses EJBs and follows the Command Pattern (The command pattern is discussed in detail in Design and Implement Servlets, JSPs, and EJBs for IBM WebSphere Application Server, an IBM Redbook. See Resources). When a user registers, the RegistrationServlet calls the UserRegistersCommandBean, which understands how to talk to our EJBs. The User EJB, an entity bean, then performs the work of actually adding the user to our database.
Last, but not least: Register.jsp
You've seen the class definitions of our view beans, ErrorView and PrefillsRegistrationJSPView, so now let's see how our JSP uses these beans. Below is an excerpt from Register.jsp. The most notable sections are in red. The first red code you'll notice is the useBean tags for each of our view beans. The useBean tag tells the JSP processor that we will be referencing these JavaBeans in our JSP. When the JSP is translated into a servlet, a JSP useBean tag is translated into an object declaration where the object is of the bean type specified in the tag.
Once we have set up our JSP with the useBean tags, we can then call methods on the beans. We do this by using the JSP setProperty and getProperty tags. The name attribute of the getProperty and setProperty tags refers to the id we assigned our bean in the useBean tag. The property attribute refers to the property and associated method we are trying to access on the bean -- in this case setInitialTitle() and getTitleSelect().
An excerpt of Register.jsp
\** This is an excerpt from Register.jsp**\ . . . <jsp:useBean id="user" class="com.goforit.user.UserDataBean" scope="request"></jsp:useBean> <jsp:useBean id="errorMsg" scope="request" class="com.goforit.view.ErrorView"></jsp:useBean> <jsp:useBean id="prefills" class="com.goforit.view.PrefillRegistrationJSPView" scope="request"></jsp:useBean> <BR> <jsp:getProperty name="errorMsg" property="message" /><BR> <BR> </FONT></TD> </TR> <TR> <TD class="subhead">Please complete the following form:</TD> </TR> <TR> <TD><IMG src="/goforit/images/asterisk.gif" width="15" height="15" border="0"> = a required field</TD> </TR> <TR> <TD valign="top"> <FORM action="/goforit/RegistrationServlet" method="POST" onsubmit="return checkForm(this);"> <TABLE border="0" width="100%"> <TBODY> <TR> <TD width="375">Â </TD> <TD>Â </TD> </TR> <TR> <TD width="375" align="right">Title:</TD> <TD> <jsp:setProperty name="prefills" property="initialTitle" param="title" /> <jsp:getProperty name="prefills" property="titleSelect" /></TD> </TR> . . . |
As you can see, there is no Java code in Register.jsp! Our Lead Architect is proud. The Java developers are thankful they can continue their peaceful existence unbothered, and the Web page developers are doing a jig because they know they can easily change the look and feel of this page without mucking about in any Java code. Another dragon is slain, and all is well in the land of Go-ForIt.
Watch for our next installment of the Go-ForIt chronicles, where we'll cover input validation. To see the previous articles in our tale of dragonslaying, go to our overview.
- Participate in the discussion forum.
- Participate in the discussion forum on this article by clicking Discuss at the top or bottom of the article.
- The GoFor-It Chronicles Part 3: Session management, servlets, and maintaining state, by Jeff Wilson.
- The GoFor-It Chronicles Part 4: "Bean" there, done that: Using client-side beans for component independence, by Sandeep Desai.
- Introduction to JavaBeans, an online tutorial that teaches basic JavaBeans concepts.
- Introduction to JavaServer Pages Technology, an online tutorial covering JSP basics.
- Introduction to Servlets and IBM WebSphere Application Server, an online tutorial that teaches you how to build simple servlets.
- Design and Implement Servlets, JSPs, and EJBs for IBM WebSphere Application Server, a redbook that covers best practices for Web application design.
Allison Pearce Wilson is an e-business Architect in the IBM Developer Relations organization in Austin, Texas. As a part of IBM Developer Relations, Allison provides technical consulting on the IBM Framework for e-business to IBM Business Partners worldwide. In the great tradition of liberal arts degree programs, this work is almost completely unrelated to her B.A. in education from Smith College. You can contact her at allison1@us.ibm.com.
