Thursday, April 30, 2009

Hibernate Object States and Actions



Transient
an object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session. It has no persistent representation in the database and no identifier value has been assigned. Transient instances will be destroyed by the garbage collector if the application doesn't hold a reference anymore. Use the Hibernate Session to make an object persistent (and let Hibernate take care of the SQL statements that need to be executed for this transition).

Persistent
a persistent instance has a representation in the database and an identifier value. It might just have been saved or loaded, however, it is by definition in the scope of a Session. Hibernate will detect any changes made to an object in persistent state and synchronize the state with the database when the unit of work completes. Developers don't execute manual UPDATE statements, or DELETE statements when an object should be made transient.

Detached
a detached instance is an object that has been persistent, but its Session has been closed. The reference to the object is still valid, of course, and the detached instance might even be modified in this state. A detached instance can be reattached to a new Session at a later point in time, making it (and all the modifications) persistent again. This feature enables a programming model for long running units of work that require user think-time. We call them application transactions, i.e. a unit of work from the point of view of the user.

save
stores an object into the database. That means it insert an entry if the identifier doesn't exist, else it will throw error. If the primary key already present in the table, it cannot be inserted.

update
is used for updating the object using identifier. If the identifier is missing or doesn't exist, it will throw exception.

saveOrUpdate
calls save() or update() based on the operation. If the identifier exists, it will call update method else the save method will be called.

persist
does the same like session.save(). But session.save() return Serializable object but session.persist() return void.

lock
simply reattaches the object to the session without checking or updating the database on the assumption that the database in sync with the detached object. It is the best practice to use either session.update(..) or session.saveOrUpdate(). Use session.lock() only if you are absolutely sure that the detached object is in sync with your detached object or if it does not matter because you will be overwriting all the columns that would have changed later on within the same transaction.When you reattach detached objects you need to make sure that the dependent objects are reatched as well.

get and load
Both methods create a persistent object by loading the required object from the database. But if there was not such object in the database then the method load() throws an exception whereas get() returns null.

Wednesday, April 22, 2009

How to Use Hibernate Annotation

1. applicationContext.xml
    <bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.aais.model.Transaction</value>
<value>com.aais.model.Account</value>
<value>com.aais.model.Security</value>
<value>com.aais.model.TradeType</value>
<value>com.aais.model.JournalEntry</value>
<value>com.aais.model.SecurityType</value>
</list>
</property>
...


2. SecurityType.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.NamedQueries;
import org.hibernate.annotations.NamedQuery;

/**
* SecurityType entity.
*/
@SuppressWarnings("serial")
@Entity
@Table(name = "security_type")
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@NamedQueries({
@NamedQuery(name = "SecurityType.FindAll", query = "from SecurityType order by securityTypeId asc") ,
@NamedQuery(name = "SecurityType.FindById", query = "from SecurityType where securityTypeId=:securityTypeId")
})
public class SecurityType implements java.io.Serializable {

// Fields

private Integer securityTypeId;
private String name;

// Constructors

/** default constructor */
public SecurityType() {
}

// Property accessors
@Id
@Column(name = "security_type_id", unique = true, nullable = false)
public Integer getSecurityTypeId() {
return this.securityTypeId;
}

public void setSecurityTypeId(Integer securityTypeId) {
this.securityTypeId = securityTypeId;
}

@Column(name = "name", length = 128)
public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((securityTypeId == null) ? 0 : securityTypeId.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SecurityType other = (SecurityType) obj;
if (securityTypeId == null) {
if (other.securityTypeId != null)
return false;
} else if (!securityTypeId.equals(other.securityTypeId))
return false;
return true;
}

}


3. Security.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
* Security entity.
*/
@SuppressWarnings("serial")
@Entity
@Table(name = "security")
public class Security implements java.io.Serializable {

// Fields

private Integer securityId;
private SecurityType securityType;
private String ticker;

// Constructors

/** default constructor */
public Security() {
}

// Property accessors
@Id
@Column(name = "security_id", unique = true, nullable = false)
public Integer getSecurityId() {
return this.securityId;
}

public void setSecurityId(Integer securityId) {
this.securityId = securityId;
}

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "security_type_id")
public SecurityType getSecurityType() {
return this.securityType;
}

