Using J2EE Design Patterns
Design Patterns in the VSM
The VSM sample application demonstrates ways to implement
the following design patterns.
The MVC design pattern differs from the others discussed in
this article, which describe ways to solve specific programming problems or
perform specific tasks, because the MVC design pattern describes an approach
to an application as a whole. The approach is multi-tiered and modular; the
MVC design pattern identifies three entities, each operating in a different
logical layer within the application space:
- Model: A back-end representation of enterprise data
and business logic, the model also maintains data about the state of the application.
In many cases, the model is a logical representation of a real-world process.
- View: The front-end presentation layer that renders
the model for end-users. Views also provide user interfaces for accessing
the enterprise data represented by the model.
- Controller: The middle tier of the MVC pattern.
The controller defines application behavior, selecting views for presentation
and capturing a user's interactions with views and routing them as commands
to the model.
The MVC design pattern defines a clear separation of application
logic, presentation details, business rules and data. As a result, multiple
clients, displays, and devices can use the same application and business rules
to work with the same data. The following figure shows how model, view, and
controller interact.

- The model is implemented by EJBs and other Java
classes, many of which represent real-world objects. such as shops, shopping
carts, and orders. For implementation examples, see
Shops.java,
ShopsBean.java, and ShopsHome.java.
- The views are provided by JavaServer Pages (JSPs)
rendered in a browser. Examples include
shoppingMall.jsp, mallAdmin.jsp,
and cart.jsp.
- The central controller is implemented in
RouterServlet.java.
When an end-user interacts with a view (for example, by submitting a form),
this HTTP servlet dispatches the action to a controller object, such as LoginController
orCartController, as appropriate, which in turn invoke methods
on objects in the model.
The process of dispatching and executing commands is itself
captured in a design pattern, Command Façade,
discussed in the next section.
Command Façade
The Command Façade design pattern describes a way to
work with method calls as objects. Without the Command Façade design
pattern, a client must find an object, hold a reference to it, then use that
reference to call a method. Using the Command Façade design pattern,
a client issues commands by name, and a command object dispatches each command
to a method call on an underlying EJB. This encapsulation of commands presents
a consistent interface to clients while hiding implementation details--developers
are free to change the back-end implementation (model or controller) without
fear of breaking the presentation layer (view). Also, commands are cached in
a history list so that they can be reused, improving performance.
The VSM implements this design pattern
in several files, including RouterServlet.java, Command.java,
and CommandCache.java. When the main VSM controller (RouterServlet)
receives a request from a view, its service method executes and
invokes the Java class RequestMap to load the values from requestmap.xml
into a Hashtable, thereby mapping the URI to a Controller class.
The RequestMap class maintains these values in a Hashtable so that
subsequent calls can be made from memory instead of reading the properties file
each time.
The following figure shows two event sequences. First, it
shows what happens when the RouterServlet is initialized: it initializes
the RequestMap class, which in turn reads mappings from requestmap.xml.
The second sequence shows what happens later in the application life cycle when
an end-user sends a command (in this case, to remove an item from the shopping
cart).

