Write once,
persist anywhere
Tutorial Details:
Write once, persist anywhere
Write once, persist anywhere
By: By James Carman
Implement a Data Access Object pattern framework
he Data Access Object (DAO) pattern provides an abstraction layer between the business logic tier (business object) and the persistent storage tier (data source). Business objects access data sources via data access objects. This abstraction layer encapsulates the persistent storage type/vendor implementation. Ideally, changes made to the data source, such as switching database vendors or type, should not modify the business objects; only the data access objects themselves would need to change.
In this article, I explore a simple yet powerful framework for implementing the DAO design pattern. First, I describe a typical DAO pattern implementation strategy, noting its shortcomings. Then, I move on to the new implementation, explaining its classes. I also explore an example implementation using the JDBC (Java Database Connectivity) API as the storage mechanism. Finally, I present a wish list for future enhancements.
Typical DAO implementation
Sun Microsystems suggests a DAO pattern implementation in the J2EE Pattern Catalog that uses the Abstract Factory and Factory Method design patterns (see Design Patterns ) and usually involves an interface similar to:
public interface DaoFactory
{
public CustomerDao createCustomerDao();
public AccountDao createAccountDao();
}
Here, the DaoFactory interface acts as the abstract factory, and the createCustomerDao() method acts as the factory method. In this example, data source-specific classes implement CustomerDao and AccountDao interfaces (or abstract classes); those interfaces typically resemble the following:
public interface CustomerDao
{
public List getCustomersByLastName( String lastName );
public Customer getCustomerBySSN( String ssn );
}
Although this implementation provides adequate data source-type independence, it introduces object type dependence. For example, adding another object type, say Vendor , to the business domain involves introducing a new VendorDao interface and adding a new getVendorDao() method to the DaoFactory interface.
A new and improved DAO implementation
To provide object type independence, you must simplify the DaoFactory class and add another layer to the DAO implementation hierarchy (the Dao interface) as follows:
public abstract class DaoFactory
{
public final DaoFactory getInstance() throws DaoException;
public abstract Dao createDao() throws DaoException;
}
public interface Dao
{
public void create( final Object object ) throws DaoException;
public Collection retrieve( final String queryString) throws
DaoException;
public void update( final Object object ) throws DaoException;
public void delete( final Object object ) throws DaoException;
public void close() throws DaoException;
}
The new, simplified DaoFactory class (now implemented as an abstract class instead of an interface) can remain unchanged as you add new object types to the business domain, as the class merely references the generic Dao interface, not object type-specific DAO interfaces. The DaoFactory class still implements the Abstract Factory and Factory Method design patterns; however, it now also implements the Singleton design pattern, via the static getInstance() method. The getInstance() method returns a DaoFactory type specified at runtime by an XML configuration file with the following format:
The getInstance() method uses the org.apache.commons.digester.Digester class (see " Sidebar 1: Apache Software Foundation's Digester Class ") to parse the XML configuration file as follows:
private static final String CONFIG_FILE_NAME = "DaoFactory.xml";
private static DaoFactory m_Instance;
public synchronized static final DaoFactory getInstance() throws DaoException
{
final Category category = Category.getInstance(
DaoFactory.class );
if( m_Instance == null )
{
try
{
final Digester digester = new Digester();
digester.addObjectCreate( "dao-factory", null,
"factoryClass" );
digester.addSetProperty( "dao-factory/property",
"name", "value");
m_Instance = ( DaoFactory )digester.parse(
DaoFactory.class.getClassLoader().getResource( CONFIG_FILE_NAME ).toString()
);
}
catch( SAXException sax )
{
throw new DaoException( "Unable to parse configuration
document.", sax );
}
catch( IOException io )
{
throw new DaoException( "Unable to parse configuration
document.", io );
}
}
return m_Instance;
}
Business objects should always use the getInstance() method to obtain a reference to a DaoFactory object, as the method lets you substitute different DaoFactory implementations as needed without changing the business object code. This dynamic instantiation and initialization mechanism requires that DaoFactory subclasses provide a no-argument, default constructor and should conform to the property setter method naming conventions described in the JavaBeans 1.0.1 specification.
The Dao interface
As you can see, the new Dao interface implements the CRUD (create, retrieve, update, and delete) design pattern. The persistence modifying methods, create() , update() , and delete() , now accept generic Object parameters, as opposed to Customer or Account parameters.
A Dao object represents one connection to the data source, similar to a java.sql.Connection , and should be treated as such. Business objects should adhere to the following guidelines when interacting with Dao objects:
Do not cache references to Dao objects. Each time a business object requires a Dao object, it should allow the DaoFactory to create one for it.
Dao objects are not thread-safe. Do not use them in multiple threads.
Be sure to call the close() method on the Dao object, as it may release valuable system resources; for example, by closing database connections or JNDI (Java Naming and Directory Interface) contexts.
Objects managed by a Dao object should follow the JavaBeans specification with respect to providing an accessible default constructor and naming property setter and getter methods.
The DAO query language
To maintain data source independence via this framework, however, we must establish a new data source-independent query syntax for the Dao interface's retrieve() method to use. The Enterprise JavaBeans (EJB) 2.0 specification addresses exactly the same issue via the EJB query language (EJBQL), providing a simple syntax definition closely resembling SQL (as most EJB vendors use relational databases for container-managed persistence). However, EJBQL, as specified in EJB 2.0, remains somewhat limited and does not provide an adequate model for the DAO query language (DAOQL). Although DAOQL's definition is beyond the scope of this article, it should meet these requirements:
It should not target any specific data store type. Since this framework is designed to be data store-independent, the language should avoid introducing features existent in one data store type and not in others.
It should be as robust as possible, providing a vast feature set so that business objects don't need to circumvent the framework to retrieve information from the data store.
It should not introduce many novel or unfamiliar concepts, so as to allow business developers to use the query language with little or no assistance.
Given these requirements, the Object query language (OQL) is an ideal candidate from which to model the DAOQL, as the OQL is a comprehensive, object-based query language, already familiar to many business developers.
The DAO provider architecture
The DaoFactory class's plug-and-play nature and the added abstraction layer between the business objects and the data store provide us with a service provider interface, or SPI (to borrow a term from the JNDI provider architecture), for third-party (or in-house) DAO providers to use. The beauty of this new SPI: it matches exactly the API business objects use. A DAO provider must subclass only the DaoFactory class and implement the Dao interface as necessary for its data source type. Thus, a DAO provider must implement only five methods from the Dao interface and one method from the DaoFactory abstract class. This obligates our DAO provider to a whopping six methods! Admittedly, this is easier said than done, but as you will see, implementing your own DAO provider doesn't have to be such a daunting task, provided you use the right tools.
Implement a JDBC DAO provider
In this section, I show how easily you can implement your own JDBC DAO provider, using a few open source utilities. All the classes you use to implement the JDBC DAO provider are contained in the com.carmanconsulting.dao.jdbc package. First, I devise an object-to-relational mapping model for use throughout the framework. Then, I implement one persistence method, delete() . Finally, I construct a portion of the DAOQL query-processing engine. The primary classes for this provider are JdbcDaoFactory and JdbcDao :
public class JdbcDaoFactory extends DaoFactory
{
public Dao createDao();
void setDomainMapFileName( String domainMapFileName );
void setDebug( int debug );
void setDataSourceName( String dataSource );
}
class JdbcDao implements Dao
{
public void create( Object o );
public Collection retrieve( String queryString );
public void update( Object o );
public void delete( Object o );
public void close();
}
The JdbcDaoFactory class uses a javax.sql.DataSource object to establish connections to the database. The dataSourceName property represents a JNDI name used to look up the javax.sql.DataSource instance within the default JNDI initial context. The domainMapFileName property locates the configuration file for the object-to-relational mapping model.
The object-to-relational mapping model
The object-to-relational mapping model involves only a few classes:
Read
Tutorial at: Click here to view the tutorial
Rate Tutorial: Write once,
persist anywhere
View Tutorial: Write once,
persist anywhere
Related
Tutorials:
Opening up new
ports to Java
with javax.comm
- JavaWorld -
September 1998
Opening up new
ports to Java
with javax.comm
- JavaWorld -
September 1998 |
Programming Java threads in the
real world, Part
5 - JavaWorld -
February 1999
Programming Java threads in the
real world, Part
5 - JavaWorld -
February 1999 |
XML JavaBeans, Part 2 - JavaWorld March 1999
XML JavaBeans, Part 2 - JavaWorld March 1999 |
Scripting power
saves the day
for your Java
apps
Scripting power
saves the day
for your Java
apps |
Static class declarations
Static class declarations |
Choosing an enterprise-wide standard Java IDE - JavaWorld March 2000
Choosing an enterprise-wide standard Java IDE - JavaWorld March 2000 |
Activatable Jini services, Part 1: Implement RMI activation - JavaWorld September
2000
Activatable Jini services, Part 1: Implement RMI activation - JavaWorld September
2000 |
XSLT blooms with
Java
XSLT blooms with
Java |
Write once,
persist anywhere
Write once,
persist anywhere |
Good
introduction to JDO
Good
introduction to JDO |
Java is here to stay (JavaWorld / January 2000 / by John Rommel)
Java is here to stay (JavaWorld / January 2000 / by John Rommel) |
Overcome J2SE
1.3-1.4 incompatibilities
Overcome J2SE
1.3-1.4 incompatibilities |
When tears bring you back your beloved method...
Accessing platform-specific information hasn't always been easy. While you could certainly create processes with Runtime.exec(), dealing with differences across platforms to build parameter sets often led to headaches. In addition, the getenv() method of |
Core Java Data Objects Excerpt
This book excerpt is from Core Java Data Objects, |
The Apache Derby Project
Derby is an effort undergoing incubation at the Apache Software Foundation. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision-making process have stabilised in a ma |
Introduction to JSP
Introduction to JSP
Introduction to JSP
Java Server Pages or JSP for short is Sun's solution for developing dynamic web sites. JSP provide excellent server side scripting support for creating database driven web applications. JSP enable the |
Distributed Objects & Components: JavaBeans
What is JavaBeans ? (from the FAQ) |
The Things I Wish I Learned in Engineering School: A Conversation with Sun Microsystems Distinguished Engineer Rick Catt
Sun Microsystems' Rick Cattell discusses why innovative software often never sees the light of day and how to remedy this problem. |
Accessing Database from servlets through JDBC!
Accessing Database from servlets through JDBC!
Java Servlets
J ava Servlets are server side components that provides a powerful mechanism for developing server side of web application. Earlier CGI was developed to provide server side capabilities |
Techniques used for Generating Dynamic Content Using Java Servlets.
Techniques used for Generating Dynamic Content Using Java Servlets.
Techniques used for Generating Dynamic Content
Common Gateway Interface (CGI)
For any web application high performance and timely delivery are key ingredients to competitive |
|
|
|