public void setSecurityType(SecurityType securityType) {
this.securityType = securityType;
}

@Column(name = "ticker", length = 128)
public String getTicker() {
return this.ticker;
}

public void setTicker(String ticker) {
this.ticker = ticker;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((securityId == null) ? 0 : securityId.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Security other = (Security) obj;
if (securityId == null) {
if (other.securityId != null)
return false;
} else if (!securityId.equals(other.securityId))
return false;
return true;
}

}


4. JournalEntry.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
* JournalEntry entity.
*/
@SuppressWarnings("serial")
@Entity
@Table(name = "journal_entry")
public class JournalEntry implements java.io.Serializable {

// Fields

private Integer journalEntryId;
private Transaction transaction;
private Account account;
private Double debit;
private Double credit;

// Constructors

/** default constructor */
public JournalEntry() {
}

// Property accessors
@Id
@Column(name = "journal_entry_id", unique = true, nullable = false)
public Integer getJournalEntryId() {
return this.journalEntryId;
}

public void setJournalEntryId(Integer journalEntryId) {
this.journalEntryId = journalEntryId;
}

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "transaction_id")
public Transaction getTransaction() {
return this.transaction;
}

public void setTransaction(Transaction transaction) {
this.transaction = transaction;
}

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "account_id")
public Account getAccount() {
return this.account;
}

public void setAccount(Account account) {
this.account = account;
}

@Column(name = "debit", precision = 18, scale = 4)
public Double getDebit() {
return this.debit;
}

public void setDebit(Double debit) {
this.debit = debit;
}

@Column(name = "credit", precision = 18, scale = 4)
public Double getCredit() {
return this.credit;
}

public void setCredit(Double credit) {
this.credit = credit;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((journalEntryId == null) ? 0 : journalEntryId.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
JournalEntry other = (JournalEntry) obj;
if (journalEntryId == null) {
if (other.journalEntryId != null)
return false;
} else if (!journalEntryId.equals(other.journalEntryId))
return false;
return true;
}

}


5. Transaction.java
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;

/**
* Transaction entity.
*/
@SuppressWarnings("serial")
@Entity
@Table(name = "transaction")
public class Transaction implements java.io.Serializable {

// Fields

private Integer transactionId;
private Security security;
private TradeType tradeType;
private Double price;
private Integer quantity;
private Set<JournalEntry> journalEntries = new HashSet<JournalEntry>(0);

// Constructors

/** default constructor */
public Transaction() {
}

// Property accessors
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "transaction_id", unique = true, nullable = false)
public Integer getTransactionId() {
return this.transactionId;
}

public void setTransactionId(Integer transactionId) {
this.transactionId = transactionId;
}

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "security_id")
public Security getSecurity() {
return this.security;
}

public void setSecurity(Security security) {
this.security = security;
}

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "trade_type_id")
public TradeType getTradeType() {
return this.tradeType;
}

public void setTradeType(TradeType tradeType) {
this.tradeType = tradeType;
}

@Column(name = "price", precision = 8, scale = 4)
public Double getPrice() {
return this.price;
}

public void setPrice(Double price) {
this.price = price;
}

@Column(name = "quantity")
public Integer getQuantity() {
return this.quantity;
}

public void setQuantity(Integer quantity) {
this.quantity = quantity;
}

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "transaction")
@OrderBy("journalEntryId asc")
public Set<JournalEntry> getJournalEntries() {
return this.journalEntries;
}

public void setJournalEntries(Set<JournalEntry> journalEntries) {
this.journalEntries = journalEntries;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((transactionId == null) ? 0 : transactionId.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Transaction other = (Transaction) obj;
if (transactionId == null) {
if (other.transactionId != null)
return false;
} else if (!transactionId.equals(other.transactionId))
return false;
return true;
}

}

Friday, April 3, 2009

Generic Data Access Objects with Pagnation under Spring and Hibernate Framework

Page.java
import java.util.List;

