| |||||||||||||
| Email Lance Lavandowska | To Outline | |
| Kevin Duffy on MVC | Recommended Reading | Other Resources |
Note: this paper was written over three years ago. While it has been updated periodically, you may still find some statements that are out of date. Please let me know. Thanks.
If you spend any time reading through Servlet or JSP related newsgroups or mailing lists, you're likely to encounter a discussion of Model I versus Model II methodologies . Which one you use depends on personal taste, team work strategies and OOP orthodoxy.
Loosely described, Model I is an approach where business logic and presentation code can be intermixed with the presentation itself (HTML in our arena). Model II proscribes that all code, to the extent this is possible, be excluded from the presentation.
In a team environment where everyone knows Java and HTML, or if you're doing it all yourself, this approach can work well, provided everyone maintains a clear coding structure (that discussion is outside the bounds of this article). The primary advantage of this approach is that there is only one file to maintain for changes to your application. The major disadvantage is readability! Unless great care is taken, your HTML and Java code can become so intermingled that it becomes difficult to debug and maintain your application.
======================================================================
<xml version="1.0" ?>
<H1>Time JSP</H1>
<jsp:scriptlet>
//the parameter "zone" shall be equal to a number between 0 and 24 (inclusive)
TimeZone timeZone = TimeZone.getDefault(); //returns the default TimeZone
if (request.getParameterValues("zone") != null)
{
// gets a TimeZone. For this example we're just going to assume
// its a positive argument, not a negative one.
String timeZoneArg = request.getParameterValues("zone")[0];
timeZone = TimeZone.getTimeZone("GMT+" + timeZoneArg + ":00");
}
/*
since we're basing our time from GMT, we'll set our Locale to
Brittania, and get a Calendar.
*/
Calendar myCalendar = Calendar.getInstance(timeZone, Locale.UK);
</jsp:scriptlet>
<%= myCalendar.get(Calendar.HOUR_OF_DAY) %>:
<%= myCalendar.get(Calendar.MINUTE) %>:
<%= myCalendar.get(Calendar.SECOND) %>
======================================================================
Similarly, the data to be displayed could have been gotten from a JavaBean. We'll see a little of that in the next example.
In a team environment where some members are HTML designers and others are Java programmers, this approach can be particularly strong. The Java programmers can focus on creating (re)usable code, while the HTML designers can focus on presentation. While the two remain dependant on each other, one or the other can change dramatically so long as the principle inputs and outputs (respectively) remain the same.
Now we'll take the same desired behaviour from the Model I example, and present it using the Model II methodology. This methodology follows the Model-View-Controller (MVC) paradigm (cite Design Patterns book). For this example, we'll have one class (or page or servlet) process the request (Controller), get the TimeZone, set all the required variables for presentation, and pass control off to a presentation page (View). For simple apps like this, there is no "Model".
======================================================================
<xml version="1.0" ?>
<!--Worker Class, nobody should see me-->
<jsp:scriptlet>
//the parameter "zone" shall be equal to a number between 0 and 24 (inclusive)
TimeZone timeZone = TimeZone.getDefault(); //returns the default TimeZone
if (request.getParameterValues("zone") != null)
{
// gets a TimeZone. For this example we're just going to assume
// its a positive argument, not a negative one.
String timeZoneArg = request.getParameterValues("zone")[0];
timeZone = TimeZone.getTimeZone("GMT+" + timeZoneArg + ":00");
}
TimeBean timeBean = new TimeBean();
timeBean.setHours = myCalendar.get(Calendar.HOUR_OF_DAY);
timeBean.setMinutes = myCalendar.get(Calendar.MINUTE);
timeBean.setSeconds = myCalendar.get(Calendar.SECOND);
HttpSession mySession = request.getSession();
mySession.putValue("tempTimeBean", timeBean);
</jsp:scriptlet>
<jsp:forward page="displayTime.jsp" />
======================================================================
View: displayTime.jsp
======================================================================
<xml version="1.0" ?>
<H1>Time JSP</H1>
<jsp:useBean class="TimeBean" id="tempTimeBean" scope="session" />
<jsp:getProperty name="tempTimeBean" property="hours">:
<jsp:getProperty name="tempTimeBean" property="minutes">:
<jsp:getProperty name="tempTimeBean" property="seconds">
<!--
would print "null" if tempTimeBean was not instantiated by timeByZone.jsp
-->
<jsp:scriptlet>
HttpSession mySession = request.getSession();
TimeBean timeBean = mySession.getValue("tempTimeBean");
if (timeBean != null)
{
// check to make sure its not null, to avoid NullPointerExceptions
out.print(timeBean.getHours());
out.print(":");
out.print(timeBean.getMinutes());
out.print(":");
out.print(timeBean.getSeconds());
}
else
{
out.println("Press your Back button and select a TimeZone");
}
</jsp:scriptlet>
======================================================================
The second method (using code inside) may be more cumbersome, but allows the developer to ensure against ugly output (such as "null:null:null null") if the Session bean has not been instantiated & had its values set. This would likely only happen if the client somehow called the View page directly. The point is that using scriptlets allows for greater control. If you are certain you can control url access, the bean approach certainly eases development, and makes the View page easier for HTML designers to work with.
The above is the "traditional" Model II design. You'll note that all the variables are wrapped up and placed into the Session object. This has two weaknesses: 1) no Session is availabe because the client has refused to participate, 2) unless the Session variable is explicitly removed it will continue to exist until the Session is destroyed or expires.
The first case is most likely to happen when cookies are used as the State mechanism and the developers have failed to provide for the alternative form of State maintenance, URL rewriting.
The second case is even more serious, as it can lead to great memory use if Sessions are defined to exist for more than the standard amount of time (30 minutes appears to be the standard). Even in the case of 30 minute Sessions, this Model can lead to disastrous memory leaks in systems under great use. Why? Objects get instantiated, set inside the Session object, and are not removed until the Session ends. Because they still have references (the Session object) pointing to them, they are not garbage-collected. In the Model II pattern, many objects are placed into the Session (either directly or via a JavaBean). As the Session progresses (more pages are accessed) memory-use increases and persists until the client ends the Session or the Session times out. Until the Session is invalidated, the objects placed there cannot be garbage-collected, and thus consume memory that could be of use elsewhere.
One means of addressing this issue is to place the Beans or other variables into the Request object, and use RequestDispatcher.include() rather than RequestDispatcher.forward(). By doing so, the View page has access to the same Request object as the Controller, and the weaknesses of the traditional Model II design are obviated. This seems to have been the case several years ago (that RD.forward() did not pass the Request object), .forward() no longer has this problem.
One final comment: despite all the above, I have a personal distaste for the Model II paradigm as it is commonly implemented. The creation of a system where the client is sent to an address, but is redirected to a different class, is for some reason abhorrent to me. For this reason, I've modified the design in the following manner:
======================================================================
<xml version="1.0" ?>
<!--Worker Class, nobody should see me-->
<jsp:scriptlet>
//the parameter "zone" shall be equal to a number between 0 and 24 (inclusive)
TimeZone timeZone = TimeZone.getDefault(); //returns the default TimeZone
if (request.getParameterValues("zone") != null)
{
// gets a TimeZone. For this example we're just going to assume
// its a positive argument, not a negative one.
String timeZoneArg = request.getParameterValues("zone")[0];
timeZone = TimeZone.getTimeZone("GMT+" + timeZoneArg + ":00");
}
TimeBean timeBean = new TimeBean();
timeBean.setHours = myCalendar.get(Calendar.HOUR_OF_DAY);
timeBean.setMinutes = myCalendar.get(Calendar.MINUTE);
timeBean.setSeconds = myCalendar.get(Calendar.SECOND);
request.setAttribute("tempTimeBean", timeBean);
</jsp:scriptlet>
======================================================================
====================================================================== <xml version="1.0" ?> <H1>Time JSP</H1> <jsp:include page="timeByZone2.jsp" /> <jsp:useBean class="TimeBean" id="tempTimeBean" scope="request" /> <jsp:getProperty name="tempTimeBean" property="hours">: <jsp:getProperty name="tempTimeBean" property="minutes">: <jsp:getProperty name="tempTimeBean" property="seconds"> <!-- would print "null" if tempTimeBean was not instantiated by timeByZone2.jsp --> ======================================================================
In a system currently under construction, we've made use of this method to create chains of classes, each responsible for its own processing. By identifying common presentation formats, we've created View objects that can be reused in yet higher level JavaServer Pages. Our goal is to create pages that are designed for reuse, and to reduce the number of presentation classes.
For information (and implementation) of this concept, please go to Jakarta Struts or read Kevin Duffy on MVC.
| If you would like to comment on this article, or make corrections, please email me. Suggestions & corrections are welcome |
To Outline Other Resources |