Friday, December 2, 2011

DAO (Data Access Object Pattern)


What is the DAO Pattern?

We will (eventually) migrate all of the code that is used to access/manipulate the database, configuration files, the RRD files, or other externally data like reports or graphs to use the Data Access Object (DAO) Design Pattern. This pattern encapsulates access and manipulation of external data sources such as databases, config files and others. The DAO pattern creates the flexibility to change the format or location of data without needing to go through and rewrite the entire application.


The DAO Pattern defines five 'roles' or collaborators in the working of the pattern. These roles are as follows:
The Client
This role represents the 'Business Objects' or objects that need to access or modify the data.
The DAO Interace
This role is the operations (i.e. quieres and updates) that Data Access Objects define. These operations might include findById(nodeId) or getOpenOutagesForService(Service)
The Data Transfer Object
This role is the object that represents the data retrieved from the data source. An example object would be a Node or an Interface for a Database DAO or a User or Group for an XML based DAO.
The DAO Implementation
This provides the actual implementation of the DAO Interface. It is written for the particular data source the contains the data. These might include JDBCNodeDAO or CastorUserDAO, for node data stored in a database accessed via JDBC and for user data stored in an XML file accessed via castor respectively.
The Data Source
This represents the external location of the data abstracted by the DAO. This is can be a relational database, XML file, proprietary file format, web service or other external data location.

                                                                   Data Access Object sequence diagram

The Strategy

The approach we will take migrate OpenNMS to use the DAO Pattern is as follows:
  1. Define Data Transfer objects representing the data in a single row of each table defined by an OpenNMS's postgresql database.
  2. Create empty DAO interfaces for each table that will eventually have methods used to access the data from the table.
  3. Create a stub implementation extends Spring's HibernateSupport class that will use Hibernate to query the data and implement the DAO operations
  4. Use XDoclet on the Data Transfer object to define the Hibernate object to relational mapping and generate the hibernate configuration files.
  5. Setup a Spring application context file that sets up all of the DAO objects as well as the Hibernate session needed to correctly retrieve the data.
  6. Go through the code looking for database access code. In any location where database access is made, place an appropriate call to locate the DAO (or even better inject the DAO)
  7. Next define a DAO operation that provides the data
  8. Implement the operation in the DAO Implementation using Hibernate
  9. Once this is done we will enhance this strategy to discuss using the DAO Pattern for XML and RRD Files and any other places where it would make sense.
Notes: Any code that exists solely to cache database data should be removed. It this is necessary for acceptable performance it should be done inside of the DAO rather than external to it. Examples of this would be places in the code where the serviceID to serviceName maps are maintained to avoid an additional DB query.


Advantages of DAO:

  • 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 readability and development productivity.
  • Centralizes All Data Access into a Separate Layer
    Because all data access operations are now delegated to the DAOs, the separate data access layer can be viewed as the layer that can isolate the rest of the application from the data access implementation. This centralization makes the application easier to maintain and manage.
  • Not Useful for Container-Managed Persistence
    Because the EJB container manages entity beans with container-managed persistence (CMP), the container automatically services all persistent storage access. Applications using container-managed entity beans do not need a DAO layer, since the application server transparently provides this functionality. However, DAOs are still useful when a combination of CMP (for entity beans) and BMP (for session beans, servlets) is required.
  • Adds Extra Layer
    The DAOs create an additional layer of objects between the data client and the data source that need to be designed and implemented to leverage the benefits of this pattern. But the benefit realized by choosing this approach pays off for the additional effort.
  • Needs Class Hierarchy Design
    When using a factory strategy, the hierarchy of concrete factories and the hierarchy of concrete products produced by the factories need to be designed and implemented. This additional effort needs to be considered if there is sufficient justification warranting such flexibility. This increases the complexity of the design. However, you can choose to implement the factory strategy starting with the Factory Method pattern first, and then move towards the Abstract Factory if necessary.

Why Hibernate

Hibernate was selected because it provides efficient object to relation mapping technology. It enables us to efficiently represent objects in a relation database that allows to put object methods where they belong and even provides for appropriate inheritance relationships. As the code improves Hibernate will make for an easier more extendible implementation.

Why Spring

Spring has a sophisticated implementation for dealing with transactions, exceptions, and database sessions/connections. It enables us to declaratively define transactions via configuration file as well as a mechanism for 'wiring' up beans that makes for code this is both testable and easy to use. Addidtionally Spring's 'proxy' features will enable us to distribute the different pieces of OpenNMS readily.

No comments:

Post a Comment