/**
* TNTConcept Easy Enterprise Management by Autentia Real Bussiness Solution S.L.
* Copyright (C) 2007 Autentia Real Bussiness Solution S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* HibernateManagerBase.java
*/
package com.autentia.tnt.dao.hibernate;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import com.autentia.tnt.dao.DataAccException;
import com.autentia.tnt.dao.IDataAccessObject;
import com.autentia.tnt.dao.ITransferObject;
import com.autentia.tnt.dao.SearchCriteria;
import com.autentia.tnt.dao.SortCriteria;
import com.autentia.tnt.util.HibernateUtil;
import com.autentia.tnt.util.SpringUtils;
/**
* Clase abstracta base de todas las clases que resuelven la l�gica de negocio de la aplicaci�n
* Hace trabajo com�n a la hora de acceder a base de datos mediante hibernate
*
* @author <a href="www.autentia.com">AUTENTIA</a>
*/
public abstract class HibernateManagerBase<T extends ITransferObject> implements IDataAccessObject<T>
{
/** El objeto logger */
private static final Log log = LogFactory.getLog(HibernateManagerBase.class);
/**
* Get all existing objects of an entity
* @param <T> type of entity the manager works with
* @param clazz entity class
* @param crit sort criteria (can be null)
* @return the list of all existing object ordered by criteria
* @throws DataAccException
*/
protected List<T> list( Class<T> clazz, SortCriteria crit ) throws DataAccException
{
return (List<T>)getAll( clazz.getName(), crit );
}
/**
* Get DAOs matching searching criteria
* @param <T> type of entity the manager works with
* @param clazz entity class
* @param search search criteria
* @param sort sort criteria (can be null)
* @return the list of objects matching the criteria
* @throws DataAccException
*/
protected List<T> search( Class<T> clazz, SearchCriteria search, SortCriteria sort ) throws DataAccException
{
if (log.isDebugEnabled()){
log.debug("search - clazz='"+clazz+"' search='" + search +"' sort='"+ sort +"'");
}
List<T> ret = null;
try
{
// Append FROM condition
StringBuilder query = new StringBuilder("FROM ");
query.append(clazz.getName());
query.append( " p" );
// Append WHERE condition
if( search!=null )
{
query.append( " " );
query.append( search.getHQL() );
}
// Append ORDER BY condition
if(sort!=null)
{
query.append( " " );
query.append(sort.getHQL());
}
// Make query
ret = (List<T>) search( query.toString(), (search==null) ? new Object[0] : search.getArguments() );
if (log.isDebugEnabled()){
log.debug("search - found "+ret.size()+" objects of type "+clazz.getName() );
}
}
catch(Exception ex)
{
log.error("search - error searching",ex);
throw new DataAccException("Error searching "+clazz.getName()+" objects",ex);
}
return ret;
}
/**
* Perform a custom Hibernate HQL search.
* @param hql the hql query
* @oaram args query parameters
* @return a List of Objects with the result
* @throws DataAccException
*/
@SuppressWarnings("unchecked")
protected List search( String hql, Object...args ) throws DataAccException
{
if (log.isDebugEnabled()){
log.debug("search - hql='"+hql+"'");
}
Session session = null;
List<Object> ret = null;
try
{
session = HibernateUtil.getSessionFactory().getCurrentSession();
if(!session.getTransaction().isActive()) {
session.beginTransaction();
}
Query q = session.createQuery( hql );
for( int i=0 ; i<args.length ; i++ )
{
if( args[i] instanceof Collection )
{
q.setParameterList( "arg"+i, (Collection)args[i] );
}
else
{
q.setParameter( "arg"+i, args[i] );
}
}
ret = q.list();
if (log.isDebugEnabled()){
log.debug("search - found "+ret.size()+" objects" );
}
}
catch(Exception ex)
{
log.error("search - error searching",ex);
throw new DataAccException("Error searching '"+hql+"'",ex);
}
return ret;
}
/* Sin revisar **********************************************************************************************/
/** El objeto logger para el cach� */
private static Log loggerCache = LogFactory.getLog(HibernateManagerBase.class);
/** Cach� de objetos de base de datos */
private static Hashtable cache = new Hashtable();
/** Indicador de si las operaciones que se van a efectuar en esta instancia van a interactuar con el cach�*/
protected boolean cacheable = false;
/**
* Crea una nueva instancia de esta clase
*/
protected HibernateManagerBase()
{}
/**
* Crea una nueva instancia de esta clase
* @param cacheable indica si las operaciones en esta instancia deben tener en
* cuenta la cach�
*/
protected HibernateManagerBase(boolean cacheable)
{
this.cacheable=cacheable;
}
public void setCacheable(boolean cacheable)
{
this.cacheable=cacheable;
}
public boolean isCacheable()
{
return cacheable;
}
/**
* Devuelve un objeto de negocio por clave primaria.
*
* @param pk Una instancia de la clave primaria
* @return Una instancia del objeto recuperado de base de datos o null en el caso de no
* encontrar ning�n objeto con la clave primaria especificada
*/
protected <T extends Object> T getByPk(Class<T> theClass, Serializable pk) throws DataAccException
{
T objResult = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
objResult = getByPk(theClass,pk,session);
return objResult;
}
/**
* Devuelve un objeto de negocio por clave primaria.
*
* @param obj Instancia vac�a del objeto que se desea recuperar
* @param pk Una instancia de la clave primaria
* @param session sesi�n de hibernate
* @return Una instancia del objeto recuperado de base de datos o null en el caso de no
* encontrar ning�n objeto con la clave primaria especificada
*/
protected <T extends Object> T getByPk(Class<T> theClass, Serializable pk, Session session) throws DataAccException
{
log.debug("getByPk");
T objResult = null;
try
{
objResult = (T)session.load(theClass, pk);
if (log.isDebugEnabled()){
log.debug("Objeto con clave '"+ pk + "' recuperado");
}
return (T)objResult;
}
catch(Exception ex)
{
String msg = "Error recuperando el objeto de tipo '" + theClass + "' con clave primaria '" + pk + "': ";
log.error("Error recuperando el objeto con clave '" + pk + "': "+ msg);
throw new DataAccException(msg, ex);
}
}
/**
* Devuelve un objeto de negocio por clave primaria
*
* @param pk Una instancia de la clave primaria
* @return Una instancia del objeto recuperado de base de datos
*/
protected Object getByPk(Serializable pk) throws DataAccException
{
throw new DataAccException("HibernateManagerBase.getByPk. M�todo no soportado por esta clase");
}
/**
* Inserta un objeto de negocio en base de datos
*
* @param obj a insertar
*/
public void insert(T obj) throws DataAccException
{
log.debug("insert");
Session session = null;
try
{
session = HibernateUtil.getSessionFactory().getCurrentSession();
obj.setOwnerId(SpringUtils.getPrincipal().getId());
obj.setDepartmentId(SpringUtils.getPrincipal().getDepartmentId());
Date d = new Date();
obj.setInsertDate(d); obj.setUpdateDate(d);
session.save(obj);
log.debug("objeto correctamente insertado");
if(this.cacheable)
HibernateManagerBase.removeCacheFor(obj.getClass().getName());
}
catch(Exception ex)
{
log.error("insert - exception",ex);
StringBuffer msg = new StringBuffer("Error insertando el objeto: ");
msg.append(obj);
throw new DataAccException(msg.toString(),ex);
}
}
/**
* Actualiza una objeto de negocio en base de datos
*
* @param obj el objeto de negocio a actualizar
*/
public void update(ITransferObject obj,Serializable pk) throws DataAccException
{
log.debug("update");
Session session = null;
try
{
session = HibernateUtil.getSessionFactory().getCurrentSession();
obj.setUpdateDate(new Date());
session.merge(obj);
if (log.isDebugEnabled()){
log.debug("objeto con clave '"+ pk +"' correctamente actualizado");
}
if(this.cacheable)
HibernateManagerBase.removeCacheFor(obj.getClass().getName());
}
catch(Exception ex)
{
String msg = "Error actualizando el objeto '" + obj + "' con clave primaria '" + pk + "'";
log.debug("error actualizando el objeto '"+ pk +"': " + msg);
throw new DataAccException(msg, ex);
}
}
public ITransferObject updateAndReturn(ITransferObject obj,Serializable pk) throws DataAccException
{
log.debug("update");
Session session = null;
try
{
session = HibernateUtil.getSessionFactory().getCurrentSession();
obj.setUpdateDate(new Date());
ITransferObject ret = (ITransferObject) session.merge(obj);
if (log.isDebugEnabled()){
log.debug("objeto con clave '"+ pk +"' correctamente actualizado");
}
if(this.cacheable)
HibernateManagerBase.removeCacheFor(obj.getClass().getName());
return ret;
}
catch(Exception ex)
{
String msg = "Error actualizando el objeto '" + obj + "' con clave primaria '" + pk + "'";
log.debug("error actualizando el objeto '"+ pk +"': " + msg);
throw new DataAccException(msg, ex);
}
}
/**
* Elimina un objeto de negocio de base de datos
* @deprecated use this method only from derived classes, and use delete() methods in derived classes from other places
* @param obj el objeto de negocio a eliminar
* @param pk clave primaria del objeto de negocio a eliminar
*/
public void delete(Object obj,Serializable pk) throws DataAccException
{
log.debug("delete");
Class clazz = obj.getClass();
Session session = null;
try
{
session = HibernateUtil.getSessionFactory().getCurrentSession();
// Cargamos el objeto antiguo
Object objOld = session.load(clazz, pk);
if (log.isDebugEnabled()){
log.debug("objeto con clave '"+ pk +"' recuperado");
}
// Borramos
session.delete(objOld);
if (log.isDebugEnabled()){
log.debug("objeto con clave '"+ pk +"' correctamente eliminado");
}
if(this.cacheable)
HibernateManagerBase.removeCacheFor(clazz.getName());
doAfterDelete(pk);
}
catch(Exception ex)
{
StringBuffer msg = new StringBuffer("Error borrando el objeto '");
msg.append(pk);
if (log.isDebugEnabled()){
log.debug("error eliminando el objeto '"+ pk +"': " + msg.toString());
}
throw new DataAccException(msg.toString(),ex);
}
}
/**
* Devuelve todas las ocurrencias de un objeto de negocio
*/
protected List getAll() throws DataAccException
{
throw new DataAccException("HibernateManagerBase.getAll. Método no soportado por esta clase");
}
/**
* @deprecated use getAll(Class<T> clazz,SortCriteria) instead
*/
protected <T extends Object> List<T> getAll( String clazz, String[] orderFields ) throws DataAccException
{
return (List<T>)getAll( clazz, new SortCriteria(orderFields) );
}
/**
* Devuelve todas las ocurrencias de un objeto de negocio. Si est� en la cach�, la lista
* la devuelve de la misma y no accede a base de datos
* @deprecated use getAll(Class<T> clazz,SortCriteria) instead
* @param nombre de la clase que representa el objeto de negocio que deseamos recuperar
* @param orderByFieldName lista de nombres de campos por los que queremos efectuar la ordenaci�n
* @param descending si la ordenacion es descendente o ascendente
*/
protected List getAll(String className,SortCriteria crit) throws DataAccException
{
Session session = null;
List lResult = null;
try
{
if(this.cacheable)
{
// Intentamos recuperar la informaci�n de la cach�
lResult = HibernateManagerBase.getAllFromCache(className);
}
if(lResult==null)
{
session = HibernateUtil.getSessionFactory().getCurrentSession();
// Montamos la query HQL
StringBuffer query = new StringBuffer("FROM ");
query.append(className);
if(crit!=null)
{
query.append(" ");
query.append(crit.getHQL());
}
lResult = session.createQuery(query.toString()).list();
if(this.cacheable)
{
HibernateManagerBase.updateCache(className,lResult);
}
}
return lResult;
}
catch(Exception ex)
{
String msg = "Error recuperando la lista de objetos de tipo '" + className + "'";
log.debug(msg);
throw new DataAccException(msg, ex);
}
}
/**
* Actualiza la cach� con un nuevo listado
*
* @param className Nombre de la clase cuyo listado se desea actualizar
* @param list Lista de objetos que se desea actualizar
*/
private static synchronized void updateCache(String className,List list)
{
if (loggerCache.isDebugEnabled()){
loggerCache.debug("actualizando caché para "+ className);
}
if(!hasListFor(className)){
// Solo en el caso de que no exista la lista, la guardamos en la cach�
putInCache(className,list);
}
if (loggerCache.isDebugEnabled()){
loggerCache.debug("caché para "+ className +" actualizada");
}
}
/**
* Pregunta a la cach� si tiene una lista para la clase pasada como par�metro
*
* @param className Nombre de la clase
* @return true si ya tiene lista para la clase, o false en caso contrario
*/
private static synchronized boolean hasListFor(String className)
{
return cache.containsKey(className);
}
/**
* Pone una nueva lista en la cach�
* @param className Nombre de la clase cuyo listado se desea actualizar
* @param list Lista de objetos que se desea actualizar
*/
private static synchronized void putInCache(String className,List list)
{
cache.put(className,list);
if (loggerCache.isDebugEnabled()){
loggerCache.debug("Insertada en la caché la lista de "+ className);
}
}
/**
* Elimina de la cache la lista de objetos de un tipo
* @param className Nombre de la clase cuyo listado se desea eliminar
*/
protected static synchronized void removeCacheFor(String className)
{
if(cache.containsKey(className))
{
cache.remove(className);
if (loggerCache.isDebugEnabled()){
loggerCache.debug("Eliminada la lista de "+ className + " de la cache");
}
}
else
if (loggerCache.isDebugEnabled()){
loggerCache.debug("Se esta intentando eliminar "+ className + " de la cache y no se encuentra en la misma????");
}
}
/**
* Devuelve la lista de objetos solicitada
* @param className Nombre de la clase cuyo listado se desea recuperar
* @return la lista de objetos, o null en el caso de que no exista dicha lista en cache
*/
private static synchronized List getAllFromCache(String className)
{
List result = null;
if(cache.containsKey(className))
{
result = (List)cache.get(className);
if (loggerCache.isDebugEnabled()){
loggerCache.debug("Recuperada de cache la lista de "+ className);
}
}
else {
if (loggerCache.isDebugEnabled()){
loggerCache.debug("No hay lista en cache para "+ className);
}
}
return result;
}
/**
* This method is intended to be overriden in order to add specific behavior
* to be executed after delete an entity.
* @throws DataAccException
*/
public void doAfterDelete(Serializable pk) throws DataAccException {
// Do nothing
}
public void flush() throws DataAccException {
try {
HibernateUtil.getSessionFactory().getCurrentSession().flush();
} catch (Exception e) {
throw new DataAccException("Can´t do all action in database.", e);
}
}
}