Core J2EE Pattern Catalog: Print-Friendly Version
Core J2EE Pattern Catalog: Print-Friendly Version
Components such as bean-managed entity beans, session beans, servlets, and other objects like helpers for JSP
pages need to retrieve and store information from persistent stores and other data sources like legacy systems,
B2B, LDAP, and so forth.
Persistent storage APIs vary depending on the product vendor. Other data sources may have APIs that are
nonstandard and/or proprietary. These APIs and their capabilities also vary depending on the type of storageRDBMS, object-oriented database management system (OODBMS), XML documents, flat files, and so forth.
There is a lack of uniform APIs to address the requirements to access such disparate systems.
Components typically use proprietary APIs to access external and/or legacy systems to retrieve and store data.
Portability of the components is directly affected when specific access mechanisms and APIs are included in the
components.
Components need to be transparent to the actual persistent store or data source implementation to provide easy
migration to different vendor products, different storage types, and different data source types.
Solution
Use a Data Access Object (DAO) to abstract and encapsulate all access to the data source. The DAO
manages the connection with the data source to obtain and store data.
The DAO implements the access mechanism required to work with the data source. The data source could be a
persistent store like an RDBMS, an external service like a B2B exchange, a repository like an LDAP database,
or a business service accessed via CORBA Internet Inter-ORB Protocol (IIOP) or low-level sockets. The
business component that relies on the DAO uses the simpler interface exposed by the DAO for its clients. The
DAO completely hides the data source implementation details from its clients. Because the interface exposed by
the DAO to clients does not change when the underlying data source implementation changes, this pattern
allows the DAO to adapt to different storage schemes without affecting its clients or business components.
Essentially, the DAO acts as an adapter between the component and the data source.
Structure
Figure 9.1 shows the class diagram representing the relationships for the DAO pattern.
Figure 9.3 Factory for Data Access Object strategy using Factory Method
When the underlying storage is subject to change from one implementation to another, this strategy may be
implemented using the Abstract Factory pattern. The Abstract Factory can in turn build on and use the Factory
Method implementation, as suggested in Design Patterns: Elements of Reusable Object-Oriented Software
[GoF]. In this case, this strategy provides an abstract DAO factory object (Abstract Factory) that can construct
various types of concrete DAO factories, each factory supporting a different type of persistent storage
implementation. Once you obtain the concrete DAO factory for a specific implementation, you use it to produce
DAOs supported and implemented in that implementation.
The class diagram for this strategy is shown in Figure 9.4. This class diagram shows a base DAO factory, which
is an abstract class that is inherited and implemented by different concrete DAO factories to support storage
implementation-specific access. The client can obtain a concrete DAO factory implementation such as
RdbDAOFactory and use it to obtain concrete DAOs that work with that specific storage implementation. For
example, the data client can obtain an RdbDAOFactory and use it to get specific DAOs such as
RdbCustomerDAO, RdbAccountDAO, and so forth. The DAOs can extend and implement a generic base class
(shown as DAO1 and DAO2) that specifically describe the DAO requirements for the business object it
supports. Each concrete DAO is responsible for connecting to the data source and obtaining and manipulating
data for the business object it supports.
The sample implementation for the DAO pattern and its strategies is shown in the "Sample Code" section of this
chapter.
Figure 9.4 Factory for Data Access Object strategy using Abstract Factory
The sequence diagram describing the interactions for this strategy is shown in Figure 9.5.
Figure 9.5 Factory for Data Access Objects using Abstract Factory sequence diagram
Consequences
Enables Transparency
Business objects can use the data source without knowing the specific details of the data source's
implementation. Access is transparent because the implementation details are hidden inside the DAO.
Enables Easier Migration
A layer of DAOs makes it easier for an application to migrate to a different database implementation. The
business objects have no knowledge of the underlying data implementation. Thus, the migration involves
changes only to the DAO layer. Further, if employing a factory strategy, it is possible to provide a concrete
factory implementation for each underlying storage implementation. In this case, migrating to a different storage
implementation means providing a new factory implementation to the application.
Reduces Code Complexity in Business ObjectsBecause the DAOs manage all the data access complexities, it
simplifies the code in the business objects and other data clients that use the DAOs. All implementation-related
code (such as SQL statements) is contained in the DAO and not in the business object. This improves code
Figure 9.7 Implementing the Factory for DAO strategy using Factory Method
The example code for the DAO factory (CloudscapeDAOFactory) is listed in Example 9.2.
Using Abstract Factory Pattern
Consider an example where we are considering implementing this strategy for three different databases. In this
case, the Abstract Factory pattern can be employed. The class diagram for this example is shown in Figure 9.8.
The sample code in Example 9.1 shows code excerpt for the abstract DAOFactory class. This factory produces
DAOs such as CustomerDAO, AccountDAO, OrderDAO, and so forth. This strategy uses the Factory Method
implementation in the factories produced by the Abstract Factory.
Figure 9.8 Implementing the Factory for DAO strategy using Abstract Factory Example 9.1 Abstract
DAOFactory Class
// Abstract class DAO Factory
public abstract class DAOFactory {
// List of DAO types supported by the factory
public static final int CLOUDSCAPE = 1;
public static final int ORACLE = 2;
public static final int SYBASE = 3;
...
// There will be a method for each DAO that can be
// created. The concrete factories will have to
// implement these methods.
public abstract CustomerDAO getCustomerDAO();
public abstract AccountDAO getAccountDAO();
public abstract OrderDAO getOrderDAO();
...
The sample code for CloudscapeDAOFactory is shown in Example 9.2. The implementation for
OracleDAOFactory and SybaseDAOFactory are similar except for specifics of each implementation, such as
JDBC driver, database URL, and differences in SQL syntax, if any.
Example 9.2 Concrete DAOFactory Implementation for Cloudscape
// Cloudscape concrete DAO Factory implementation
import java.sql.*;
public class CloudscapeDAOFactory extends DAOFactory {
public static final String DRIVER=
"COM.cloudscape.core.RmiJdbcDriver";
public static final String DBURL=
"jdbc:cloudscape:rmi://localhost:1099/CoreJ2EEDB";
// method to create Cloudscape connections
public static Connection createConnection() {
// Use DRIVER and DBURL to create a connection
// Recommend connection pool implementation/usage
}
public CustomerDAO getCustomerDAO() {
// CloudscapeCustomerDAO implements CustomerDAO
return new CloudscapeCustomerDAO();
}
public AccountDAO getAccountDAO() {
// CloudscapeAccountDAO implements AccountDAO
return new CloudscapeAccountDAO();
}
public OrderDAO getOrderDAO() {
// CloudscapeOrderDAO implements OrderDAO
return new CloudscapeOrderDAO();
}
...
}
The CustomerDAO interface shown in Example 9.3 defines the DAO methods for Customer persistent object
that are implemented by all concrete DAO implementations, such as CloudscapeCustomerDAO,
OracleCustomerDAO, and SybaseCustomerDAO. Similar, but not listed here, are AccountDAO and OrderDAO
interfaces that define the DAO methods for Account and Order business objects respectively.
Example 9.3 Base DAO Interface for Customer
// Interface that all CustomerDAOs must support
public interface CustomerDAO {
public int insertCustomer(...);
public boolean deleteCustomer(...);
public Customer findCustomer(...);
public boolean updateCustomer(...);
public RowSet selectCustomersRS(...);
public Collection selectCustomersTO(...);
...
}
The CloudscapeCustomerDAO implements the CustomerDAO as shown in Example 9.4. The implementation
of other DAOs, such as CloudscapeAccountDAO, CloudscapeOrderDAO, OracleCustomerDAO,
OracleAccountDAO, and so forth, are similar.
Example 9.4 Cloudscape DAO Implementation for Customer
// CloudscapeCustomerDAO implementation of the
// CustomerDAO interface. This class can contain all
// Cloudscape specific code and SQL statements.
// The client is thus shielded from knowing
// these implementation details.
import java.sql.*;
public class CloudscapeCustomerDAO implements
CustomerDAO {
public CloudscapeCustomerDAO() {
// initialization
}
// The following methods can use
// CloudscapeDAOFactory.createConnection()
// to get a connection as required
public int insertCustomer(...) {
// Implement insert customer here.
// Return newly created customer number
// or a -1 on error
}
public boolean deleteCustomer(...) {
// Implement delete customer here
// Return true on success, false on failure
}
public Customer findCustomer(...) {
// Implement find a customer here using supplied
// argument values as search criteria
// Return a Transfer Object if found,
// return null on error or if not found
}
public boolean updateCustomer(...) {
// implement update record here using data
// from the customerData Transfer Object
// Return true on success, false on failure or
// error
}
public RowSet selectCustomersRS(...) {
// implement search customers here using the
// supplied criteria.
// Return a RowSet.
}
public Collection selectCustomersTO(...) {
// implement search customers here using the
// supplied criteria.
// Alternatively, implement to return a Collection
// of Transfer Objects.
}
...
}
The Customer Transfer Object class is shown in Example 9.5. This is used by the DAOs to send and receive
data from the clients. The usage of Transfer Objects is discussed in detail in the Transfer Object pattern.
Example 9.5 Customer Transfer Object
public class Customer implements java.io.Serializable {
// member variables
int CustomerNumber;
String name;
String streetAddress;
String city;
...
// getter and setter methods...
...
}
Example 9.6 shows the usage of the DAO factory and the DAO. If the implementation changes from
Cloudscape to another product, the only required change is the getDAOFactory() method call to the DAO
factory to obtain a different factory.
Example 9.6 Using a DAO and DAO Factory - Client Code
...
// create the required DAO Factory
DAOFactory cloudscapeFactory =
DAOFactory.getDAOFactory(DAOFactory.DAOCLOUDSCAPE);
// Create a DAO
CustomerDAO custDAO =
cloudscapeFactory.getCustomerDAO();
// create a new customer
int newCustNo = custDAO.insertCustomer(...);
// Find a customer object. Get the Transfer Object.
Customer cust = custDAO.findCustomer(...);
// modify the values in the Transfer Object.
cust.setAddress(...);
cust.setEmail(...);
Core DAO
Data Access Object
mechanism from using Entity Beans to using direct JDBC calls from a session bean, or even a move to an
alternative persistence framework, such as JDO. Without a Data Access Object tier in place, this sort of
transition would require extensive re-engineering of existing code.
The Data Access Object design pattern also provides a simple, consistent API for data access that does not
require knowledge of JDBC, EJB, Hibernate, or JDO interfaces. A typical Data Access Object interface is
shown below.
publicinterfaceCustomerDAO
{
publicvoidinsert(Customercustomer)
throwsCustomerDAOException;
publicvoidupdate(CustomerPKpk,Customercustomer)
throwsCustomerDAOException;
publicvoiddelete(CustomerPKpk)
throwsCustomerDAOException;
publicCustomer[]findAll()
throwsCustomerDAOException;
publicCustomerfindByPrimaryKey(Stringemail)
throwsCustomerDAOException;
publicCustomer[]findByCompany(intcompanyId)
throwsCustomerDAOException;
}
It is important to note that Data Access Object does not just apply to simple mappings of one object to one
relational table, but also allows complex queries to be performed and allows for stored procedures and
database views to be mapped into Java data structures.
It is important to note that Data Access Object does not just apply to simple mappings of one object to one
relational table, but also allows complex queries to be performed and allows for stored procedures and
database views to be mapped into Java data structures.