Sunday, December 1, 2013

Don't repeat the DAO !!!

Most of the time, DAO objects we create, we basically promote the same functionality for different object types.
For example, take the following two implementations.

Implementation of Person DAO for Person related operations
 /*  
  * Copyright 2014-2014 Palash Kanti Kundu.  
  *  
  * Licensed under the Apache License, Version 2.0 (the "License");  
  * you may not use this file except in compliance with the License.  
  * You may obtain a copy of the License at  
  *  
  *   http://www.apache.org/licenses/LICENSE-2.0  
  *  
  * Unless required by applicable law or agreed to in writing, software  
  * distributed under the License is distributed on an "AS IS" BASIS,  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  * See the License for the specific language governing permissions and  
  * limitations under the License.  
  *   
  */  
 import java.io.Serializable;  
 import java.util.List;  
 import org.hibernate.Session;  
 import org.hibernate.SessionFactory;  
 import org.hibernate.Transaction;  
 import org.springframework.orm.hibernate4.HibernateTemplate;  
 /**  
  * Person DAO implementation with basic CRUD operations.  
  *   
  * @author Palash Kanti Kundu  
  * @version 1.0  
  */  
 public class PersonDAOImpl {  
      private HibernateTemplate hibernateTemplate;  
      private SessionFactory sessionFactory;  
      public List<Person> fetchAll() {  
           @SuppressWarnings("unchecked")  
           List<Person> objectList = (List<Person>) hibernateTemplate  
                     .find("from Person");  
           return objectList;  
      }  
      public Person fetchById(Serializable id) {  
           return hibernateTemplate.get(Person.class, id);  
      }  
      public void save(Person bean) {  
           Session session = sessionFactory.openSession();  
           Transaction transaction = session.beginTransaction();  
           session.save(bean);  
           session.flush();  
           transaction.commit();  
           session.close();  
      }  
      public void update(Person bean) {  
           Session session = sessionFactory.openSession();  
           Transaction transaction = session.beginTransaction();  
           session.update(bean);  
           session.flush();  
           transaction.commit();  
           session.close();  
      }  
      public void deleteById(Serializable id) {  
           Session session = sessionFactory.openSession();  
           Transaction transaction = session.beginTransaction();  
           Person bean = fetchById(id);  
           session.delete(bean);  
           session.flush();  
           transaction.commit();  
           session.close();  
      }  
 }  


Implementation of Employee DAO for Employee related operations
 /*  
  * Copyright 2014-2014 Palash Kanti Kundu.  
  *  
  * Licensed under the Apache License, Version 2.0 (the "License");  
  * you may not use this file except in compliance with the License.  
  * You may obtain a copy of the License at  
  *  
  *   http://www.apache.org/licenses/LICENSE-2.0  
  *  
  * Unless required by applicable law or agreed to in writing, software  
  * distributed under the License is distributed on an "AS IS" BASIS,  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  * See the License for the specific language governing permissions and  
  * limitations under the License.  
  *   
  */  
 import java.io.Serializable;  
 import java.util.List;  
 import org.hibernate.Session;  
 import org.hibernate.SessionFactory;  
 import org.hibernate.Transaction;  
 import org.springframework.orm.hibernate4.HibernateTemplate;  
 /**  
  * Employee DAO implementation with basic CRUD operations.  
  *   
  * @author Palash Kanti Kundu  
  * @version 1.0  
  */  
 public class EmployeeDAOImpl {  
      private HibernateTemplate hibernateTemplate;  
      private SessionFactory sessionFactory;  
      public List<Employee> fetchAll() {  
           @SuppressWarnings("unchecked")  
           List<Employee> objectList = (List<Employee>) hibernateTemplate  
                     .find("from Employee");  
           return objectList;  
      }  
      public Employee fetchById(Serializable id) {  
           return hibernateTemplate.get(Employee.class, id);  
      }  
      public void save(Employee bean) {  
           Session session = sessionFactory.openSession();  
           Transaction transaction = session.beginTransaction();  
           session.save(bean);  
           session.flush();  
           transaction.commit();  
           session.close();  
      }  
      public void update(Employee bean) {  
           Session session = sessionFactory.openSession();  
           Transaction transaction = session.beginTransaction();  
           session.update(bean);  
           session.flush();  
           transaction.commit();  
           session.close();  
      }  
      public void deleteById(Serializable id) {  
           Session session = sessionFactory.openSession();  
           Transaction transaction = session.beginTransaction();  
           Employee bean = fetchById(id);  
           session.delete(bean);  
           session.flush();  
           transaction.commit();  
           session.close();  
      }  
 }  

