New to Java? We'll help you get started with our revised beginner's tutorial, or our free online textbook.


Get the latest Java books
h t t p : / /w w w . j a v a c o f f e e b r e a k . c o m /

Java Coffee Break

Menu



Learning Java

Articles
Author Profiles
Lessons
FAQ's
Books
Newsletter
Tutorials
Talk Java!

Using Java

Applets
JavaBeans
Servlets
Resources
Discuss Java


Looking for Java resources? Check out the Java Coffee Break directory!

Professional JSP Excerpt
Part Three : The "Dispatcher" Approach

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 workers architectures.

In an N-tier application, the server side of the architecture is broken up into multiple tiers, as illustrated in the next figure:

 

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:

These categories are analogous to the Model-View design pattern, where the front-end component is the model and the presentation component the view. This approach was referred to as the "Model 2" programming model in earlier releases of the JSP specifications. It differs from Model 1 essentially in the location at which the bulk of the request processing is performed. The figure below shows the Model 2 approach:

 

In this approach, JSPs are used to generate the presentation layer, and either JSPs or Servlets to perform process-intensive tasks. The front-end component acts as the controller and is in charge of the request processing and the creation of any beans or objects used by the presentation JSP, as well as deciding, depending on the user's actions, which JSP to forward the request to. There is no processing logic within the presentation JSP itself: it is simply responsible for retrieving any objects or beans that may have been previously created by the Servlet, and extracting the dynamic content for insertion within static templates.

Instead of writing Servlets for the front-end components you can choose, if you wish, to use a JSP that contains only code and doesn't have any presentation responsibilities. Whichever option is used (and in this chapter we only use Servlets in this role), this approach typically results in the cleanest separation of presentation from content, leading to delineation of the roles and responsibilities of the developers and page designers, especially in complex applications.

Beans that are used by JSPs are not the same as Enterprise JavaBeans (EJBs), but are usually simple classes that serve as data wrappers to encapsulate information. They have simple get and set methods for each bean property .The properties further correspond by name to the HTML variables on the screen. This allows the bean properties to be set dynamically by the jsp:usebean tag without doing an individual request.getParameter(parametername) on the request object. See Chapter 4 for bean usage.

Mediator-View

Factoring common services, such as authentication out to a mediating Servlet allows us to remove potential duplication from our JSP pages. The code below is an example of a Servlet that provides us with central forwarding control for our game system, and includes a simple authentication check that will be reused across requests. A Bean could be used for this purpose, but you would have to add the same code to each page to perform the authentication checks. Instead, each request will be serviced by the Servlet, which now includes our authentication code.

The mediating Servlet, BabyGameServlet.java, is shown below. It is placed in the <jswdk-root>/examples/WEB-INF/servlets/ directory:

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

 

public class BabyGameServlet extends HttpServlet {

public void doGet(HttpServletRequest request,

HttpServletResponse response) {

processRequest(request, response);

}

 

public void doPost(HttpServletRequest request,

HttpServletResponse response) {

processRequest(request, response);

}

 

protected void processRequest(HttpServletRequest request,

HttpServletResponse response) {

 

try {

// If we added actual authentication, this is where it would go

// For example purposes, if the parameters exist, we consider the

// auth successful.

if ((request.getParameter("guesser") != null)

&& (request.getParameter("password") != null)) {

 

// Note: Based on the successful authentication of this user we may

// want to consider writing something into the session state that

// signifies that this is the case. For example, if we wanted to

// limit direct access to certain JSP pages only to authenticated

// users, then we could include code that would check for this

// session state before allowing such access.

 

// In order to reuse this Servlet for multiple examples, we pass as

// a request parameter the resource name to which we dispatch our

// request.

getServletConfig().getServletContext()

.getRequestDispatcher(request.getParameter("dispatchto"))

.forward(request, response);

} else {

PrintWriter outy = response.getWriter();

outy.println("Unable to authenticate, please try again.");

}

} 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:

 

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

 

public void include(ServletRequest request, ServletResponse response)

  throws ServletException, java.io.IOException

Here is an example from within a Servlet:

RequestDispatcher dispatcher =

  getServletContext().getRequestDispatcher("process.jsp");

request.setAttribute("user", user);

dispatcher.forward(request, response);

For a detailed description of the Servlet API, see Appendix C.

Mediator-Composite View

Sometimes we are building systems with dynamic template text as well as dynamic content. In other words, there is content being generated dynamically, and the template text that surrounds this data is also being constantly changed. Imagine that there are headers and footers in a page that are modified quite often, notifying individuals of status changes or information of special interest. It may not be desirable to recompile our JSP source each time this template text changes, since this involves a run time delay and resource load. If we simply type our header and footer text directly into our JSP source, then we will need to modify that source each time we want to change the template text, and our modified source will need to be re-translated in order to service another request, causing this run time latency, and this scenario will repeat itself each and every time the text undergoes even slight modification.

Moving the header and footer template text to external files provides us with a solution to this dependency on run time re-translation when our template changes. We move a portion of the template text from our JSP source to another file, replacing it with the JSP include action:

<jsp:include page="header.html" flush="true" />

Unlike its counterpart the include directive (signified with <%@), which includes text at translation time, the JSP include action substitutes the designated page into the JSP source at run time. Not only have we made our solution more modular, we have provided a way to change template text on the fly without the need for recompiling our JSP source. Of course, there is a run time cost for this processing, but it is far less expensive than a full source compile. Such flexibility is useful, especially since the JSP specification does not include much coverage of pre-compilation. 

Not only can we dynamically include resources, such as static HTML template fragments within our JSP source, but we can also include other JSPs, creating a multiple-level nesting of pages. In this case, the presentation is built from numerous static and dynamic resources, which together make up the page presented to the user. Each of these resources is potentially composed of additional nested pages. Although the HTML template text is considered a static resource, meaning it is not generated dynamically at run time, these template fragments are potentially a dynamic piece of the interface, since each can be modified continually with immediate updates occurring in the containing presentation. This 'Mediator-Composite View' architecture is shown visually below:


Each of these architectures builds on the previous ones in some way, and in this case we have modified the middle of the 'Mediator-View', while inheriting the front and back. As with the other dispatcher architectures, the Servlet mediator dispatches to a JSP, which imports the aforementioned static and dynamic resources. The figure above shows this nested server page including dynamic content generated via an invocation on a helper bean, which gets to the business processing through a delegate which once again acts as a façade to the back- end resource that may be "wrapped" in an Enterprise JavaBeans component.

As we have seen, the role of the delegate as a client-side business abstraction layer is to make business calls on the actual back-end resource, such as remote invocations on an Enterprise JavaBeans component. Once again, the role of the worker bean is to service the JSP page, preparing data for use and dynamic presentation by the page. The worker bean serves as an intermediate model for the JSP with which it is paired. Again, we are creating a more flexible architecture by abstracting out the worker bean and the business delegate, so that the model for the JSP is not actually responsible for remote invocations on business resources, and these two distinct parts of the system are more loosely coupled.

This architecture allows us to abstract out portions of our page, creating atomic pieces that can be plugged into a composite whole in different configurations. For example, a checkout page on a shopping site might present a user with the contents of a shopping cart. It is easy to imagine the shopping cart component as an atomic portion of the presentation that might be included by other pages, as well, such as a page that allows a user to survey, modify, or remove their current selections while still in "shopping" mode, as shown in the next two figures:

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:

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.

Service to Workers

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:

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:

 

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">

 

<input type=submit value="Retrieve">

 

</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);

}

 

