JaVa
   

Constructing the View for the Reservations Page

As we examine different view technologies in this chapter, let's consider a simple dynamic page as an example. Last chapter we examined the controller code in the processSeatSelectionFormSubmission() method of the com.wrox.expertj2ee.ticket.web.TicketController class. This method handles submission of a form that allows the user to request the reservation of a number of seats of a specified type (such as "Premium Reserve") for a particular performance.

Information Presented and Required Formatting

Two views can result from processing this request:

In this chapter, we'll use the "Show Reservation" view as an example. The "Not Enough Seats" view is completely distinct. Part of the point of using a controller to handle a request is that it enables us to choose one of several possible views depending on the outcome of the necessary business operations. The "Show Reservation" screen looks like this:

Java Click To expand

It displays the following dynamic information:

Currency display and date and time display should be appropriate to the user's locale. There is one variant of this view, which is displayed if there were enough seats to satisfy the user's request, but they are not adjacent. In this case, the user should be given the opportunity to abandon this reservation and try to tutorial on another date. We need to add an additional section highlighting the potential problem and providing a link to try to tutorial for another performance. Whatever view technology we use must be able to handle this simple conditional: this is the same view with a minor, presentational, difference, not a distinct view like the notEnoughSeats view.

Java Click To expand

The Model Behind this View

The model returned by the controller's processSeatSelectionFormSubmission() method when it chooses the "Show Reservation" view contains three objects:

The performance and priceband objects are reference data, shared among all users of the app. The reservation object is unique to the current user. The three types are interfaces, not classes. The returned objects will be of implementation classes that expose methods that allow some of their state to be manipulated. This is best concealed from views, so we choose not to code views to the mutable classes (views should treat models as read-only). The use of interface-based design also allows the potential for different implementations. Let's look at some of the important methods in each of these interfaces in turn. Please refer to the sample app source code for a complete listing of each. Both the Performance and PriceBand interfaces are part of an abstract inheritance hierarchy based on com.wrox.expertj2ee.ticket.reference.ReferenceItem, which exposes a numeric id and a name or code as follows:

 public interface ReferenceItem extends Serializable {
 int getId();
 String getName();
 }


It's worthwhile ensuring this basic commonality between reference data objects as it saves a little code in concrete implementations, which use a parallel inheritance hierarchy, and makes it easy to treat objects consistently. For example, reference items can be indexed by id whatever their subtype, to allow for rapid lookup. The following UML class diagram illustrates the inheritance hierarchy:

Java Click To expand

The following diagram shows how reference data instances of the types shown above are assembled into a tree at run time. Each object provides methods to navigate downwards, through its children (for the sake of simplicity, I've only expanded one Show and one Performance:

Java Click To expand

The Performance interface, part of the model for the "Show Reservation" view, extends ReferenceItem to expose a link to the parent Show object, as well as the performance's date and time and a list of PriceBand objects for that performance:

 public interface Performance extends ReferenceItem {
 Show getShow();
 Date getWhen();
 List getPriceBands();
 }


PriceBand objects add seat price to the information about seat types such as the name or code (such as AA) and description (such as Premium Reserve) exposed by the SeatType interface. The following is a complete listing of these two simple interfaces:

 public interface SeatType extends ReferenceItem {
 int getSeatTypeId();
 String getDescription();
 }
 public interface PriceBand extends SeatType {
 public double getPrice();
 }


The com.wrox.expert.j2ee.ticket.boxoffice.Reservation interface exposes user-specific information. A Reservation object is created when seats are reserved for a user, and contains a reference to the ReservationRequest object (a command generated by the user) that caused the reservation to be made. A Reservation isn't reference data, but dynamic data created when a user successfully completes the first step of the-booking process. Note that a Reservation is serializable. We will need to put Reservation objects in a user session: we need to ensure that this is possible in a clustered environment. I've highlighted the methods relevant to views:

 public interface Reservation extends Serializable {


The following method returns an array of the Seat objects reserved for the user:

 Seat[] getSeats();


The following method indicates whether or not these seats are adjacent. As we've seen, presentation logic may depend on this information, but determining whether or not a set of seats is adjacent isn't presentation logic, as it will involve understanding of the relevant seating plan:

 boolean seatsAreAdjacent();


 int getMinutesReservationWillBeValid();
 double getTotalPrice();
 ReservationRequest getQuoteRequest();


The following methods are used only by controllers:

 long getTimestamp();
 String getReference();
 boolean isReserved();
 boolean satisfiesRequest (ReservationRequest r);
 }


Please refer to these listings as necessary to understand the view code shown below.

None of these model objects is web-specific. In fact they're not even UI-specific, which means that we can easily write test harnesses that check for expected results, and could easily use these objects as the basis of a web services interface.

Model Principles

The design of these models raises some important points relating to all models that may be used in web apps:

Since the web app framework introduced in enables us to return a Map, rather than a single object, as model, we don't need to create a single container object to hold all this information in one object. Such an object would be unique to this page, so by not needing to create one we've avoided creating what would be a web interface-specific object.

Important 

Model objects used in web interfaces don't need to - and should not - be web-specific. For example, they should never expose markup or other formatting information.

Following a few golden rules will ensure that model objects provide maximum value to views, whatever the view technology used:

Sometimes the second of these four rules can best be followed by creating an adapter bean: a value object that caches and exposes all model data needed by one or more views in a way that makes it simple to access. For example, an adapter might expose via bean properties data retrieved by method calls on several non-bean objects with complex interfaces. In such cases, the adapter simplifies the data interface available to views and suppresses unwanted, distracting information. We have no need for this adapter approach in the sample app, as domain objects such as the Reservation object are naturally suited to use as models without any design compromises being necessary.

If an adapter bean is used, it should be created by the relevant controller, not the view. Although it is easy for JSP pages to create adapter beans, and this approach is sometimes advocated, this breaks the principle of view substitutability.

JaVa
   
Comments