CONTENTS | PREV | NEXT | INDEX J2EE BluePrints



5.5 Design Guidelines

In addition to the guidelines discussed previously for choosing specific bean types, there are other design choices that Application Component Providers must make when developing objects for the EJB tier. These choices include what types of objects should be enterprise beans, and what role an enterprise bean may play in a group of collaborating components.

Since enterprise beans are remote objects that consume a significant amount of system resources and network bandwidth, it is not appropriate to model all business objects as enterprise beans. Only the business objects that need to be accessed directly by a client need to be enterprise beans; other objects can be modeled as data access objects, which encapsulate database access, and value objects, which model fine-grained objects that are dependent on enterprise beans.

It may not be appropriate to give clients direct access to all enterprise beans within an application. As a consequence, some enterprise beans may act as mediators of communication between clients and the EJB tier. A bean of this type can encapsulate work flow specific to an application or can serve as an entry point to a hierarchy of information keyed to an attribute of the entry-point bean.


5.5.1 Data Access Objects

To encapsulate access to data, the sample application uses data access objects. The use of separate objects to access databases was driven by following requirements:

5.5.1.1 Clarifying Session Bean Implementations

Any session bean method that needs to access a database has a corresponding method in the data access object that implements the actual logic of fetching or updating data in the database. This makes the enterprise bean implementation much cleaner and readable by conveying the business logic at a glance without being cluttered up with JDBC calls.

For example, consider the Catalog session bean. The business method
getProducts need to return all the products for a category. Whenever getProducts needs to operate on data residing in the database, it hands over control to a data access object. The data access object formulates the query, fetches the result set, and returns the data in the desired format to the calling method of the enterprise bean.

In the sample application, the implementation of the Catalog session bean is provided by CatalogEJB, which inherits from CatalogImpl. The code for CatalogImpl.getProducts appears in Code Example 5.4; the code for the corresponding data access object appears in Code Example 5.5.


public Collection getProducts(String categoryId,
	int startIndex, int count) {
	Connection con = getDBConnection();

	try {
		CatalogDAO dao = new CatalogDAO(con);
			return dao.getProducts(categoryId, startIndex, count);
	} catch (SQLException se) {
		throw new GeneralFailureException(se);
	} finally {
		try {
			con.close();
		} catch (Exception ex) {
			...
		}
	}
}
Code Example 5.4 CatalogImpl.getProducts

public Collection getProducts(String categoryId, int startIndex, 
	int count) throws SQLException {

	String qstr =
		"select itemid, listprice, unitcost, " +
		"attr1, a.productid, name, descn " +
		"from item a, product b where " +
		"a.productid = b.productid and category =  "
		 + "'" + categoryId + "' " + " order by name";

	ArrayList al = new ArrayList();
	Statement stmt = con.createStatement();
	ResultSet rs = stmt.executeQuery(qstr);
	HashMap table = new HashMap();
	// skip initial rows as specified by the startIndex parameter
	while (startIndex-- > 0 && rs.next());
	// Now get data as requested
	while (count-- > 0 && rs.next()) {
		int i = 1;
		String itemid = rs.getString(i++).trim();
		double listprice = rs.getDouble(i++);
		double unitcost = rs.getDouble(i++);
		...
		Product product = null;
		if (table.get(productid) == null) {
			product = new Product(productid, name, descn);
			table.put(productid, product);
			al.add(product);
		}
	}
	rs.close();
	stmt.close();
	return al;
}
Code Example 5.5 CatalogDAO.getProducts
5.5.1.2 Migrating to Container-Managed Persistence

Apart from neater, more maintainable code, the use of data access objects provides an easier migration path to container-managed persistence. To convert an entity bean from bean-managed persistence to container-managed persistence you simply need to discard corresponding the data access object along with references to it in the entity bean's code.

5.5.1.3 Database and Schema Portability

By encapsulating data access calls, data access objects allow adapting data access to different schemas or even to a different database types. Data access objects for different schemas and databases can share a common interface enabling the Application Assembler to choose the appropriate object from among several at assembly time.

In the sample application we have used the flexibility provided by data access objects to access different types of databases, namely Oracle, Sybase, and Cloudscape. In the order management module, a separate data access object is provided for each vendor. This allows the same enterprise bean code to run on all databases. The decision of which data access object to invoke is taken dynamically when a connection to the database is made. A similar approach can be used to access databases with different schemas.

5.5.1.4 Tool Compatibility

Data access objects fill a gap in the J2EE application architecture between responsibilities of application developers and those of Server Providers. They represent an excellent opportunity for the tool vendors to add value. Data access objects are a type of class that can be easily generated by sophisticated tools. In the future, custom data access objects, such as those in the sample application, will most likely be replaced by sophisticated object-relational tools.


5.5.2 Value Objects