public class Page<T> {
private List<T> rowsInPage;
private int pageSize;
private int pageNo;
private int totalRows;

/**
*
* @param pageNo
* @param pageSize
* @param rowsInPage
* @param totalRows
*/
public Page(int pageNo, int pageSize, List<T> rowsInPage, int totalRows) {
if(pageSize > 0){
this.pageNo = (pageNo > 0) ? pageNo : 1;
this.pageSize = pageSize;
this.rowsInPage = rowsInPage;
this.totalRows = totalRows;
}else if(pageSize == 0){
this.pageNo = 0;
this.pageSize = 0;
this.rowsInPage = null;
this.totalRows = 0;
}else{
this.pageNo = 1;
this.pageSize = -1;
this.rowsInPage = rowsInPage;
this.totalRows = -1;
}
}

/**
*
* @return
*/
public boolean hasNext() {
return getPages() > pageNo;
}

/**
*
* @return
*/
public boolean hasPrevious() {
return pageNo > 1;
}

/**
*
* @return
*/
public List<T> getRowsInPage() {
return rowsInPage;
}

/**
*
* @return
*/
public int getPageSize() {
return pageSize;
}

/**
*
* @return
*/
public int getPageNo() {
return pageNo;
}

/**
*
* @return
*/
public int getTotalRows() {
return totalRows;
}

/**
*
* @return
*/
public int getPages() {
if(totalRows > 0)
return (totalRows%pageSize == 0) ? totalRows / pageSize : totalRows / pageSize + 1;
else if(totalRows == 0)
return 0;
else
return 1;
}
}


GenericDAO.java
import java.io.Serializable;
import org.hibernate.criterion.Order;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.aais.core.utils.Page;

@Transactional(rollbackFor=Exception.class)
public interface GenericDAO<T, ID extends Serializable> {

/**
*
* @param id
* @param lock
* @return
*/
@Transactional(readOnly=true)
public T findById(ID id, boolean lock);

/**
*
* @param pageNo
* @param pageSize
* @param order
* @return
*/
@Transactional(readOnly=true)
public Page<T> findAll(int pageNo, int pageSize, Order order);

/**
*
* @param pageNo
* @param pageSize
* @param exampleInstance
* @param order
* @param excludeProperty
* @return
*/
@Transactional(readOnly=true)
public Page<T> findByExample(int pageNo, int pageSize, T exampleInstance, Order order, String[] excludeProperty);

/**
*
* @param pageNo
* @param pageSize
* @param queryName
* @param paramNames
* @param values
* @return
*/
@Transactional(readOnly=true)
public Page<T> findByHQL(int pageNo, int pageSize, String queryName, String[] paramNames, Object[] values);

/**
*
* @param entity
* @return
*/
@Transactional(propagation=Propagation.REQUIRED)
public T saveOrUpdate(T entity);

/**
*
* @param entity
*/
@Transactional(propagation=Propagation.REQUIRED)
public void delete(T entity);
}


GenericDAOHibernateImpl.java
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.aais.core.dao.GenericDAO;
import com.aais.core.utils.Page;

