package gr.ntua.ivml.athena.db;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.hibernate.exception.ConstraintViolationException;
public class DAO<T, ID extends Serializable> {
protected Class<T> persistentClass;
static Logger daoLog = Logger.getLogger( DAO.class );
Logger log;
public DAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
log = Logger.getLogger( this.getClass() );
}
public Transaction beginTransaction() {
return getSession().beginTransaction();
}
public Session getSession() {
return DB.getSession();
}
public Class<T> getPersistentClass() {
return persistentClass;
}
public void deleteAll() {
boolean commit = false;
Transaction t = getSession().getTransaction();
if( !t.isActive()) {
t=getSession().beginTransaction();
commit = true;
}
getSession().createQuery(
"delete from " + getPersistentClass().getCanonicalName())
.executeUpdate();
if( commit )
t.commit();
}
/**
* This method doesn't check if the object is in the database.
* @param id
* @param lock
* @return
*/
@SuppressWarnings("unchecked")
public T findById(ID id, boolean lock) {
T entity;
if (lock)
entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);
else
entity = (T) getSession().load(getPersistentClass(), id);
return entity;
}
/**
* This method goes to the DB and checks if the object is actually there.
* @param id
* @param lock
* @return
*/
@SuppressWarnings("unchecked")
public T getById(ID id, boolean lock) {
T entity;
if (lock)
entity = (T) getSession().get(getPersistentClass(), id, LockMode.UPGRADE);
else
entity = (T) getSession().get(getPersistentClass(), id);
return entity;
}
@SuppressWarnings("unchecked")
public List<T> findAll() {
return findByCriteria();
}
public ScrollableResults scrollAll() {
Criteria crit = getSession().createCriteria(getPersistentClass());
return crit.scroll();
}
@SuppressWarnings("unchecked")
public List<T> findByExample(T exampleInstance, String[] excludeProperty) {
Criteria crit = getSession().createCriteria(getPersistentClass());
Example example = Example.create(exampleInstance);
for (String exclude : excludeProperty) {
example.excludeProperty(exclude);
}
crit.add(example);
return crit.list();
}
/**
* Will return null if things didn't turn out well.
* @param entity
* @return
*/
@SuppressWarnings("unchecked")
public T makePersistent(T entity) {
boolean commit = false;
Transaction t = getSession().getTransaction();
if( !t.isActive()) {
t=getSession().beginTransaction();
commit = true;
}
try {
getSession().saveOrUpdate(entity);
getSession().flush();
if( commit )
t.commit();
} catch( ConstraintViolationException he ) {
t.rollback();
log.warn( "Session closed!");
getSession().close();
DB.removeSession();
DB.setSession( DB.newSession());
if( !commit )
getSession().beginTransaction();
commit = false;
entity = null;
} catch( NonUniqueObjectException nve ) {
// a different object with the same id was in session
log.warn( "A merge was issued, try to avoid creating objects from scratch!");
T newEntity = (T) getSession().merge(entity);
getSession().flush();
if( commit )
t.commit();
entity = newEntity;
// maybe we need to catch stuff here too
}
return entity;
}
/**
* tried to catch the constraint violation exception and
* make a new session and transaction.
*
* When this returns false you should not use any of the objects
* you retrieved during the running request.
*
* You have a new transaction running. All previously fetched objects
* don't have "magic" any more (lazy loading etc)
*
* @param entity
* @return
*/
public boolean makeTransient(T entity ) {
boolean result = true;
boolean commit = false;
// if the DAO is used in an environment where there is no transaction running
// It creates one automatically.
Transaction t = getSession().getTransaction();
if( !t.isActive()) {
t=getSession().beginTransaction();
commit = true;
}
try {
getSession().delete(entity);
getSession().flush();
if( commit )
t.commit();
} catch(ConstraintViolationException he ) {
result = false;
t.rollback();
getSession().close();
DB.removeSession();
DB.setSession( DB.newSession());
if( !commit )
getSession().beginTransaction();
commit = false;
} finally {
// don't know, probably nothing
}
return result;
}
public long count( String simpleCondition ) {
Long count = (Long) getSession()
.createQuery("select count(*) from "+ getPersistentClass().getName() +
(simpleCondition==null?"":(" where " + simpleCondition )))
.iterate().next();
return count.longValue();
}
public long count() {
return count( null );
}
@SuppressWarnings("unchecked")
public T simpleGet( String condition ) {
List<T> l = getSession().createQuery(" from " + getPersistentClass().getName() +
(condition==null?"":" where " + condition ))
.list();
if( l.size()> 0 ) {
return (T)l.get(0);
} else {
return null;
}
}
@SuppressWarnings("unchecked")
public List<T> simpleList( String condition) {
List<T> l = getSession().createQuery(" from " + getPersistentClass().getName() +
(condition==null?"":" where " + condition ))
.list();
return l;
}
public void flush() {
getSession().flush();
}
public void clear() {
getSession().clear();
}
/**
* Use this inside subclasses as a convenience method.
*/
@SuppressWarnings("unchecked")
protected List<T> findByCriteria(Criterion... criterion) {
Criteria crit = getSession().createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
public static void generateFieldnames( int level, String prefix, Class clazz, Set<String> result ) {
if( level == 0 ) return;
for( Field f:clazz.getDeclaredFields()) {
if( f.getAnnotation( org.hibernate.search.annotations.Field.class ) != null ) {
if( f.getAnnotation( org.hibernate.search.annotations.FieldBridge.class ) != null ) {
result.add( prefix+f.getName()+"_el" );
result.add( prefix+f.getName()+"_en" );
result.add( prefix+f.getName()+"_xx" );
} else
result.add( prefix+f.getName() );
}
if( f.getAnnotation( org.hibernate.search.annotations.IndexedEmbedded.class ) != null ) {
Type t = f.getGenericType();
if( t instanceof ParameterizedType ) {
// this assumes lists, doesnt make sense with other paramterized types
// and doesn't work with Asset<VideoFileDescriptor> eg
t = ((ParameterizedType)t).getActualTypeArguments()[0];
if( t instanceof Class )
generateFieldnames(level-1, prefix+f.getName()+".", (Class) t, result);
} else
generateFieldnames(level-1, prefix+f.getName()+".", f.getType(), result);
}
}
}
protected Set<String> classFields( String prefix ) {
HashSet<String> fields = new HashSet<String>();
if( prefix == null ) prefix = "";
for( Field f:persistentClass.getDeclaredFields()) {
fields.add( prefix+f.getName());
}
return fields;
}
}