As mentioned earlier, because enterprise beans are remote objects, they consume significant amount of system resources and network bandwidth to execute. Therefore, before modeling a business object as an enterprise bean, you should determine that there is a good case for doing so. For example, if a business object merely represents a structure to hold data fields, and the only behavior it provides are get and set methods for the fields, then it would be wasteful of system resources to implement it as an enterprise bean.

A better alternative would be to model it as a value object. A value object is a serializable Java object that can be passed by value to the client. A business concept should be implemented as a value object when it is:

A client's request for a value object can be fulfilled by the server more simply than for an enterprise bean; the object is serialized and sent over the network to the client where the object is deserialized. The object can then be used as a local object. This conserves system resources by reducing the load on a remote object. It also reduces network traffic as the method calls to get fields of the object are all local.

In the sample application the details of an account are modeled as a value object representing the state of a particular account in the database and providing getter methods to query the state of this account. The client makes just one remote call to execute getAccountDetails on the remote object account and gets back the serialized AccountDetails object. The client can then query the state of this account locally via the methods provided with the AccountDetails object. Similarly, the state of an account object can be modified in just one remote call by passing a ContactInformation object to the remote method for updating contact information.

5.5.2.1 Example: An Address Value Object

In the sample application, an address and credit card information are modeled as value objects. The definition of the Address class is shown in Code Example 5.6.


public class Address implements java.io.Serializable {
	public Address (String streetName1, String streetName2,
		String city, String state, String zipCode, String country){
		this.streetName1 = streetName1;
		this.streetName2 = streetName2;
	...
	}
	public String getStreetName1() {
		return streetName1;
	}
	...
	private String streetName1;
	private String streetName2;
	...
}
Code Example 5.6 Address

An Address does not exhibit complex behavior, but is merely a data structure that contains only data fields. An address is fine-grained, having only get and set methods. Also, it is a dependent object; it only has meaning if it is associated with an account.

When making the object pass-by-value it is important to make it immutable to reinforce the idea that the dependent object is not a remote object and changes to its state will not be reflected on the server; in other words, it is just a copy and not the remote reference. To make an Address object immutable, all its instance data is declared private and it only has methods to get fields. To change a pass-by-value object the client must first remove it and then create a new object with the desired field values.


5.5.3 Session Beans as a Facade to Entity Beans

A facade provides a unified interface to a set of interfaces. This section describes when and how to use an session bean as a facade to entity beans.

Entity beans represent an object-oriented view of data and provide business logic to manipulate this data. In an enterprise environment, entity beans often need to be shared among different applications representing different work flows. In such cases, use of application-specific stateful session beans to manage the interaction of various entity beans provides a simpler interface to the client, by giving the client a central point of entry. The client always interacts with this session bean and is unaware of the existence of other entity beans in the system.

Stateful session beans are logical extensions of the client programs. Whether to use one or many session bean facades depends on the types of clients the application supports. Since the sample application has only one kind of client for the application, namely the shopping client, the sample application uses a single stateful session bean called ShoppingSessionController. It's easy to imagine another client that would provide administration functionality such as inventory and order status monitoring. The work flow of such a client would be entirely different from a shopping client. Therefore, defining another stateful session bean that encapsulates this work flow would be advisable. However, creating a session bean for every entity bean in the system would waste server resources and is not recommended.

Where the client interacts with only a few entity beans in a relatively simple way, the entity beans can be exposed directly. For example, in the sample application the client that converts pending orders to XML (for use by business-to-business transactions) interacts with the order entity bean directly.


5.5.4 Master-Detail Modeling Using Enterprise Beans

In a master-detail relationship, one object serves as a pointer to another. Typically such a relationship is represented to the user as a list of items from which to select. This list is called a master record and its contents are provided by the master object. Selecting an item from this list leads to an expanded view of that item. The expanded view is provided by a detail object.

A master-detail relationship is a one-to-many type relationship among data sets. For example, if we have a set of customers and a set of orders placed by each customer, a master-detail relationship is created by having customer number as a common field between the two. An application can use this master-detail relationship to enable users to navigate through the customer data set and see the detail data for orders placed by the selected customer.

When modeling a master-detail relationship as enterprise beans, the guidelines for using entity or session beans still hold. The choice is not affected by the master-detail relationship. However, the relationship is relevant when designing the behavior of the master. For example, suppose the master object should be modeled as a session bean and the details object should be an entity bean. In this case, the issue to be decided is how to implement the behavior of the master:

In analyzing various possible combinations of session beans, entity beans, or value objects, to represent master and detail objects, these questions are relevant only when the details are entity beans. For this case there are two possible scenarios:



CONTENTS | PREV | NEXT | INDEX
Copyright © 2001 Sun Microsystems, Inc. All Rights Reserved.