public abstract class GenericDAOHibernateImpl<T, ID extends Serializable> extends HibernateDaoSupport implements GenericDAO<T, ID> {

private Class<T> persistentClass;
private final static Log logger = LogFactory.getLog(GenericDAOHibernateImpl.class);

/**
*
*/
@SuppressWarnings("unchecked")
public GenericDAOHibernateImpl() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

/**
*
* @return
*/
public Class<T> getPersistentClass() {
return persistentClass;
}

/**
* (pageNo > 0 && pageSize > 0) paginate
* (pageNo < 0 && pageSize < 0) don't paginate
*/
public Page<T> findAll(int pageNo, int pageSize, Order order) {
return findByCriteria(pageNo, pageSize, order, (Criterion[])null);
}

/**
* (pageNo > 0 && pageSize > 0) paginate
* (pageNo < 0 && pageSize < 0) don't paginate
*/
@SuppressWarnings("unchecked")
protected Page<T> findByCriteria(int pageNo, int pageSize, Order order, Criterion...criterion) {
Criteria crit = getCriteria();
if(criterion != null){
for (Criterion c : criterion) {
crit.add(c);
}
}
if(order != null)
crit.addOrder(order);
int rowCount = 0;
if(pageSize > 0){
rowCount = (Integer) ((Criteria) crit.setProjection(Projections.rowCount())).uniqueResult();
crit.setProjection(null);
if(pageNo < 1)
pageNo = 1;
((Criteria) crit).setFirstResult((pageNo - 1) * pageSize);
((Criteria) crit).setMaxResults(pageSize);
if(pageSize > rowCount)
pageSize = rowCount;
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<T> list = crit.list();
return new Page<T>(pageNo, pageSize, list, rowCount);
}

/**
*
* @return
*/
protected Criteria getCriteria(){
Criteria crit = this.getSession().createCriteria(getPersistentClass());
return crit;
}

/**
* (pageNo > 0 && pageSize > 0) paginate
* (pageNo < 0 && pageSize < 0) don't paginate
*/
@SuppressWarnings("unchecked")
protected Page<T> findByCriteria(int pageNo, int pageSize, Criteria crit, Order order){
if(order != null)
crit.addOrder(order);
int rowCount = 0;
if(pageSize > 0){
rowCount = (Integer) ((Criteria) crit.setProjection(Projections.rowCount())).uniqueResult();
crit.setProjection(null);
if(pageNo < 1)
pageNo = 1;
((Criteria) crit).setFirstResult((pageNo - 1) * pageSize);
((Criteria) crit).setMaxResults(pageSize);
if(pageSize > rowCount)
pageSize = rowCount;
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<T> list = crit.list();
return new Page<T>(pageNo, pageSize, list, rowCount);
}

/**
* (pageNo > 0 && pageSize > 0) paginate
* (pageNo < 0 && pageSize < 0) don't paginate
*/
@SuppressWarnings("unchecked")
public Page<T> findByExample(int pageNo, int pageSize, T exampleInstance, Order order, String[] excludeProperty) {
Criteria crit = getCriteria();
Example example = Example.create(exampleInstance).enableLike();
if(excludeProperty != null){
for (String exclude : excludeProperty) {
example.excludeProperty(exclude);
}
}
crit.add(example);
if(order != null)
crit.addOrder(order);
int rowCount = 0;
if(pageSize > 0){
rowCount = (Integer) ((Criteria) crit.setProjection(Projections.rowCount())).uniqueResult();
crit.setProjection(null);
if(pageNo < 1)
pageNo = 1;
((Criteria) crit).setFirstResult((pageNo - 1) * pageSize);
((Criteria) crit).setMaxResults(pageSize);
if(pageSize > rowCount)
pageSize = rowCount;
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<T> list = crit.list();
return new Page<T>(pageNo, pageSize, list, rowCount);
}

/**
*
*/
public T findById(ID id, boolean lock) {
T entity = null;
if (lock)
entity = (T) getHibernateTemplate().get(getPersistentClass(), id, LockMode.UPGRADE);
else
entity = (T) getHibernateTemplate().get(getPersistentClass(), id);
if(entity == null){
logger.warn("Could not find out " + getPersistentClass().getName() + " instance with id=" + id);
}else{
if(logger.isDebugEnabled())
logger.debug("Getting "+getPersistentClass().getName()+" instance with id: " + id);
}
return entity;
}

/**
*
* @param queryName
* @param paramNames
* @param values
* @return
*/
private Query createQuery(String queryName, String[] paramNames, Object[] values) {
Query query = getSession().getNamedQuery(queryName);
query.setCacheable(true);
if ((paramNames != null) && (values != null)) {
for (int i = 0; i < paramNames.length; i++) {
query.setParameter(paramNames[i], values[i]);
}
}
return query;
}

/**
* (pageNo > 0 && pageSize > 0) paginate
* (pageNo < 0 && pageSize < 0) don't paginate
* don't use for full table paginate, that would be low efficency
*/
@SuppressWarnings("unchecked")
public Page<T> findByHQL(int pageNo, int pageSize, String queryName, String[] paramNames, Object[] values){
long rowCount = 0;
Query query = createQuery(queryName, paramNames, values);
if(pageSize > 0){
rowCount = ((Long)getRowCountByHQL(appendRowCountHQL(queryName), paramNames, values)).longValue();
if(pageNo < 1)
pageNo = 1;
if(pageSize > rowCount)
pageSize = (int)rowCount;
query.setFirstResult((pageNo - 1) * pageSize);
query.setMaxResults(pageSize);
}
List<T> list = query.list();
return new Page<T>(pageNo, pageSize, list, (int)rowCount);
}

/**
*
* @param queryName
* @return
*/
private String appendRowCountHQL(String queryName){
return queryName + ".Count";
}

/**
*
* @param queryName
* @param paramNames
* @param values
* @return
*/
@SuppressWarnings("unchecked")
private Object getRowCountByHQL(final String queryName, final String[] paramNames, final Object[] values) {
return ((Object) getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query query = createQuery(queryName, paramNames, values);
if (paramNames != null && values != null && paramNames.length == values.length) {
for (int i = 0, max = paramNames.length; i < max; i++) {
query.setParameter(paramNames[i], values[i]);
}
}
return query.uniqueResult();
}
}));
}


/**
*
*/
public T saveOrUpdate(T entity) throws DataIntegrityViolationException{
getHibernateTemplate().saveOrUpdate(entity);
return entity;
}

/**
*
*/
public void delete(T entity) {
getHibernateTemplate().delete(entity);
}
}