So, we can see that both the classes basically achieve the same set of functionality but on different type. Now, if you go through these implementations and think it in a different way, you can find that, with Java 5.0 you can write it a single time and use it for different types with Generics.
Hibernate and Spring gives you the flexibility to use this concept in a fine grained way.

Well, it can be done in various ways, one implementation is here. You can check this article, its a great way to achieve the Generic DAO  implementation.
I have done it in another way, depending on my application needs. In my application, any persistence object is of type IBean. So, I have used the following DAO implementation in my application


 /*  
  * Copyright 2014-2014 Palash Kanti Kundu.  
  *  
  * Licensed under the Apache License, Version 2.0 (the "License");  
  * you may not use this file except in compliance with the License.  
  * You may obtain a copy of the License at  
  *  
  *   http://www.apache.org/licenses/LICENSE-2.0  
  *  
  * Unless required by applicable law or agreed to in writing, software  
  * distributed under the License is distributed on an "AS IS" BASIS,  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  * See the License for the specific language governing permissions and  
  * limitations under the License.  
  *   
  */  
 package com.palash90.assistant.dao;  
 import java.io.Serializable;  
 import java.util.List;  
 import org.hibernate.Criteria;  
 import org.hibernate.SessionFactory;  
 import org.springframework.orm.hibernate4.HibernateTemplate;  
 import com.palash90.assistant.beans.IBean;  
 /**  
  * DAO interface  
  *   
  * @author Palash Kanti Kundu  
  * @version 1.0  
  */  
 public interface IDao {  
      /**  
       * Returns the list of objects of the provided class  
       *   
       * @return  
       */  
      public List<? extends IBean> fetchAll(Class<? extends IBean> cls);  
      /**  
       * Returns the object with the provided id  
       *   
       * @return  
       */  
      public <T extends IBean> T fetchById(Class<T> cls, Serializable id);  
      /**  
       * Saves the bean to database  
       *   
       * @param bean  
       */  
      public void save(IBean bean);  
      /**  
       * Updates the bean in the database  
       *   
       * @param bean  
       */  
      public void update(IBean bean);  
      /**  
       * Deletes the bean from the database  
       *   
       * @param bean  
       */  
      void deleteById(Class<? extends IBean> cls, Serializable id);  
      /**  
       * Set the sessionFactory to be used  
       */  
      void setSessionFactory(SessionFactory sessionFactory);  
      /**  
       * Set the hibernateTemplate to be used  
       */  
      void setHibernateTemplate(HibernateTemplate hibernateTemplate);  
      /**  
       * Returns the list of object of Class type for the provided criteria  
       *   
       * @param cls  
       * @param criteria  
       * @return  
       */  
      <T extends IBean> List<T> fetchByCriteria(Class<? extends IBean> cls,  
                Criteria criteria);  
 }  

