Mocking Hibernate DAOs to test Service Level Spring Beans

A simple layered architecture usually consists of a view layer, a service layer and domain layer. DAO’s are also placed at the domain layer together with the domain objects. Only the upper layer is aware of the lower layer and the interaction happens from top to bottom. A well known example might be JSF-Spring-Hibernate where spring beans are injected to JSF managed beans and these service level spring beans are used to interact with hibernate(HibernateTemplate).

Testing the DAO’s is fairly simple using the spring’s AbstractBlaBlaSomeFancyNameTestCases, actually the fun part is testing the service level business objects(in this case a spring bean). Assume we are trying to save a Customer object to the db and view layer makes a call to the service object. Later after doing a check, service bean makes a call to the DAO layer. Following stuff is needed;

* ICustomerDAO
* CustomerDAO
* IBusinessService
* BusinessService
* Customer

The whole idea is to do a simple check to see whether the customer is already saved or not. If the customer is already in db, a business rule exception is thrown.

ICustomerDAO

    
    

package domain;

public interface ICustomerDAO {
  public void save(Customer customer);
  public boolean isAlreadySaved(Customer customer);
}      

CustomerDAO

  
    
    

package domain;

import java.util.List;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class CustomerDAO extends HibernateDaoSupport implements ICustomerDAO{

  public void save(Customer customer){
    getHibernateTemplate().save(customer);
  }

  public boolean isAlreadySaved(Customer customer) {
    //Some algorithm to do the check here
  }

}      

IBusinessService

  
    
    

package service;

import exceptions.BusinessRuleException;
import domain.Customer;

public interface IBusinessService {
  public void saveCustomer(Customer customerthrows BusinessRuleException;
}      

BusinessService

  
    
    

package service;

import exception.BusinessRuleException;
import domain.ICustomerDAO;
import domain.Customer;

public class BusinessService implements IBusinessService{

  private ICustomerDAO customerDAO;

  public void saveCustomer(Customer customerthrows BusinessRuleException{
    if(customer == null || getCustomerDAO().isAlreadySaved(customer))
      throw new BusinessRuleException();
    else
      getCustomerDAO().save(customer);
  }

  public ICustomerDAO getCustomerDAO() {
    return customerDAO;
  }

  public void setCustomerDAO(ICustomerDAO customerDAO) {
    this.customerDAO = customerDAO;
  }

}      

Finally the fun part, testing the BusinessService;

BusinessServiceTest

  
    
    

package service;

import org.jmock.Mock;
import org.jmock.MockObjectTestCase;

import exception.BusinessRuleException;

import domain.ICustomerDAO;
import domain.Customer;

public class BusinessServiceTest extends MockObjectTestCase {

  private BusinessService businessService;

  private ICustomerDAO customerDAO;

  private Mock mockCustomerDAO;

  protected void setUp() throws Exception {
    businessService = new BusinessService();

    mockCustomerDAO = new Mock(ICustomerDAO.class);
    customerDAO = (ICustomerDAO)mockCustomerDAO.proxy();
    businessService.setCustomerDAO(customerDAO);
  }

  public void testTryingToSaveACustomerThatIsAlreadyInDBCausesBusinessRuleException() {
    mockCustomerDAO.expects(once()).method(“isAlreadySaved”).will(returnValue(true));
    try {
      businessService.saveCustomer(new Customer());
      fail();
    }catch(BusinessRuleException businessRuleException) {
      //test passes
    }
  }

  public void testTryingToSaveACustomerThatIsNullCausesBusinessRuleException() {
    try {
      businessService.saveCustomer(null);
      fail();
    }catch(BusinessRuleException businessRuleException) {
      //test passes
    }
  }

}      

That’s all, the service object uses a DAO that actually hits the db. In order to test it, I’ve replaced it a mock version. The example is a simple case, but the idea remains same for more complex business rules. The good practice is to make these kind of checks at service layer instead of at DAO. Although I’ve used spring-hibernate as an example, the practice applies to all kind of architectures containing a business layer.

Posted in Java. 2 Comments »

FacesTrace with Facelets

I’ve recieved some mails asking for a facelets taglib file in order to use FacesTrace . So here we go;

 <?xml version=”1.0″?>
<!DOCTYPE facelet-taglib PUBLIC “-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN” “facelet-taglib_1_0.dtd”>
<facelet-taglib>
<namespace>http://sourceforge.net/projects/facestrace</namespace>
<tag>
    <tag-name>trace</tag-name>
    <component>
        <component-type>net.sf.facestrace.component.Trace</component-type>
    </component>
</tag>
</facelet-taglib>

Still don’t know what is FacesTrace?, check it out.

Posted in Java. 2 Comments »

Aspect Oriented Web Service Transactions

AOP is definitely a life saver. The project which I’ll leave soon is a J2EE project with JSF, Spring and Hibernate but the Document Management System module is implemented by a subcontractor firm and with .NET. As you may guess they talk by using web services and the basic requirement is uploading a document to the java application and send it to the .NET application to save. Let’s say there is a persistent object called Agreement with documents. The basic code in the service method that implements a service interface is as follows;

In SomeSpringService;

  
    
    

public void saveAgreement(Agreement aggrement) {          
     getAgreementDao().saveAggrement(agreement);
     getDMSService().saveDocs(agreement.getDocs());
}      

Subcontractor firm doing the .NET stuff is a small company and apparently they don’t know much about software development. I’m saying this after seeing methods composed of hundreds of lines. I hate the sound of the mouse wheel they use when they are looking for a code portion in the method. Up and Down. Man somebody has to tell them there is a concept of refactoring in the world. Anyway, a requirement arised after Master Kenan realized that the flow to save a document using their web service is a transactional requirement. Paired with Mert, they have created features to begin, end and rollback web service call transaction methods. After that the code looks like;

  
    
    

public void saveAgreement(Agreement aggrement) {
            try {
                  getDMSService().beginDMSTransaction();
                  getAgreementDao().saveAgreement(aggrement);
                  getDMSService.saveDocs(aggrement.getDocs());
                  getDMSService().commitDMSTransaction();
            }
            catch (Exception e) {
                 getDMSService().rollbackDMSTransaction();
                 throw new DMSException(e);
            }
}      

A problem occurred here, because the new infrastructure caused a core change and the first way was widely used by the developers in the project. This means, all the developers must change their service layer code interacting with the web service which will lead to a lot of workload. At this point I’ve sensed a disturbance in the force. Like Russell Crowe in Beautiful Mind or Tom Hanks in Da Vinci Code, some parts of the whole picture began to shine and I’ve came up with a way that will allow no change in the current code but will also handle the transaction stuff. Spring handles the transactions with AOP why not do the samething here.

I’ve used a commons attribute that defines the method needs a web service transaction. The only thing remaining was to implement the interceptor and the attribute related stuff.

DMSAttribute

  
    
    

package forca.barca;

public class DMSAttribute {

