This chapter will examine a variety of ways to architect a system with JavaServer Pages,
Servlets, and JavaBeans. We will see a series of different architectures, each a development
of the one before. The diagram below shows this process in outline; the individual parts of
the diagram will be explained in turn later in the chapter.
System
Architecture
When Sun introduced Java ServerPages, some were quick to claim that Servlets had been
replaced as the preferred request handling mechanism in web-enabled enterprise
architectures. Although JSP is a key component of the Java 2 Platform Enterprise Edition
(J2EE) specification, serving as the preferred request handler and response mechanism, we
must investigate further to understand its relationship with Servlets. For all the latest
information on J2EE, including documentation relating to some of the issues discussed in
this chapter, please refer to http://java.sun.com/j2ee.
Other sections of this book explain the implementation details of JSP source translation and
compilation into a Servlet. Understanding that JSP is built on top of the Servlet API, and
utilizes Servlet semantics, raises some interesting questions. Should we no longer develop
standalone Servlets in our web-enabled systems? Is there some way to combine Servlets
and JSPs? If so, where do we place our Java code? Are there any other components
involved in the request processing, such as JavaBeans? If so, where do they fit into the
architecture and what type of role do they fulfill?
It is important to understand that, although JSP technology will be a powerful successor to
basic Servlets, they have an evolutionary relationship and can be used in a cooperative and
complementary manner.
Given this premise, we will investigate how these two technologies, each a Java Standard
Extension, can be used co-operatively along with other components, such as JavaBeans, to
create Java-based web-enabled systems. We will examine architectural issues as they relate
to JSP and Servlets and discuss some effective designs while looking at the tradeoffs of
each. Before jumping directly into a discussion of specific architectures, though, we will
briefly examine the need to develop a variety of architectures.
One of the main reasons why the Java Server Pages technology has evolved into what it is
today (and it's still evolving) is the overwhelming technical need to simplify application
design by separating dynamic content from static template display data. The foundation for
JSP was laid down with the initial development of the Java Web Server from Sun, which
utilized page compilation and focused on embedding HTML inside Java code. As applications
came to be based more on business objects and n-tier architectures, the focus changed to
separating HTML from Java code, while still maintaining the integrity and flexibility the
technology provided.
In Chapter 5 we saw how beans and objects can be bound to different contexts just by
defining a certain scope. Good application design builds on this idea and tries to separate
the objects, the presentation and the manipulation of the objects into distinct,
distinguishable layers.
Another benefit of utilizing JSP is that it allows us to more cleanly separate the roles of a
web production/HTML designer individual from a software developer. Remember that a
common development scenario with Servlets was to embed the HTML presentation markup
within the Java code of the Servlet itself, which can be troublesome. In our discussion, we
will consider the Servlet solely as a container for Java code, while our entire HTML
presentation template is encapsulated within a JSP source page. The question then arises as
to how much Java code should remain embedded within our JSP source pages, and if it is
taken out of the JSP source page, where should it reside?
Let's investigate this further. On any web-based project, multiple roles and responsibilities
will exist. For example, an individual who designs HTML pages fulfills a web production role
while someone who writes software in the Java programming language fulfills a software
development role.
On small-scale projects these roles might be filled by the same individual, or two individuals
working closely together. On a larger project, they will likely be filled by multiple individuals,
who might not have overlapping skill sets, and are less productive if made too dependent on
the workflow of the other.
If code that could be factored out to a mediating Servlet is included instead within HTML
markup, then the potential exists for individuals in the software development role and those
in the web production role to become more dependent than necessary on the progress and
workflow of the other. Such dependencies may create a more error-prone environment,
where inadvertent changes to code by other team members become more common.
This gives us some insight into one reason why we continue to develop basic Servlets: they
are an appropriate container for our common Java code that has been factored out of our
JSP pages, giving our software development team an area of focus that is as loosely coupled
to our JSP pages as possible. Certainly, there will be a need for these same individuals to
work with the JSP source pages, but the dependency is reduced, and these pages become
the focus of the web-production team instead. Of course, if the same individual fulfills both
roles, as is typical on a smaller project, such dependencies are not a major concern.
So, we should try to minimize the Java code that we include within our JSP page, in order to
uphold this cleaner separation of developer roles. As we have discussed, some of this Java
code is appropriately factored to a mediating Servlet. Code that is common to multiple
requests, such as authentication, is a good candidate for a mediating Servlet. Such code is
included in one place, the Servlet, instead of potentially being cut and pasted into multiple
JSPs.
We will also want to remove much of our business logic and data access code from our JSP
page and encapsulate it within JavaBeans, called worker or helper beans. We start to see a
pattern of code movement from our JSP into two areas: a Servlet (or JSP) that sits in front
of the main JSP, and JavaBeans that sit in back. We refer to this common pattern as 'Factor
Forward-Factor Back', as shown in the figure below:
Baby Game
Screenshot
The HTML code for this page, BabyGame1.html, is stored in <jswdk-root>/examples/jsp/
pageview/ and includes a form that prompts a user for selections. The user is asked to
make some guesses about the statistics of a baby to be born in the near future. The HTML
code is as follows:
<html>
<head>
<title>Baby Game</title>
</head>
<body bgcolor="#FFFFFF">
<form method="post" action="BabyGame1.jsp" name="">
<center>
<h3>Baby Game</h3></center>
<center>
<br>
<table BORDER COLS=5 WIDTH="75%" >
<caption>Please enter your own name:
<input type="text" name="guesser"></caption>
<tr>
<td>
<br><input type="radio" name="gender"
value="Female" checked>Female
<p><input type="radio" name="gender"
value="Male">Male
<p></td>
<br></select>
<p> </td>
<br></select>
<p> </td>
<option
value="14">14</option>
<option
value="15">15</option>
...
<option
value="25">25</option>
</select><p> <p> <p> </td>
</tr>
</table>
</center>
<br>
<center>
<p><input type="submit" name="submit" value="Make Guess">
<input type="reset" name="reset" value="Reset">
</center>
<br></form>
</body>
</html>
This HTML form will POST the choices to our JSP, which is shown in source form below
(BabyGame1.jsp, stored in directory <jswdk-root>/examples/jsp/pageview/ ). These
choices are then stored and displayed by our simple JSP, which has handled the request
directly.
The resulting display looks like this:
BabyGame1.jsp
The first part of BabyGame1.jsp is responsible for extracting the values from each of the
request parameters and populating the state of the JSP. The name of the individual making
the guess is contained in a request parameter called guesser. Each of the statistics about
the baby is stored in a request parameter with an intuitive name, such as gender, length,
etc.
<HTML>
<HEAD><TITLE>Baby Game - Your Guesses</TITLE></HEAD>
<BODY bgcolor=FFFFFF>
<%@ page language="java" import="java.util.*,java.io.*" buffer="8k" %>
<%
String guesser = request.getParameter("guesser");
%>
<br>
<%= guesser %>, your choices have been
stored.<br> Here they
are:<br>
<table BORDER COLS=5 WIDTH="75%"
>
<caption></caption>
<tr>
</tr>
</table>
<br>
<%}
%>
</BODY>
</HTML>
This JSP certainly was easy to build and is well suited to handling such simple needs. It is
getting quite cluttered with Java code, though, and its processing requirements are
extremely simplistic. More sophisticated business rules and data access code would require
much more Java within the JSP and the source would become unwieldy quickly as it grows.
Additionally, we are limited to mostly "cut-and-paste" reuse, which means duplicate code
and a more error-prone environment that is harder to maintain and debug.
In order to reduce the clutter of the current example and to provide a cleaner environment
for future growth, we will look at another 'Page-Centric' architecture called 'Page-View with
Bean' in the next section.
This pattern is used when the Page-View architecture becomes too cluttered with business-
related code and data access code. The Baby Game example now evolves into a more
sophisticated design, as shown in the figure below.
Page-View
with Bean
The modified JSP source page, <jswdk-root>/examples/jsp/pageviewwithbean/
BabyGame1.jsp, is shown below, followed by the worker bean that works in tandem with
the modified JSP in order to process the request. The HTML for the initial game interface
remains unchanged. The resulting display to the user from the JSP is basically unchanged
from that of the previous 'Page-View' example:
<HTML>
<HEAD><TITLE>Baby Game - Your Guesses</TITLE></HEAD>
<BODY bgcolor=FFFFFF>
<%@ page language="java" buffer="8k" %>
<jsp:useBean id="worker1" class="examples.pageviewwithbean.BabyGameWorker1"
scope="request" />
<%
if(worker1.getGuesser == null || worker1.getGender() == null ||
worker1.getPounds() == null || worker1.getOunces() == null ||
worker1.getMonth() == null || worker1.getDay() == null ||
worker1.getLength() == null)
{ %>
<br> There where some choices that were not selected.<br><br>
Sorry, but you must complete all selections to play.<br>
<font size=-1>(Please hit the browser 'back'
button to continue)</font><br>
<%}
else
{
worker1.store();
%>
<br>
<jsp:getProperty name="worker1" property="guesser" />, your choices have
been stored.<br> Here they are:<br>
<table BORDER COLS=5 WIDTH="75%" >
<caption></caption>
<tr>
</tr>
</table>
<br>
<%}
%>
</BODY>
</HTML>
The source for the worker bean, BabyGameWorker1 , is as follows:
package examples;
import java.io.*;
import java.util.Properties;
}
We see in these two listings that the Java code representing the business logic and simple
data storage implementation has migrated from the JSP to the JavaBean worker. This
refactoring leaves a much cleaner JSP with limited Java code, which can be comfortably
owned by an individual in a web-production role, since it encapsulates mostly markup tags.
Additionally, a less technical individual could be provided with a property sheet for the
JavaBean workers, providing a listing of properties that are made available to the JSP page
by the particular worker bean, and the desired property may simply be plugged into the JSP
getProperty action via the markup tag in order to obtain the attribute value. An example of
a potential property sheet is shown below. Additionally, once a convention and format were
agreed upon, an automated tool could be created to interrogate all JavaBeans of interest
and generate property sheets automatically.
Property Sheet
Moreover, we now have created a bean that a software developer can own, such that
functionality
may be refined and modified without the need for changes to the HTML or markup within
the JSP source page.
Another way to think about these changes is that we have created cleaner abstractions in
our system
by replacing implementation with intent. In other words, we have taken a bunch of code
from our JSP source (the Java code that writes the guesses to a file on disk ), encapsulated
it within a bean, and replaced it with our intent, which is to store the data, worker1.store().
So why might one choose to embed Java code in a JSP as opposed to using a predefined
tag? An example would be in order to loop through some data and format HTML for output.
Earlier versions of the JSP specification included a tag syntax for looping through indexed
properties of JavaBeans, so that no Java code was needed within the HTML for this purpose.
With the JSP software specification version 1.0, such tags were removed in favor of the
creation of an extensible custom tag markup mechanism that could be used for this purpose
and much more. Unfortunately, this custom tag functionality is first available in version 1.1
of the specification, and JSP engines supporting the custom tag libraries are only now
becoming available.
Further Refinements
After deploying this solution, our expectant family decides to limit the group of people who
are able to access the system, deciding to include only their family and friends. To this end,
they decide to add an authentication mechanism to their system so that each individual will
have to provide proof of identity before accessing the system.
If a simple authentication mechanism is added to the top of our JSP page and we want to
ensure that each JSP page is protected by this device, then we will need to add some code
to each and every JSP page to execute this authentication check. Whenever there is a
duplication of code such as this, it is beneficial to explore options for migrating the
duplicated code to a common area.
In the previous example we "factored back," as we moved business logic and data-access
Java code from our JSP to our JavaBean, and in the next section we expand our example to
"factor forward" into a Servlet, continuing our efforts to minimize the amount of inline Java
code in our JSPs.
We now move on to look at architectures based on the dispatcher or "N-tiered" approach,
where a Servlet (or JSP) acts as a mediator or controller, delegating requests to JSP pages
and JavaBeans. We will look at the mediator-view, mediator-composite view, and service to
workersarchitectures.
In an N-tier application, the server side of the architecture is broken up into multiple tiers,
as illustrated in the next figure:
N-tier application
In this case, the application is composed of multiple tiers, where the middle tier, the JSP,
interacts with the back end resources via another object or Enterprise JavaBeans
component. The Enterprise JavaBeans server and the EJB provide managed access to
resources, support transactions and access to underlying security mechanisms, thus
addressing the resource sharing and performance issues of the 2-tier approach. This is the
programming model supported by the Java 2 Enterprise Edition (J2EE) platform.
The first step in N-tiered application design should be identifying the correct objects and
their interactions, in other words, object modeling. This is the part where class diagrams
and tools like Rational Rose (http://www.rational.com) step in for architects. Quite often a
line has to be drawn as to what objects need to be modeled: being over zealous can cause
unnecessary complexity. If you get this part right, you're half way there!
The second part is identifying the JSPs or Servlets. As a rule of thumb, these should be
divided into two categories, depending on the role they play, often called "web components"
in the J2EE terminology
• Front end JSPs or Servlets that manage application flow and business logic
evaluation. This is where a lot of method invocation on the objects, or usage of
EJBs, can be coded. They are not responsible for any presentation, and act as a
point to intercept the HTTP requests coming from the users. They provide a single
entry point to an application, simplifying security management and making
application state easier to maintain.
• Presentation JSPs that generate HTML (or even XML), with their main purpose in life
being presentation of dynamic content. They contain only presentation and
rendering logic.
The figure below shows the relationship between these two categories. The front-end
component accepts a request, and then determines the appropriate presentation component
to forward it to. The presentation component then processes the request and returns the
response to another front component or directly back to the user:
processRequest(request, response);
}
processRequest(request, response);
}
try
{
// auth successful.
if ((request.getParameter("guesser") != null)
// request.
getServletConfig().getServletContext()
.getRequestDispatcher(request.getParameter("dispatchto"))
.forward(request, response);
}
else {
}
catch (Exception ex) {
ex.printStackTrace();
}
}
A new architectural pattern is emerging, with the mediating Servlet working with a JSP page
and worker bean pair to fulfill a service request. This 'Mediator-View' architecture is shown
below, and illustrating how each service is partitioned. The Servlet initially handles the
request and delegates to a JSP software page/worker bean combination. The JSP populates
bean properties from the request parameters and then uses the bean to prepare the data
for presentation:
"Mediator-
View" architecture
Continuing our attempts at creating the appropriate abstractions in our system, we shall
consider how to better partition our business logic and data access code, attempting to
reduce the coupling among the various parts of the system.
As we discussed, this request is handled first by a basic Servlet that dispatches to a JSP
page for formatting and display. The JSP is responsible for delegating the processing of
business functionality to a business delegate via a worker bean, which act as façades for the
back-end resources. We call this component a business delegate, because it is a client-side
business abstraction used to complete the basic business processing by abstracting out the
code that deals with the back-end communication. The worker beans might communicate
through the business delegate with the back-end via Enterprise JavaBeans components
running in a scalable, load-balancing container.
In this case, we are able to decouple the EJB implementation from the JSP worker bean by
moving the EJB-related code, such as the code relating to JNDI lookup, into the business
delegate. If we include our EJB-related code in our worker beans, then we are closely
coupling the bean to a specific underlying implementation, and if this implementation is
modified or changed we must make modifications to our worker bean accordingly. So we
have succeeded in creating abstractions that have reduced the coupling among the distinct
pieces of our system. We can see how the worker bean and the business delegate reduce
coupling between the client request and the ultimate back-end resource.
In other words, the public interfaces need not change even if the API to the underlying
resource changes. The worker beans can be combined with different JSP pages in order to
provide different views of the same underlying information. Also, the Servlet that initially
handles each request, and is responsible for authenticating each user, may restrict direct
access to our JSP pages, an added security mechanism. Once a >user has been successfully
authenticated, the Servlet might store certain information in that user's session, and access
to certain JSP pages might only be allowed to users whose session state contained such that
information. The mechanism could be made more fine grained by including authorization
information within this session state that would directly relate to which pages a user may
view.
Our baby guessing game example will need to change, in order to adhere to this new
design. The HTML user interface needs to change only slightly, adding an input field for each
user to enter a password. The table caption in Babygame1.html is modified as shown below
in order to add the password input field, and the revised file, babygame2.html, is placed in
<jswdk-root>/examples/jsp/mediatorview/:
<caption>
Please enter your userID:
<input type="text" name="guesser">
Please enter your Password:
<input type="password" name="password">
</caption>
>
The other change to the HTML is to change the hidden input field called dispatchto.
The Servlet uses this value to dispatch the request via the forward() method to the
appropriate JSP, and the value is supplied simply to allow for easy modification of these
examples. In this case we modify the value attribute to reference the JSP for our "Mediator-
View" example, and the modified line looks like this:
<input type="hidden" name="dispatchto"
value="/jsp/mediatorview/BabyGame2.jsp">
We have already seen the next piece of the puzzle in the Servlet, which handles each
request, authenticating each user and dispatching the request appropriately. The Servlet
and worker beans now contain Java code that is owned by an individual in the software
development role, and the syntax and semantics of which may be modified without any
changes to our JSP. The property sheets remain a simple contract between the web-
production team and the software developers.
The benefit of a dispatcher approach is in the control the Servlet has on the request. Since
the Servlet acts as the mediator, there is central forwarding control. As discussed, this also
creates a nice role separation between the lower level coding in the Servlet and the JSP
coding. A drawback of this architecture is that it involves more design work and more
coding, since individual beans are created instead of code fragments. A very simple project
might be overly burdened by this extra overhead, while more sophisticated efforts will
benefit from the cleaner design.
Additionally, encapsulating as much Java code as possible into our Servlet and beans, and
removing it from the JSP source, will also have the added benefit of encouraging more
elegant and refined Java coding, because excessive Java code embedded within JSP source
can quickly start to look like just another scripting language, and the cut-and-paste
mentality tends to take over. Moreover, a software developer will be more inclined to refine
code that they own, without potential dependencies and conflicts with a web-production
person. Of course the irony is that such unwieldy pages that are filled with Java code are in
more need than any of refactoring.
Updating our example to include improvements based on these very forces, we add to our
worker bean a factory that vends multiple storage implementations based on a
parameterized factory method. Our actual storage process may be modified easily and
dynamically, simply by providing an implementation that adheres to the Store interface. We
move our basic file storage code into an implementation called SimpleStore that implements
the Store interface and is created by StoreFactory. We don't actually include data access
code in this example, but it would reside in a worker bean and would reference the business
delegate, which could then reference an EJB component. The Store interface also hides
implementation details, in this case those of the storage mechanism behind it, exposing a
well-defined interface instead.
The initial delegation point in this architecture is a JSP – we will see later another
architecture in which the initial point of delegation is a worker bean (Service-to-Workers).
The subtle difference between the two is worth discussing. In situations where there is on-
going workflow that is necessary for the generation of the data model, requiring multiple
business calls, one needs to decide where to encapsulate these business calls:
• In one case, the JSP may contain the business calls that are required to obtain the
necessary state for the intermediate model, which will be stored in the associated
worker bean(s). The JSP is not only responsible for the presentation of the data, but
additionally has some responsibility for coordinating the business calls, and may
interact with different beans in order to present multiple views of the same
underlying models.
• On the other hand, if the Servlet delegates initially to a worker bean, then the
Servlet will need to adopt the responsibility for controlling these business calls,
utilizing the worker beans to make its requests. If the required data can be gathered
with a single business call, then dispatching this call to the worker bean directly
from the Servlet allows the bean to populate the entire intermediate model. The
Servlet is then able to forward the request to the JSP for presentation.
As you may have noticed, in the former scenario the JSP's responsibilities are increased as it
fulfills part of the role of the controller in addition to the view. One needs to decide what is
right for the job and move code forward or back based on the workflow and presentation
needs. One issue to consider is that adding business calls to a JSP page allows for reuse of
this code conditionally across requests simply by nesting pages, as in Mediator-Composite
View, which we will discuss shortly. Adding business invocations to the Servlet means either
that these calls will be invoked for each request the Servlet handles, limiting its potential for
reuse, or that the Servlet may become cluttered with conditional logic dictating which code
to execute for a particular request.
The elements of the current "Mediator-View" example are:
• The HTML UI, which POSTs the request to the Servlet: <jswdk-root>/examples/jsp/
mediatorview/babygame2.html
• The Servlet, which dispatches to the JSP: <jswdk-root>/examples/WEB-INF/
servlets/BabyGameServlet.java (source) and <jswdk-root>/examples/WEB-INF/
servlets/BabyGameServlet.class (bytecode)
• The JSP: <jswdk-root>/examples/jsp/mediatorview/BabyGame2.jsp
• The worker bean: examples.mediatorview.BabyGameWorker2.java
• The supporting source code: examples.mediatorview.StoreFactory,
examples.mediatorview.Store, examples.mediatorview.SimpleStore,
examples.mediatorview.StoreException, examples.auth.AuthenticatoFactory,
examples.auth.Authenticator, examples.auth.SimpleAuthenticator,
examples.auth.AuthContext, and examples.auth.SimpleAuthContext.
This supporting code must be included in the CLASSPATH that is used by the JSP engine.
The RequestDispatcher API
These architectures rely on a Servlet's dispatching a request to another resource. Prior to
the Servlet API 2.1, dispatching of requests to another dynamic resource was cumbersome,
and limited because it was not directly supported in the specification.
The Servlet API 2.1 introduces the RequestDispatcher. Accessible via the ServletContext,
the RequestDispatcher implementation can dispatch a request to either a static resource,
such as an HTML page, or another dynamic resource, such as a Servlet or JSP. A request
can be either 'forwarded' or 'included', and state can be made available to the dispatched
resource.
The include() method allows the programmatic equivalent of Server-Side Includes (SSI),
while the forward() method transfers control to the designated dynamic resource. A Servlet
that invokes RequestDispatcher.include() retains overall responsibility for the service
request, handling the response to the client. In this case, the Servlet has the opportunity to
do any sort of clean up after all the nested invocations have completed.
Once the Servlet dispatches to another dynamic resource with an invocation to
RequestDispatcher.forward(), though, the Servlet has completed its work. An example of
the latter type of forward dispatch is occurs in both the Mediator-View and Mediator-
Composite View architectures.
The method signatures that a Servlet may use to dispatch a request to another resource,
are:
public void forward(ServletRequest request,
ServletResponse response) throws ServletException,
java.io.IOException
Checkout -
Screenshot
A presentation component that is nested within another page will often represent a fairly
coarse-grained entity, such as the complete line-by-line inventory of the items in the
aforementioned shopping cart, but may be decorated with different header and footer
information based on the context of its usage within a page.
As an example, we will factor out the body of the presentation in our ongoing "Baby Game"
example, and decorate it with some headers and footers. So how has our code changed to
support this architecture?
Our HTML simply requires a change to the hidden input field dispatchto. Again, this value is
used to dispatch to the appropriate JSP and is used simply to allow for easy modification of
these examples. In this case we modify the value attribute to reference the JSP for our
'Mediator-Composite View' example. The modified line now looks like this:
<input type="hidden" name="dispatchto"
value="/jsp/mediatorcompositeview/BabyGame2.jsp">
This modified user interface is now in <jswdk-root>/examples/jsp/mediatorcompositeview/
babygame2.html
Also, we have created some files containing the static header and footer template text to be
included at runtime into our composite display. Here's an example of what one of these
header files looks like:
<center>
<H3><B>Baby Game 2000! Fun for the whole family!</B></H3><BR>
<hr>
</center>
<br>
><br>
This file includes the header template for the presentation that results from our "Mediator-
Composite View" example, as shown in the following screen shot:
Screenshot
The elements of the current example are then:
• The HTML UI, which POSTs the request to the Servlet: <jswdk-root>/examples/jsp/
mediatorcompositeview/babygame2.html
• The Servlet, which dispatches to the JSP: <jswdk-root>/examples/WEB-INF/
servlets/BabyGameServlet.java
• The outermost JSP: <jswdk-root>/examples/jsp/mediatorcompositeview/
BabyGame2.jsp
• The composite JSP, included within the outermost JSP: <jswdk-root>/examples/jsp/
mediatorcompositeview/compositeinclude.jsp
• The worker bean: examples.mediatorview.BabyGameWorker2
• The supporting code, which is reused unchanged from the previous example:
examples.mediatorview.StoreFactory, examples.mediatorview.Store,
examples.mediatorview.SimpleStore, examples.mediatorview.StoreException,
examples.auth.AuthenticatorFactory, examples.auth.Authenticator,
examples.auth.SimpleAuthenticator, examples.auth.AuthContext, and
examples.auth.SimpleAuthContext
This supporting code must be included in the CLASSPATH that is used by the JSP
engine.
• The static template text, which is included dynamically at runtime to create the
composite display: <jswdk-root>/examples/jsp/mediatorcompositeview/
gameheader.html, <jswdk-root>/examples/jsp/mediatorcompositeview/
gamefooter.html, <jswdk-root>/examples/jsp/mediatorcompositeview/
nestedheader.html, <jswdk-root>/examples/jsp/mediatorcompositeview/
nestedfooter.html.
The initial delegation point of the Service to Workers architecture, shown visually below, is a
worker bean that processes our business and data access code, once again via a client-side
business abstraction. As with each of the dispatcher architectures, the Servlet handles the
request from the client, providing the opportunity for the processing of common services.
After the worker bean has completed its responsibility of populating the intermediate model
for the JSP, the Servlet dispatches to the JSP to generate the presentation:
"Service to
Workers" architecture
This architecture provides a cleaner separation between the view and the controller, since
the JSP page is no longer making business calls, but simply accessing the state of the pre-
populated worker bean. Depending on the workflow needs of the system, a decision will
have to be made about the suitability of this architecture versus one where the initial
delegation point is a JSP, such as the Mediator-View. The cleaner separation of view and
controller is indeed an important factor in the decision as well, and often an overriding one.
Certainly, if there is not a need for multiple business calls to generate the intermediate
model, then this type of architecture is a good choice.
In some cases, though, we may only want portions of a model to be utilized in a display and
we may not want to reuse this code across requests. If the granularity of the data access
components necessitate multiple calls to retrieve the data, then the Mediator-View
architecture may be better suited to handle this type of situation, since the server page will
make business calls on the beans as necessary.
Our example will allow an authenticated user to examine his or her previously stored
guesses. One could imagine this feature being expanded to allow modification of the
previously stored data, as well.
The HTML for the user interface consists of a couple input fields for the user to enter their id
and password for authentication purposes. The dispatchto hidden field has been modified
appropriately, and another hidden field, a flag called delegatetobean, has been added, and
signals to the Servlet that we want to use our worker bean as the initial dispatch point in
this scenario. It allows us to reuse the Servlet that we have been utilizing throughout our
discussion with minor modifications. The screen shot below shows this HTML page:
Baby Game
- Screenshot
The HTML source for this page, <jswdk-root>/examples/jsp/servicetoworkers/
babygameSW.html, is as follows:
<!-- babygameSW.html -->
<html>
<head>
<title>Baby Game -- Retrieve stored guesses</title>
</head>
<body bgcolor="#FFFFFF">
<form method="post" action="/examples/servlet/BabyGameServlet" name="">
<center>
<h3>
Baby Game -- Retrieve stored guesses</h3></center>
<center>
<hr>
><br>
Please enter your userID:<input type="text"
name="guesser"><br><br>Please enter your Password:<input
type="password" name="password">
<br><br>
<input type=hidden name="dispatchto"
value="/jsp/servicetoworkers/BabyGameSW.jsp">
<input type=hidden name="delegatetobean" value="true">
</form>
</body>
</html>
The Servlet has been modified to include a conditional check for the delegatetobean flag. If
it is set, then the Servlet uses the worker bean as the initial delegation point. In previous
examples, the Servlet uses the JSP as the initial delegation point.
Adding this conditional, which will evaluate to true in this Service to Workers example only,
allows us to reuse similar Servlet code throughout our discussion; the Servlet source is
shown below. After successfully authenticating the user, the Servlet delegates to the worker
bean (BabyGameWorkerSW), instructing it to load previously stored guesses based on the
user's id. The worker bean is set as an attribute of the request object with the same bean id
that is used in the presentation JSP (an id value of "SWworker"). This allows the JSP to
share this previously instantiated and initialized bean, instead of creating a new one. In
effect, we have passed the bean as an argument to the JSP.
The code for the Servlet is as follows, and is kept in <jswdk-root>/examples/WEB-INF/
servlets/BabyGameServlet.java:
import javax.servlet.*;
import
javax.servlet.http.*;
import
java.io.*;
import
examples.auth.*;
import
examples.servicetoworker.BabyGameWorkerSW;
public
class BabyGameServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response) {
processRequest(request, response);
}
Authenticator auth =
AuthenticatorFactory.create(AuthenticatorFactory.SIMPLE);
AuthContext authContext =
AuthenticatorFactory
.createContext(AuthenticatorFactory.SIMPLE);
authContext.addValue("guesser", guesser);
authContext.addValue("password", password);
auth.init(authContext);
if (auth.authenticate()) {
String dispatchto = request.getParameter("dispatchto");
String delegateToBean =
request.getParameter("delegatetobean");
// Delegate to worker bean
if (delegateToBean != null) {
BabyGameWorkerSW worker = new BabyGameWorkerSW();
worker.load(guesser);
request.setAttribute("SWworker", worker);
}
<br>
<jsp:getProperty name="SWworker"
property="guesser" />, here are your previously stored
choices:<br>
<table BORDER COLS=5 WIDTH="75%"
>
<caption></caption>
<tr>
><td> <jsp:getProperty name="SWworker" property="gender" />
</td>
<td>
<jsp:getProperty name="SWworker"
property="pounds" /> lbs
<jsp:getProperty name="SWworker" property="ounces" />oz
</td>
<td>
<jsp:getProperty name="SWworker"
property="month" /> <jsp:getProperty name="SWworker" property="day" />
</td>
<td>
<jsp:getProperty name="SWworker"
property="length" /> inches
</td>
</tr>
</table>
<br>
</BODY>
</HTML>
The full elements of the "Service To Workers" example are:
• The HTML UI, which POSTs the request to the Servlet: <jswdk-root>/examples/jsp/
servicetoworkers/babygameSW.html
• The Servlet, which dispatches to the JSP: <jswdk-root>/examples/WEB-INF/
servlets/BabyGameServlet
• The JSP: <jswdk-root>/examples/jsp/servicetoworkers/BabyGameSW.jsp
• The ErrorPage: <jswdk-root>/examples/jsp/servicetoworkers/errorpageSW.jsp
• The worker bean: examples.servicetoworker.BabyGameWorkerSW
• The supporting code, which is reused from a previous example:
examples.mediatorview.StoreFactory, examples.mediatorview.Store,
examples.mediatorview.SimpleStore, examples.mediatorview.StoreException,
examples.auth.AuthenticatorFactory, examples.auth.Authenticator,
examples.auth.SimpleAuthenticator, examples.auth.AuthContext, and
examples.auth.SimpleAuthContext
JSPs can be used for most purposes, but there are some scenarios where Servlets are more
appropriate. As well as components such as the "mediator" Servlets used earlier in this
chapter, Servlets are well suited for handling binary data dynamically (for example,
uploading files or creating dynamic images), since they need not contain any display logic.
Consider the following: a JSP needs to display a banner image based on who is referring the
user to the site. This can be done by using the IMG tag like this:
<%@ page import="com.ibm.jspredbook.*;" errorPage="error.jsp" %>
<body bgcolor="#FFFFFF">
<!--the referer header is used to trap the url the user is coming from -->
<IMG SRC="/servlets/ImgServlet?from=<%=request.getHeader("Referer")%>">
</body>
</html>
The Servlet referenced in the IMG tag, ImgServlet, is coded as:
package com.ibm.projsp;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.*;
servletoutputstream.flush();
}
finally {
if (fileinputstream != null) {
fileinputstream.close();
}
}
}
}
This image can be cached in memory and updated every minute or so as needed. Keeping
the data in memory and using a servlet can save time and improve performance by not
requiring access to the file system every time a request is made.
We have examined how we architect systems using JSPs, Servlets, and JavaBeans,
discussed benefits and limitations of various approaches and actually seen an example that
evolves to satisfy the constraints of the various architectures.
We discussed a variety of architectural patterns, each of which we categorized as either a
Page-Centric or Dispatcher type of architecture. Page-Centric architectures have a JSP
handling the request directly, while Dispatcher architectures include a Servlet that handles
the request and delegates to a JSP.
The architectural patterns we examined are:
• Page-View (Page-Centric)
• Page-View with Bean (Page-Centric)
• Mediator-View (Dispatcher)
• Mediator-Composite View (Dispatcher)
• Service-to-Workers (Dispatcher)
As we continue to investigate new ways to build our systems, we will continue to realize
new architectural patterns. Additionally, the specifications for these technologies continue to
be refined and improved in ways that will potentially demand modifications to current
architectural patterns and the realization of additional ones. The ability (in the post-1.0 JSP
specifications) to factor code and implementation details into a Custom Tag that might be
used in place of a JavaBean is simply one example. The integration of these technologies
more closely with XML and XSLT is another.
This is certainly an exciting and important area of technology that continues to change at a
rapid pace. Hopefully, this information will help you better understand the current state of
affairs with respect to JSP architectures, and thus feel better positioned to follow the
evolution of these architectural issues in the future.