/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.core; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.dspace.storage.rdbms.DatabaseConfigVO; import org.hibernate.FlushMode; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.proxy.HibernateProxyHelper; import org.hibernate.resource.transaction.spi.TransactionStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.orm.hibernate5.SessionFactoryUtils; /** * Hibernate implementation of the DBConnection * * @author kevinvandevelde at atmire.com */ public class HibernateDBConnection implements DBConnection<Session> { @Autowired(required = true) @Qualifier("sessionFactory") private SessionFactory sessionFactory; private boolean batchModeEnabled = false; @Override public Session getSession() throws SQLException { if(!isTransActionAlive()){ sessionFactory.getCurrentSession().beginTransaction(); configureBatchMode(); } return sessionFactory.getCurrentSession(); } @Override public boolean isTransActionAlive() { Transaction transaction = getTransaction(); return transaction != null && transaction.getStatus().isOneOf(TransactionStatus.ACTIVE); } protected Transaction getTransaction() { return sessionFactory.getCurrentSession().getTransaction(); } @Override public boolean isSessionAlive() { return sessionFactory.getCurrentSession() != null && sessionFactory.getCurrentSession().getTransaction() != null && sessionFactory.getCurrentSession().getTransaction().getStatus().isOneOf(TransactionStatus.ACTIVE); } @Override public void rollback() throws SQLException { if(isTransActionAlive()){ getTransaction().rollback(); } } @Override public void closeDBConnection() throws SQLException { if(sessionFactory.getCurrentSession() != null && sessionFactory.getCurrentSession().isOpen()) { sessionFactory.getCurrentSession().close(); } } @Override public void commit() throws SQLException { if(isTransActionAlive() && !getTransaction().getStatus().isOneOf(TransactionStatus.MARKED_ROLLBACK, TransactionStatus.ROLLING_BACK)) { getSession().flush(); getTransaction().commit(); } } @Override public synchronized void shutdown() { sessionFactory.close(); } @Override public String getType() { return ((SessionFactoryImplementor) sessionFactory).getDialect().toString(); } @Override public DataSource getDataSource() { return SessionFactoryUtils.getDataSource(sessionFactory); } @Override public DatabaseConfigVO getDatabaseConfig() throws SQLException { DatabaseConfigVO databaseConfigVO = new DatabaseConfigVO(); try (Connection connection = getDataSource().getConnection()) { DatabaseMetaData metaData = connection.getMetaData(); databaseConfigVO.setDatabaseDriver(metaData.getDriverName()); databaseConfigVO.setDatabaseUrl(metaData.getURL()); databaseConfigVO.setSchema(metaData.getSchemaTerm()); databaseConfigVO.setMaxConnections(metaData.getMaxConnections()); databaseConfigVO.setUserName(metaData.getUserName()); } return databaseConfigVO; } @Override public long getCacheSize() throws SQLException { return getSession().getStatistics().getEntityCount(); } @Override @SuppressWarnings("unchecked") public <E extends ReloadableEntity> E reloadEntity(final E entity) throws SQLException { if(entity == null) { return null; } else if(getSession().contains(entity)) { return entity; } else { return (E) getSession().get(HibernateProxyHelper.getClassWithoutInitializingProxy(entity), entity.getID()); } } @Override public void setOptimizedForBatchProcessing(final boolean batchOptimized) throws SQLException { this.batchModeEnabled = batchOptimized; configureBatchMode(); } @Override public boolean isOptimizedForBatchProcessing() { return batchModeEnabled; } private void configureBatchMode() throws SQLException { if(batchModeEnabled) { getSession().setFlushMode(FlushMode.ALWAYS); } else { getSession().setFlushMode(FlushMode.AUTO); } } /** * Evict an entity from the hibernate cache. This is necessary when batch processing a large number of items. * * @param entity The entity to reload * @param <E> The class of the enity. The entity must implement the {@link ReloadableEntity} interface. * @throws SQLException When reloading the entity from the database fails. */ @Override public <E extends ReloadableEntity> void uncacheEntity(E entity) throws SQLException { getSession().evict(entity); } }