And this is the implementation,

 /*  
  * Copyright 2014-2014 Palash Kanti Kundu.  
  *  
  * Licensed under the Apache License, Version 2.0 (the "License");  
  * you may not use this file except in compliance with the License.  
  * You may obtain a copy of the License at  
  *  
  *   http://www.apache.org/licenses/LICENSE-2.0  
  *  
  * Unless required by applicable law or agreed to in writing, software  
  * distributed under the License is distributed on an "AS IS" BASIS,  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  * See the License for the specific language governing permissions and  
  * limitations under the License.  
  *   
  */  
 package com.palash90.assistant.dao;  
 import java.io.Serializable;  
 import java.util.List;  
 import org.hibernate.Criteria;  
 import org.hibernate.Session;  
 import org.hibernate.Transaction;  
 import com.palash90.assistant.beans.IBean;  
 import com.palash90.assistant.constants.AssistantConstants;  
 /**  
  * Generic DAO implementation with basic CRUD operations.  
  *   
  * @author Palash Kanti Kundu  
  * @version 1.0  
  */  
 public class GenericDAOImpl extends AbstractDaoImpl {  
   /*  
    * (non-Javadoc)  
    *   
    * @see com.palash90.assistant.dao.IDao#fetch(java.lang.Class)  
    */  
   @Override  
   public List<? extends IBean> fetchAll(Class<? extends IBean> cls) {  
      @SuppressWarnings("unchecked")  
      List<? extends IBean> objectList = (List<? extends IBean>) hibernateTemplate  
           .find(AssistantConstants.FROM + AssistantConstants.SPACE  
                + cls.getCanonicalName());  
      return objectList;  
   }  
   /*  
    * (non-Javadoc)  
    *   
    * @see com.palash90.assistant.dao.IDao#fetchById(java.lang.Class,  
    * java.io.Serializable)  
    */  
   @Override  
   public <T extends IBean> T fetchById(Class<T> cls, Serializable id) {  
      return hibernateTemplate.get(cls, id);  
   }  
   /*  
    * (non-Javadoc)  
    *   
    * @see com.palash90.assistant.dao.IDao#save(com.palash90.assistant  
    * .beans.IBean)  
    */  
   @Override  
   public void save(IBean bean) {  
      Session session = sessionFactory.openSession();  
      Transaction transaction = session.beginTransaction();  
      session.save(bean);  
      session.flush();  
      transaction.commit();  
      session.close();  
   }  
   /*  
    * (non-Javadoc)  
    *   
    * @see com.palash90.assistant.dao.IDao#update(com.palash90.assistant  
    * .beans.IBean)  
    */  
   @Override  
   public void update(IBean bean) {  
      Session session = sessionFactory.openSession();  
      Transaction transaction = session.beginTransaction();  
      session.update(bean);  
      session.flush();  
      transaction.commit();  
      session.close();  
   }  
   /*  
    * (non-Javadoc)  
    *   
    * @see com.palash90.assistant.dao.IDao#delete(com.palash90.assistant  
    * .beans.IBean)  
    */  
   @Override  
   public void deleteById(Class<? extends IBean> cls, Serializable id) {  
      Session session = sessionFactory.openSession();  
      Transaction transaction = session.beginTransaction();  
      IBean bean = fetchById(cls, id);  
      session.delete(bean);  
      session.flush();  
      transaction.commit();  
      session.close();  
   }  
   /*  
       * (non-Javadoc)  
       *   
       * @see dao.IDao#fetchByCriteria(java.lang.Class, org.hibernate.Criteria)  
       */  
      @SuppressWarnings("unchecked")  
      @Override  
      public <T extends IBean> List<T> fetchByCriteria(Class<? extends IBean> cls,Criteria criteria) {  
           return (List<T>) criteria.list();  
      }  
 }  

Now, if you need a specific kind of implementation for any of particular, you can inherit the generic implementation and add the particular functionality, like I have done for my Person DAO,

 /*  
  * Copyright 2014-2014 Palash Kanti Kundu.  
  *  
  * Licensed under the Apache License, Version 2.0 (the "License");  
  * you may not use this file except in compliance with the License.  
  * You may obtain a copy of the License at  
  *  
  *   http://www.apache.org/licenses/LICENSE-2.0  
  *  
  * Unless required by applicable law or agreed to in writing, software  
  * distributed under the License is distributed on an "AS IS" BASIS,  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  * See the License for the specific language governing permissions and  
  * limitations under the License.  
  *   
  */  
 package com.palash90.assistant.dao;  
 import java.util.List;  
 import org.hibernate.Criteria;  
 import org.hibernate.criterion.Restrictions;  
 import com.palash90.assistant.beans.person.Person;  
 public class EmployeeDaoImpl extends GenericDAOImpl {  
      /**  
       * Returns the list of persons with the name provided  
       *   
       * @param name  
       * @return  
       */  
      public List<Person> fetchByName(String name) {  
           Criteria criteria = sessionFactory.openSession().createCriteria(  
                     Person.class);  
           criteria.add(Restrictions.eq("firstName", name));  
           return fetchByCriteria(Person.class, criteria);  
      }  
 }  

Hope that, you get some idea about implementing your DAO in a generic way.
Now, Don't repeat the DAO.

Thanks for reading !!!

Palash Kanti Kundu