  public final static String TRANSACTION_REQUIRED = “DMS_TRANSACTION_REQUIRED”;
  
  private String type;
  
  public DMSAttribute() {}
  
  public DMSAttribute(String type) {
    this.type = type;
  }

  public String getType() {
    return type;
  }

  public void setType(String type) {
    this.type = type;
  }
}      

DMS Attribute Source

  
    
    

package forca.barca;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;

import org.springframework.aop.support.AopUtils;
import org.springframework.metadata.Attributes;
import org.springframework.util.Assert;

public class DMSAttributeSource {

  private Attributes attributes;
    
    public Attributes getAttributes() {
        Assert.notNull(attributes,“‘Attributes’ cannot be null.”);
        return attributes;
    }
    
    public void setAttributes(Attributes attributes) {
        this.attributes = attributes;
    }
    
    public DMSAttribute getDMSAttribute(Method method, Class targetClass) {
        
        Method specificMethod = AopUtils.getMostSpecificMethod(method,targetClass);
        
        DMSAttribute attr = findDMSAttribute(getAttributes().getAttributes(specificMethod));
        if(attr != null) {
            return attr;
        }
        
        attr = findDMSAttribute(getAttributes().getAttributes(specificMethod.getDeclaringClass()));
        if(attr != null) {
            return attr;
        }
        
        if(specificMethod != method) {
            attr = findDMSAttribute(getAttributes().getAttributes(method));
            if(attr != null) {
                return attr;
            }
            
            attr = findDMSAttribute(getAttributes().getAttributes(method.getDeclaringClass()));
            if(attr != null) {
                return             }
        }
        
        return null;
    }
    
    private DMSAttribute findDMSAttribute(Collection collection) {
        for (Iterator iter = collection.iterator(); iter.hasNext();) {
            Object attr = (Objectiter.next();
            if(attr instanceof DMSAttribute) {
                return (DMSAttribute)attr;
            }
        }
        return null;
    }
}      

Interceptor;

  
    
    

package forca.barca;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import forca.barca.DMSexception;

public class DMSTransactionInterceptor implements MethodInterceptor {
  
  private final static Log logger = LogFactory.getLog(DMSTransactionInterceptor.class);

  private DMSAttributeSource dmsAttributeSource;

  private IDMSService dmsService;

  public Object invoke(MethodInvocation methodInvocationthrows Throwable {
    DMSAttribute dmsAttribute = getDMSAttributeSource().
                           getDMSAttribute
(methodInvocation.getMethod(),methodInvocation.getThis().getClass());

    if (dmsAttribute != null && dmsAttribute.getType().equals(DMSAttribute.TRANSACTION_REQUIRED)) {
      return handleDMSTransaction(methodInvocation);
    else {
      return methodInvocation.proceed();
    }
  }

  public DMSAttributeSource getDMSAttributeSource() {
    return dmsAttribute;
  }

  public void setDMSAttributeSource(DMSAttributeSource dmsAttribute) {
    this.dmsAttribute = dmsAttribute;
  }

  public IDMSService getDMSService() {
    return dmsService;
  }

  public void setDMSService(IDMSService dmsService) {
    this.dmsService = dmsService;
  }

  private Object handleDMSTransaction(MethodInvocation methodInvocationthrows Throwable {
    try {
      getDMSService().beginDMSTransaction();
      logger.debug(“DMS Transaction started”);
      Object result = methodInvocation.proceed();
      getDMSService().commitDMSTransaction();
      logger.debug(“DMS Transaction commi
tted”
);
      return result;
    catch (Exception e) {
      getDMSService().rollbackDMSTransaction();
      logger.debug(“DMS transaction rolled back”);
      throw new DMSException(e);
    }
  }

}      

By the way dmsService is injected to the interceptor. New usage in the interface of the service method, implementation of the service object remains unchanged;

In ISomeSpringService;

  
    
    

 /**
   * @@forca.barca.DMSAttribute (“DMS_TRANSACTION_REQUIRED”) 
   */
 public void saveAgreement(Agreement agreement);      

The DMSAttribute and DMSAttributeSource are used to get the commons attribute defined for the service method. This is similar to the ones in Aspect Oriented Audit Logging with Spring and Hibernate. In the end my whole idea worked and the project saved from changing a lot of production code. It was fun and I believe this is one of the most useful stuff I’ve done before leaving the project.

Posted in Java. Comments Off