How to manage DAOs in a real system

Every example in our documentation is quite simple. There are few DAOs in the code. In these examples each DAO is created in a standard Java way by calling the constructor, as shown here:

BookDAO bookDAO = new BookDAOImpl(dbAdapter, dataSource);
AuthorDAO authorDAO = new AuthorDAOImpl(dbAdapter, dataSource);

System.out.println(bookDAO.getBookList());
System.out.println(authorDAO.getAuthorList());

In the real world (I mean real production systems), this way is not an option. It makes the code complex and error prone when you have to pass DAO constructor parameters to every business logic class. The list of DAO arguments may vary. To avoid that, you can use the DAOManager class.

Simple usage

Let's see how you can use it. There is a default implementation of DaoManager called DefaultDaoManager. This implementation uses the same constructor parameters set as DAO implementations. Here is an example:

DaoManager daoManager = new DefaultDaoManager(ds,dbAdapter);
        
BookDAO bookDAO = daoManager.getDao(BookDAO.class);
System.out.println(bookDAO.getBookList());
        
AuthorDAO authorDAO = daoManager.getDao(AuthorDAO.class);
System.out.println(authorDAO.getAuthorList());

Using DaoManager makes logging all queries easier. Just pass a logger (DaoMonitor) as a third argument. All DAOs will log their queries.

DaoManager daoManager = new DefaultDaoManager(ds,dbAdapter, new PrintStreamDaoMonitor(System.err));
        
BookDAO bookDAO = daoManager.getDao(BookDAO.class);
System.out.println(bookDAO.getBookList());
        
AuthorDAO authorDAO = daoManager.getDao(AuthorDAO.class);
System.out.println(authorDAO.getAuthorList());

This is all you need to add support for your web framework. There are two steps:

  1. Create DaoManager in a servlet filter and store in request attributes
  2. In business servlet get the DaoManager instance from the request and use it.

In a future post, I will show you how to handle the transaction.

More complex usage

It's time to do something complex. Let's see how DaoMonitor can used in integration code. Let assume we have two databases, "OLD" and "NEW", and the requirement is to pour data from older to the newer. Yep, the old-school solution.

The old database is running under Oracle and the newer is a DB2 instance. Let's define it:

DBAdapter dbAdapter_OLD = new OracleDBAdapter();
DataSource dataSource_OLD = ...;

DBAdatper dbAdapter_NEW = new DB2DBAdapter();
DataSource dataSource_NEW = ...;

DaoManager has a constructor which requires two mappers. What is a mapper? I hope you'll guess reading the code ;).

The first one maps the data source name to DBAdatapter:

Map<String, DBAdapter> ds2adapter = new HashMap<String, DBAdapter>();
ds2adapter.put(OLD_DS, dbAdapter_OLD);
ds2adapter.put(NEW_DS, dbAdapter_NEW);
            
DBAdapterMapper dbAdapterMapper = new DefaultDBAdapterMapper(ds2adapter);

The second one maps the data source name to the DataSource data source instance:

Map<String, DataSource> ds2dataSource = new HashMap<String, DataSource>();

ds2dataSource.put(OLD_DS, dataSource_OLD);
ds2dataSource.put(NEW_DS, dataSource_NEW);
            
DataSourceManager dsManager = new DefaultDataSourceManager(ds2dataSource);

You have two mappers, so create DaoManager:

DaoManager daoManager = new DefaultDaoManager(dsManager, dbAdapterMapper);

DaoManager now knows how to create DAO with the proper DBAdapter and data source for a given data source name. Let's see what the sample integration code looks like:

BookDAO newBookDAO = daoManager.getDao(BookDAO.class, NEW_DS, "PUBLIC");
BookDAO oldBookDAO = daoManager.getDao(BookDAO.class, OLD_DS, "PUBLIC");
            
for(Book b : oldBookDAO.getBookList()) {
        b.setBookId(null);
        newBookDAO.insert(b);
}

As you can see, only a data source name is used in the business code. Using DaoManager greatly simplifies the code in a large system.

What else would you like to know?