Here is a portion of requestmap.xml, which maps
URIs to methods. This example maps the /remove URI to the removeItem
method of the CartController class, and specifies cart.jsp
as the page to display for the resulting view.
<?xml version="1.0"?> <mappings>
...
<uri-mapping> <uri>/remove</uri> <jsp-template>jsps/mallUser/cart.jsp</jsp-template> <controller class="oracle.otnsamples.vsm.controllers.CartController" method="removeItem"/> <security> <authenticate>false</authenticate> <invalidate-session>false</invalidate-session> </security> </uri-mapping>
...
</mappings>
|
The following code comes from Command.execute.
Given a URI submitted with a client request, this code searches the request
map for the corresponding controller and method, then invokes the method on
that controller. Then it returns the response to the RouterServlet
which parses it to find out which JSP to invoke for the next client view.
public class Command {
...
public UserResponse execute( String uri, Hashtable request, UserSession session, String controller ) throws InvalidURIException, BusinessException { // Initialize Response object UserResponse response = null; try { // Provides access to the required method on the Controller Class Method methodObject = null; // Create the controller object only if not created previously if( baseController == null ) { baseController = (BaseController)Class.forName( controller ).newInstance(); } // Check the cache for method object if( uriMethodMap.containsKey( uri ) ) { methodObject = (Method)uriMethodMap.get( uri ); } else { // An array of Class objects that identify the method's formal // parameter types in declared order Class[] paramTypes = new Class[] { Hashtable.class, UserSession.class }; // Get the method name from the RequestMap and instantiate the method String methodName = RequestMap.getInstance().getMethod( uri ); methodObject = baseController.getClass().getMethod(methodName, paramTypes); // Cache this method object uriMethodMap.put( uri, methodObject ); } // Create an object array of the parameters to be passed to the method Object[] params = { request, session }; // Execute the method on the specified controller object using reflection response = (UserResponse)methodObject.invoke( baseController, params ); } catch ...
} // Return the response from the Controller return response; }
...
}
|
Session Façade
The Session
Façade design pattern is useful in situations where client objects
need to interact with a set of EJBs to perform tasks in a workflow. For example,
in the VSM environment, customers browse shops and order products, shop owners
track orders and maintain inventory, and adminstrators approve and reject requests
for new shops and manage category lists. In an implementation where client objects
interact directly with the underlying EJBs, the following problems can arise:
- When an EJB's interface changes, client objects must also
be updated. This situation is analogous to the brittle class problem common
in object-oriented programming.
- To carry out a workflow, client objects must make numerous
remote calls to access the EJBs, leading to increased network traffic and
reduced performance.
A session façade solves such problems by presenting
client objects with a unified interface to the underlying EJBs. Client objects
interact only with the façade, which resides on the server and invokes
the appropriate EJB methods. As a result, dependencies and communication between
clients and EJBs is reduced. A session façade can also simplify transaction
management: for example, when a database transaction involves multiple method
calls, all could be wrapped in one method of the façade and the transaction
could be monitored at that level.
In the VSM, the CartManagerBean implements a
session façade that provides an interface to the EJBs that manage the
items in a customer's shopping cart. The CartManagerBean exposes
the checkOutCart method to clients, encapsulating inventory management
and order creation tasks performed by underlying objects InventoryManager
and OrdersBean (accessed via OrdersHome).
public StringBuffer checkOutCart( ShoppingCart cart ) throws CartException { try { // Get the order home OrdersHome home = (OrdersHome)ServiceLocator.getLocator(). getService( "Orders" );
...
// For each item in the cart for( int i = cart.getItems().length - 1; i >= 0; i-- ) { currentItem = (CartItem)cart.getItems()[i]; // check the inventory if( !InventoryManager.inventoryCheck( currentItem.getID(), currentItem.getQuantity() ) ) { response.append( "Failure," ); response.append( currentItem.getID() ); response.append( "," ); response.append( InventoryManager.getInventory(currentItem.getID())); continue; }
...
// Create the order and add it to the table order = home.create( new Integer( orderID ), details ); shops.put( shopID, order ); } ...
// Add it to the order for the shop order.setOrderItemID( item ); cart.removeItem( i ); } if( response.length() < 1 ) { response.append( "Checked out your cart successfully" ); } return response;
...
}
...
}
|
The following figures show this client-EJB interaction with
and without the session façade, and how the session façade reduces
network traffic.
| Without Session Façade |
With Session Façade
(CartManagerBean) |
|
|
|
Value Object
The Value
Object design pattern (also known as Data Transfer Object) describes a container
for a set of related data. It is often (but not necessarily) used with the Session
Façade pattern to reduce network traffic and the number of method calls
required to get an entity's attribute values. For example, when a customer uses
the VSM to buy a product, the application generates an order comprising several
attributes including order ID, order date, customer name, and shipping address.
To retrieve the details of an order, an application that does not implement
the Value Object pattern would have to make a remote get method
call for each attribute (example: Orders.getOrderID), adding to
network traffic and increasing EJB container resource usage.
In contrast, the VSM implements the Value Object design pattern
in several places, creating a container object and sending it across the network
to the client, which can then access the data via local method calls. For example,
the following code from CartManagerBean.checkOutCart uses an OrderDetails
object to store data for a given order.
public StringBuffer checkOutCart( ShoppingCart cart ) throws CartException { ...
// Create order details details = new OrderDetails( orderID, new Date(), cart.getUserName(), shopID.intValue(), shippingAddress.getAddress(),
|
|
|