public void doPost(HttpServletRequest request,

HttpServletResponse response) {

processRequest(request, response);

}

 

protected void processRequest(HttpServletRequest request,

HttpServletResponse response) {

try {

String guesser = request.getParameter("guesser");

String password = request.getParameter("password");

 

// Authenticate each request

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);

}

 

// In order to reuse this Servlet for multiple examples, we pass

// as a request parameter the resource name to which we dispatch

// our request

getServletConfig().getServletContext()

.getRequestDispatcher(dispatchto)

.forward(request, response);

} else {

PrintWriter outy = response.getWriter();

outy.println("Unable to authenticate, please try again.");

}

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

In our earlier examples, we collected and stored a user's guesses to a text file. Now the example evolves such that the worker bean called examples.servicetoworker.BabyGameWorkerSW adds a method that loads our previously stored guesses from the store, based on an authenticated user's id. The method is defined as follows:

public void load(String id) {

  try {

    Store storer = StoreFactory.createStore(StoreFactory.SIMPLE);

    Properties props = (Properties) storer.load(id);

    setProperties(props);

  } catch (StoreException e) {

    e.printStackTrace();

  }

}

Additionally, the worker bean has a method that is included so that our example may make use of JSP error processing. The method is invoked as a guard clause from within the JSP in order to validate the accuracy of the data before it is presented to the user. The method throws an exception if the bean's state is incomplete, and is defined as follows:

 

public void validationGuard() throws Throwable {

  if (getGender() == null) {

    throw new Throwable("Error populating guess data.");

  }

}

 

The JSP, <jswdk-root>/examples/jsp/servicetoworkers/BabyGameSW.jsp, is shown below. Notice that it includes an explicit reference to an error page:

<HTML>

<HEAD><TITLE>Baby Game - Your Guesses</TITLE></HEAD>

<BODY bgcolor=FFFFFF>

<%@ page language="java" errorPage="errorPageSW.jsp" buffer="8k" %>


If an uncaught exception occurs within a JSP, the flow of control immediately transfers to the referenced error page, in this case errorPageSW.jsp. As mentioned, the JSP includes a guard clause at the beginning, which checks for valid data. If valid data does not exist, then the worker bean will throw an exception, which will present the error page to the user, notifying him or her of the problem. In our example, if the client enters an id and password for a valid user who has not previously stored any guesses, then the bean state will be invalid and the bean's validationGuard() method will indeed throw an exception. The error page display could easily be made as informative as necessary for the user:

<jsp:useBean id="SWworker" class="examples.servicetoworker.BabyGameWorkerSW" scope="request" />

Notice also that the JSP has the same bean id that the Servlet previously included in its setAttribute() invocation. Thus, the JSP will reuse the existing bean, which was created in the Servlet: 

<jsp:setProperty name="SWworker" property="*" />

 

<% SWworker.validationGuard(); %>

 

<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

prev .... | next ....

Back to main


Copyright 1998, 1999, 2000 David Reilly

Privacy | Legal | Linking | Advertise!

Last updated: Monday, June 05, 2006