| CONTENTS | PREV | NEXT | INDEX | J2EE BluePrints |
In this section we focus our attention on the state that needs to be maintained by the application. One can think of the back-end of an application as a collection of state with some rules on how the state changes in response to user interactions. This section explains how the sample application maintains state in the J2EE platform and persistent data in database tables.
Typically, the customer will use a number of features of the pet store during a single visit (such as requesting product information and placing items in a shopping cart), resulting in numerous requests during the client session. While the application does not need to store this information in a database, this information must be somehow tracked to maintain a meaningful dialog between the customer and the application.
There is state associated with both the user interface and the business logic. In general, the sample application must maintain the following state:
- The user identity: Typically, the user account module maintains the user identify, which includes the user's login ID and certain security credentials.
- The search cursor and catalog position: The catalog module maintains the cursor's position within the current search and within the catalog hierarchy.
- The items in the shopping cart: The shopping cart module maintains the list of items placed in the customer's shopping cart.
- Order information: When the customer confirms the order, the shopping cart passes this information the order information--billing address, shipping address, and payment method--to the order management module, which eventually stores it to a database.
The J2EE platform provides several choices for storing the application state. An application can store state in the Web tier using the state maintenance capabilities of servlets, which include the HTTPSession and ServletContext objects as well as JavaBeans components. In the EJB tier, state can be maintained using enterprise beans. Also, session state for an application can be divided between these tiers. The decision of where each object representing application state is stored depends on the lifetime and scope of the object. The following sections identify each state component, its lifetime requirements, and discuss why it should be stored using a particular mechanism.
The Web tier maintains state required by JSP pages in JavaBeans components.
These JavaBeans components are managed by a class called ModelManager
that uses both an HttpSession and a ServletContext
to maintain handles to the JavaBeans components. ModelManager is
discussed further in Section 10.6.8.1. Beans that are specific to a client are maintained by
an HTTP session object. Beans that can be shared by all clients are maintained
as an attribute of the servlet generated from Main.jsp.
The JavaBeans components contain copies of the state maintained by corresponding model objects which are maintained in the EJB tier. When designing objects in the EJB tier to maintain state, the developer must answer two questions:
- What is the appropriate granularity for the objects? Not every business object should be modelled as an enterprise bean. Since every method call to an enterprise bean is potentially a remote call, the overhead of an inter-component call is likely to be prohibitive for interactions with fine-grained objects. Therefore, the sample application makes extensive use of helper objects, which are non-remote, serializable objects that mirror their respective enterprise beans.
- What type of enterprise bean should I use? An application can use either session beans or entity beans to maintain state. For a non-transactional object, a session bean is the simplest way to maintain session state for a short period of time because it leverages the EJB container's ability to manage session bean state. Using entity beans to maintain state provides transactional support for storing the state data in the database. While there is overhead in making the object transactional, the object reference could persist for as long as needed, even beyond the scope of a single session. For example, an object reference can be stored in a cookie on the browser to be retrieved and used even weeks later. The sample application has examples of using both session and entity beans to store session state.
10.4.1.1 Using Enterprise Beans to Maintain Session State
This section describes how different types of enterprise beans are used to represent objects in the sample application. General guidelines for how to use enterprise beans can be found in Chapter 5.
A stateless session bean does not contain state for a specific client. However, the instance variables of a stateless session bean can contain state across method calls. Examples of such state include an open database connection and a cache of data retrieved from that connection. Stateless session beans are never written out to secondary storage. As a consequence, stateless beans usually offer better performance than stateful beans.
The sample application uses stateless session beans for objects containing more than one database row. In particular, because stateless session beans provide high performance, stateless session beans are a good choice to provide a fast access to data derived from multiple database rows. In the pet store application, the Catalog stateless session bean functions as a cache that is built up over time.
A stateful session bean exists during a single client session and can maintain information specific to a client between invocations of methods. The sample application represents the contents of a client's shopping cart with the ShoppingCart stateful session bean.
The sample application uses entity beans to provide an object view of individual rows in a database. The sample application includes three such beans, Account, Inventory, and Order, to represent individual rows in the corresponding tables.
10.4.1.2 Helper Objects
It is not appropriate to model all objects in the EJB tier as enterprise beans. Therefore, the sample application uses helper objects that are subordinate to their respective enterprise beans for a number of purposes. The different types of helper objects are: data access objects and value objects. The use of helper objects is discussed in detail in Section 5.5.
A data access object is used to encapsulate access to databases. Data access objects can encapsulate access to more than one database, more than one table within one database, and different types of databases. The sample application uses data access objects for all these purposes.
The sample application uses the abstract data access class OrderDAO to access three tables, order, orderstatus, and lineitem, when an order is created, read, or updated. The sample application contains three subclasses, OrderDAOOracle, OrderDAOSybase, and OrderDAOCS, that are used to access Oracle, Sybase, and Cloudscape databases.
A value object is a business object that can be passed by value as a serializable Java object. A business concept should be implemented as a value object when it is fine-grained, dependent, and immutable. The sample application uses two types of value objects: dependent objects and details objects.
An object is a dependent object of another object if its life cycle is completely managed by that object and if it can only be accessed indirectly through that object. Examples of dependent objects in the sample application are Address and CreditCard.
A value object can also be used to encapsulate an entire remote object. Such
objects allow a client to retrieve the value of a remote object in one remote
call. The sample application contains details objects for each enterprise bean.
Code Example 10.9 illustrates an
account entity bean and its corresponding details object. In keeping with its
purpose, AccountModel's methods only enable retrieval of the
values in the fields of its bean, while Account itself provides
a method for setting a value and a coarse-grained method (getDetails)
that returns an AccountModel.
public interface Account extends EJBObject {
public AccountModel getDetails() throws RemoteException;
public void changeContactInformation(ContactInformation info)
throws RemoteException;
}
public class AccountModel implements java.io.Serializable {
private String userId;
private String status;
private ContactInformation info;
...
public String getUserId() {
return userId;
}
public ContactInformation getContactInformation() {
return info;
}
...
}
Code Example 10.9 Account and AccountModel
|
The sample application maintains persistent data in database tables, organized according to the functional areas of the application. Figure 10.8 illustrates the database schema.
The application uses this database schema to maintain accounts and track orders for products. Thus, there are three areas for which data must be maintained: product, account, and order information. The product, category, and item tables represent the business's product catalog. Each item has an associated entry in the inventory table that represents the inventory for that product. The account table maintains customer account information, one record per customer, with information such as customer name, password, and customer address. Finally, there is an orders table with one record per order, for information such as ship-to address, bill-to address, total price of the order, and payment (credit card name, expiration date, type) information. The orders table is linked to lineitem and orderstatus tables. Each item in an order is stored in a separate lineitem record, which contains the quantity ordered and price and a separate orderstatus record, which contains a reference to the item and the status of the order.