/* * Data Hub Service (DHuS) - For Space data distribution. * Copyright (C) 2013,2014,2015 GAEL Systems * * This file is part of DHuS software sources. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package fr.gael.dhus.database.dao.interfaces; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.DetachedCriteria; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.DataAccessUtils; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import javax.swing.event.EventListenerList; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.sql.SQLException; import java.util.Date; import java.util.List; /** * Hibernate DAO Implementation, containing minimal CRUD operations. * * @param <T> Object concerned by this DAO * @param <PK> Primary Key of this Object. */ public class HibernateDao<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK>, Pageable<T> { protected Class<T> entityClass; private final EventListenerList listeners = new EventListenerList (); @SuppressWarnings ("unchecked") public HibernateDao () { ParameterizedType genericSuperclass = (ParameterizedType) getClass ().getGenericSuperclass (); this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments ()[0]; } @SuppressWarnings ("unchecked") @Override public T create (T t) { T sent = t; long start = new Date ().getTime (); PK id = (PK) getHibernateTemplate ().save (t); t = getHibernateTemplate ().get ((Class<T>)t.getClass (), id); long end = new Date ().getTime (); logger.info("Create/save " + entityClass.getSimpleName () + "("+ id +") spent " + (end-start) + "ms" ); fireCreatedEvent (new DaoEvent<T> (sent)); return t; } @Override public T read (PK id) { long start = new Date ().getTime (); T ret = getHibernateTemplate ().get (entityClass, id); long end = new Date ().getTime (); logger.debug("Read " + entityClass.getSimpleName () + "(" + id + ") spent " + (end-start) + "ms" ); return ret; } @Override public void update (T t) { long start = new Date ().getTime (); getHibernateTemplate ().update (t); long end = new Date ().getTime (); logger.info("Update " + entityClass.getSimpleName () + " spent " + (end-start) + "ms" ); fireUpdatedEvent (new DaoEvent<T> (t)); } /** * Merge the provided object into the current session. * This could be useful when one session handle the same object twice. * @param t the entity to merge. */ public void merge (T t) { long start = new Date ().getTime (); getHibernateTemplate().getSessionFactory().getCurrentSession().merge(t); long end = new Date ().getTime (); logger.info("Merge " + entityClass.getSimpleName () + " spent " + (end-start) + "ms" ); } @Override public void delete (T t) { long start = new Date ().getTime (); getHibernateTemplate ().delete (t); long end = new Date ().getTime (); logger.info("Delete " + entityClass.getSimpleName () + " spent " + (end-start) + "ms" ); fireDeletedEvent (new DaoEvent<T> (t)); } /** * Remove all the element from the db og this <T> instance. */ public void deleteAll () { for (T entity : readAll ()) delete (entity); // String hql = "DELETE FROM " + entityClass.getName (); // getHibernateTemplate ().bulkUpdate (hql); } /** * <p>Returns a List of <b>T</b> entities, where HQL clauses can be * specified.</p> * * Note: This method is useful in read only. It can be use to delete or * create <b>T</b> entities, but caution with <code>top</code> and * <code>skip</code> arguments. * * @param clauses query clauses (WHERE, ORDER BY, GROUP BY), if null no * clauses are apply. * @param skip number of entities to skip. * @param n number of entities max returned. * @return a list of <b>T</b> entities. */ @SuppressWarnings ("unchecked") public List<T> scroll (final String clauses, final int skip, final int n) { StringBuilder hql = new StringBuilder (); hql.append ("FROM ").append (entityClass.getName ()); if (clauses != null) hql.append (" ").append (clauses); Session session; boolean newSession = false; try { session = getSessionFactory ().getCurrentSession (); } catch (HibernateException e) { session = getSessionFactory ().openSession (); newSession = true; } Query query = session.createQuery (hql.toString ()); if (skip > 0) query.setFirstResult (skip); if (n > 0) { query.setMaxResults (n); query.setFetchSize (n); } logger.info("Execution of HQL: " + hql.toString ()); long start = System.currentTimeMillis (); List<T> result = (List<T>) query.list (); logger.info("HQL executed in " + (System.currentTimeMillis() -start) + "ms."); if (newSession) { session.disconnect (); } return result; } /** * Retrieve the first element of the results. * * @param query_string * @return */ public T first (String query_string) { @SuppressWarnings ("unchecked") List<T> result = (List<T>) getHibernateTemplate ().find (query_string); return (result.isEmpty ()) ? null : result.get (0); } /** * Returns all Objects in a List. * * @return List containing all Objects. */ @SuppressWarnings ("unchecked") @Override public List<T> readAll () { return find ("FROM " + entityClass.getName ()); } /** * Count objects in table. * * @return Objects count. */ public int count () { int count = 0; @SuppressWarnings ("unchecked") List<Long>counts = find ( "select count(*) FROM " + entityClass.getName ()); if (counts != null) for (Long c:counts) count +=c; return count; } @SuppressWarnings ("rawtypes") public List find(String query_string) throws DataAccessException { long start = new Date ().getTime (); List ret= getHibernateTemplate ().find (query_string); long end = new Date ().getTime (); logger.debug("Query \"" + query_string.replaceAll("(\\r|\\n)", " ").trim () + "\" spent " + (end-start) + "ms" ); return ret; } public void addListener (DaoListener<T> listener) { listeners.add (DaoListener.class, listener); } public void removeListener (DaoListener<T> listener) { listeners.remove (DaoListener.class, listener); } @SuppressWarnings ("unchecked") public DaoListener<T>[] getListeners () { return listeners.getListeners (DaoListener.class); } protected void fireCreatedEvent (DaoEvent<T> e) { for (DaoListener<T> listener : getListeners ()) { listener.created (e); } } protected void fireUpdatedEvent (DaoEvent<T> e) { for (DaoListener<T> listener : getListeners ()) { listener.updated (e); } } protected void fireDeletedEvent (DaoEvent<T> e) { for (DaoListener<T> listener : getListeners ()) { listener.deleted (e); } } @Autowired public void init (SessionFactory session_factory) { setSessionFactory (session_factory); } public void printCurrentSessions () { int num_session = countOpenSessions (); logger.info(countOpenSessions () + " open sessions:"); int index = 0; while (index<num_session) { logger.info(" SESSION_ID "+ getSystemByName("SESSION_ID", index)); logger.info(" CONNECTED "+ getSystemByName("CONNECTED", index)); logger.info(" SCHEMA "+ getSystemByName("SCHEMA", index)); //logger.info( // "TRANSACTION "+ getSystemByName("TRANSACTION", index)); logger.info(" WAITING_FOR_THIS "+ getSystemByName("WAITING_FOR_THIS", index)); logger.info(" THIS_WAITING_FOR "+ getSystemByName("THIS_WAITING_FOR", index)); logger.info(" LATCH_COUNT "+ getSystemByName("LATCH_COUNT", index)); logger.info(" STATEMENT "+ getSystemByName("CURRENT_STATEMENT",index)); logger.info(""); index++; } } @SuppressWarnings ("rawtypes") private int countOpenSessions () { return DataAccessUtils.intResult (getHibernateTemplate ().execute ( new HibernateCallback<List>() { @Override public List doInHibernate(Session session) throws HibernateException, SQLException { String sql = "SELECT count (*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS"; SQLQuery query = session.createSQLQuery (sql); return query.list (); } })); } @SuppressWarnings ({ "unchecked", "rawtypes" }) private String getSystemByName (final String name, final int index) { return DataAccessUtils.uniqueResult (getHibernateTemplate ().execute ( new HibernateCallback<List>() { @Override public List doInHibernate(Session session) throws HibernateException, SQLException { String sql = "SELECT " + name + " FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS" + " LIMIT 1 OFFSET " + index; SQLQuery query = session.createSQLQuery (sql); return query.list (); } })).toString (); } /** * Returns a paged list of database entities. * * @param query the passed query to retrieve the list. * @param skip the number of elements to skip in the list (0=no skip). * @param top number of element to be retained in the list. * @throws ClassCastException if query does not returns entity list of type T. * @see org.hibernate.Query */ @Override public List<T> getPage (final String query, final int skip, final int top) { return getHibernateTemplate ().execute (new HibernateCallback<List<T>> () { // List must be instance of List<T> otherwise ClassCast @SuppressWarnings ("unchecked") @Override public List<T> doInHibernate (Session session) throws HibernateException, SQLException { Query hql_query = session.createQuery (query); hql_query.setFirstResult (skip); hql_query.setMaxResults (top); return hql_query.list (); } }); } @SuppressWarnings ("unchecked") public List<T> listCriteria (DetachedCriteria detached, int skip, int top) { SessionFactory factory = getSessionFactory (); org.hibernate.classic.Session session = factory.getCurrentSession (); Criteria criteria = detached.getExecutableCriteria (session); if (skip > 0) criteria.setFirstResult (skip); if (top > 0) criteria.setMaxResults (top); return criteria.list (); } @SuppressWarnings ("unchecked") public T uniqueResult (DetachedCriteria criteria) { return (T) criteria.getExecutableCriteria ( getSessionFactory ().getCurrentSession ()).uniqueResult (); } public int count (DetachedCriteria detached) { Session session = getSessionFactory ().getCurrentSession (); Criteria criteria = detached.getExecutableCriteria (session); Object result = criteria.uniqueResult (); return ((Number) result).intValue (); } }