Thursday, April 2, 2009

Unit Testing Sample with Spring and JUnit Annotations

package test.com.one.dao.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.one.dao.CustomerDAO;
import com.one.model.Customer;

@ContextConfiguration(locations={"/applicationContext.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class CustomerDAOHibernateImplTests extends AbstractTransactionalJUnit4SpringContextTests{

@Autowired
private CustomerDAO customerDAO;

@Before
public void setup(){

}

@After
public void clean(){

}

@Test
public void testCRUD(){
Customer customer = new Customer();
customer.setCustomerFirstName("firstName");
customer.setCustomerLastName("lastName");
customer.setEmailAddr("email");
customer.setCreatedOn(new Date());
customer.setUpdatedOn(new Date());
customerDAO.saveOrUpdateCustomer(customer);
Assert.assertNotNull(customer.getCustomerId());
Assert.assertTrue(customer.getCustomerId().intValue() > 0);
customer = (Customer) customerDAO.getCustomerByCustomerId(customer.getCustomerId());
Assert.assertNotNull(customer);
Assert.assertEquals(customer.getCustomerFirstName(), "firstName");
Assert.assertEquals(customer.getCustomerLastName(), "lastName");
Assert.assertEquals(customer.getEmailAddr(), "email");
customerDAO.deleteCustomer(customer);
customer = (Customer) customerDAO.getCustomerByCustomerId(customer.getCustomerId());
Assert.assertNull(customer);
}

@Test
public void testGetCustomersByDateRange(){
Customer customer = new Customer();
customer.setCustomerFirstName("firstName");
customer.setCustomerLastName("lastName");
customer.setEmailAddr("email");
customer.setCreatedOn(new Date());
customer.setUpdatedOn(new Date());
customerDAO.saveOrUpdateCustomer(customer);
Assert.assertNotNull(customer.getCustomerId());
Assert.assertTrue(customer.getCustomerId().intValue() > 0);
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_YEAR, -1);
Date from = c.getTime();
c.add(Calendar.DAY_OF_YEAR, +2);
Date to = c.getTime();
List list = customerDAO.getCustomersByDateRange(from, to);
Assert.assertNotNull(list);
Assert.assertTrue(list.size() > 0);
}

@Ignore
public void testGetCustomerByFirstnameAndLastnameAndEmail(){
Customer customer = new Customer();
customer.setCustomerFirstName("firstName");
customer.setCustomerLastName("lastName");
customer.setEmailAddr("email");
customer.setCreatedOn(new Date());
customer.setUpdatedOn(new Date());
customerDAO.saveOrUpdateCustomer(customer);
Assert.assertNotNull(customer.getCustomerId());
Assert.assertTrue(customer.getCustomerId().intValue() > 0);
customer = (Customer) customerDAO.getCustomerByFirstnameAndLastnameAndEmail("firstName", "lastName", "email");
Assert.assertNotNull(customer);
Assert.assertEquals(customer.getCustomerFirstName(), "firstName");
Assert.assertEquals(customer.getCustomerLastName(), "lastName");
Assert.assertEquals(customer.getEmailAddr(), "email");
}

}