[ Team LiB ] Previous Section Next Section

Calling Multiple Controllers and Views

One of the things you will notice in the controller servlet is that it has direct knowledge of the JSP that is handling the view—the name of the view that the JSP is coded in. You should strive to break such dependencies whenever you can. What happens if you want to do things exactly the same way in the controller but display a different view of the data?

The controller should be concerned with sending information to the model, and the view should be concerned with displaying the output. The only thing that ties the controller to the view at the moment is the fact that the controller contains the logic to forward the request on to the view. The way to completely separate the controller from the view is with a dispatcher servlet.

A dispatcher performs the crucial transition between the controller and the view. Instead of invoking a controller directly, you call the dispatcher and tell it which controller you want to call and which view to display. That way, the controller doesn't have any specific view hardwired into its code. Likewise, the dispatcher doesn't have a view hardwired in, either.

Don't Confuse This Dispatcher with RequestDispatcher

graphics/bytheway_icon.gif

This is not the same dispatcher as the RequestDispatcher class that is part of the Servlet API. This section of the book refers to a dispatcher in the generic sense.


You can even have the dispatcher call multiple controllers before invoking a view. That way, you can break your business logic down into finer-grained pieces. When the client sends a request to the server, it may invoke several controllers to update various portions of the model before displaying the view.

Listing 20.4 shows the dispatcher servlet. In this example, you use parameters (form variables) named controller to pass the controllers. The pathname for the default view is passed in the view parameter, whereas the pathname for the error-handler view is passed in the errorView parameter.

Listing 20.4 Source Code for DispatcherServlet.java
package examples;

import javax.servlet.*;

public class DispatcherServlet extends GenericServlet
{
    public void service(ServletRequest request,
        ServletResponse response)
        throws java.io.IOException, ServletException
    {

// Get the list of controllers to call.
        String[] controllers =
            request.getParameterValues("controller");

// Get the name of the view to call.
        String viewName = request.getParameter("view");

// Get the name of the view to call if there is an error.
        String errorViewName = request.getParameter("errorView");

        try
        {
            for (int i=0; i < controllers.length; i++)
            {
                RequestDispatcher d =
                    getServletContext().
                        getRequestDispatcher(
                            controllers[i]);
                if (d != null)
                {
// Invoke the next controller.
                    d.include(request, response);
                }
                else
                {
                    getServletContext().log(
                        "No controller named " +
                        controllers[i]);
                }
            }

            RequestDispatcher d = getServletContext().
                getRequestDispatcher(viewName);

// The dispatcher includes the other controllers, but it forwards to the view.
            if (d != null)
            {
                d.forward(request, response);
            }
            else
            {
                getServletContext().log(
                    "No view named "+ viewName);
            }
        }
        catch (Exception exc)
        {
// If there is an error, forward to the error view.

            request.setAttribute("exception", exc.toString());

            RequestDispatcher d = getServletContext().
                getRequestDispatcher(errorViewName);

            if (d != null)
            {
                d.forward(request, response);
            }
            else
            {
                getServletContext().log(
                    "No errorView named " + errorViewName);
            }
        }
    }
}

To use this dispatcher with the ControllerServlet, you need to strip a few things out of the controller. You no longer need to include the calls to gotoPage because the dispatcher is handling that. Also, rather than have it call the error page, make the controller throw a ServletException with the reason for the error. Listing 20.5 gives the source for the modified ControllerServlet.

Listing 20.5 Source Code for ControllerServlet2.java
package examples;

import java.io.*;
import java.util.*;
import javax.servlet.*;

public class ControllerServlet2 extends GenericServlet
{
    private static Person[] people = new Person[]
    {
        new Person("Samantha Tippin", 9, "770-123-4567"),
            new Person("Kaitlyn Tippin", 6, "770-123-4567"),
            new Person("Edward Alexander", 3, "No phone"),
            new Person("Star Alexander", 3, "Phone off hook"),
            new Person("Norton Alexander", 12, "No phone")
    };


    public synchronized void service(ServletRequest request,
        ServletResponse response)
        throws java.io.IOException, ServletException
    {
        String minimumAgeStr = request.getParameter("minAge");
        int minimumAge = 0;

        try
        {
            minimumAge = Integer.parseInt(minimumAgeStr);
        }
        catch (Exception exc)
        {
            throw new ServletException("Invalid minimum age");
        }

        String maximumAgeStr = request.getParameter("maxAge");
        int maximumAge = 0;

        try
        {
            maximumAge = Integer.parseInt(maximumAgeStr);
        }
        catch (Exception exc)
        {
            throw new ServletException("Invalid maximum age");
        }

        // Get all the people matching the criteria
        Vector v = new Vector();

        for (int i=0; i < people.length; i++) {
            if ((people[i].age >= minimumAge) &&
                (people[i].age <= maximumAge)) {
                v.addElement(people[i]);
            }
        }

        // Store the vector of person objects so the JSP can access it
        request.setAttribute("people", v);
    }
}

You don't need to change anything in the ShowPeople.jsp page to make it work with the dispatcher. The only other thing you need to do is modify the initial HTML form. It now needs to pass parameters to the dispatcher to tell it which controller and view to use. You can insert the information as hidden form variables so that it is automatically passed when the user submits the form. Listing 20.6 shows the modified HTML form.

Listing 20.6 Source Code for PeopleQuery2.html
<html>
<body>

Please enter the minimum and maximum ages to view:
<P>
<form action="/DispatcherServlet" method="post">

<input type=hidden name="controller"
    value="/ControllerServlet2">
<input type=hidden name="view" value="/ShowPeople.jsp">
<input type=hidden name="errorView"
    value="/ErrorHandler.jsp">

Minimum Age: <input type="text" name="minAge"><br>
Maximum Age: <input type="text" name="maxAge"><br>
<P>
<input type="submit" value="Perform Query!">
</form>
</body>
</html>
    [ Team LiB ] Previous Section Next Section