gov.nih.nci.lv.util.HibernateHelper.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.lv.util.HibernateHelper.java

Source

/*
* Copyright ScenPro, Inc and SemanticBits, LLC
*
* Distributed under the OSI-approved BSD 3-Clause License.
* See http://ncip.github.com/labviewer/LICENSE.txt for details.
*/

package gov.nih.nci.lv.util;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.context.ManagedSessionContext;
import org.hibernate.engine.SessionFactoryImplementor;

/**
 * Hibernate Helper class.
 * @author Naveen Amiruddin
 *
 */

public class HibernateHelper implements LVHibernateHelper {
    /**
     * The maximum number of elements that can be in a single in clause. This is due to bug
     * http://opensource.atlassian.com/projects/hibernate/browse/HHH-2166
     */
    public static final int MAX_IN_CLAUSE_LENGTH = 500;

    private static final Logger LOG = Logger.getLogger(HibernateHelper.class);

    private Configuration configuration;
    private SessionFactory sessionFactory;

    /**
     * Default constructor.
     */
    public HibernateHelper() {
        this(null, null);
    }

    /**
     * Constructor to build the hibernate helper.
     * @param namingStrategy the name strategy, if one is needed, null otherwise.
     * @param interceptor the interceptor, if one is needed, null otherwise.
     */
    public HibernateHelper(NamingStrategy namingStrategy, Interceptor interceptor) {
        try {
            configuration = new AnnotationConfiguration();
            initializeConfig(namingStrategy, interceptor);
            configuration = configuration.configure();
            // We call buildSessionFactory twice, because it appears that the annotated classes are
            // not 'activated' in the config until we build. The filters required the classes to
            // be present, so we throw away the first factory and use the second. If this is
            // removed, you'll likely see a NoClassDefFoundError in the unit tests
            configuration.buildSessionFactory();
            sessionFactory = configuration.buildSessionFactory();
        } catch (HibernateException e) {
            //            LOG.error(e.getMessage(), e);
            //            throw new ExceptionInInitializerError(e);
            LOG.warn("Failed to initialize HibernateHelper using hibernate.cfg.xml.  "
                    + "This is expected behavior during unit testing.", e);
            e.printStackTrace();
        }
    }

    private void initializeConfig(NamingStrategy namingStrategy, Interceptor interceptor) {
        if (namingStrategy != null) {
            configuration.setNamingStrategy(namingStrategy);
        }

        if (interceptor != null) {
            configuration.setInterceptor(interceptor);
        }
    }

    /**
     * @return the configuration
     */
    public Configuration getConfiguration() {
        return this.configuration;
    }

    /**
     * @return the sessionFactory
     */
    public SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    /**
     * Get the session that is bound to the current context.
     * @return the current session
     */
    public Session getCurrentSession() {
        Session s = getSessionFactory().getCurrentSession();
        beginTransaction();
        return s;
    }

    /**
     * Starts a transaction on the current Hibernate session. Intended for use in
     * unit tests - DAO / Service layer logic should rely on container-managed transactions
     *
     * @return a Hibernate session.
     */
    public Transaction beginTransaction() {
        return getSessionFactory().getCurrentSession().beginTransaction();
    }

    /**
     * Checks if the transaction is active and then rolls it back.
     *
     * @param tx the Transaction to roll back.
     */
    public void rollbackTransaction(Transaction tx) {
        if ((tx != null) && (tx.isActive())) {
            tx.rollback();
        }
    }

    /**
     * Open a hibernate session and bind it as the current session via
     * {@link ManagedSessionContext#bind(org.hibernate.classic.Session)}. The hibernate property
     * "hibernate.current_session_context_class" must be set to "managed" for this to have effect This method should be
     * called from within an Interceptor or Filter type class that is setting up the scope of the Session. This method
     * should then call {@link HibernateUtil#unbindAndCleanupSession()} when the scope of the Session is expired.
     *
     * @see ManagedSessionContext#bind(org.hibernate.classic.Session)
     */
    public void openAndBindSession() {
        SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor) getSessionFactory();
        org.hibernate.classic.Session currentSession = sessionFactoryImplementor.openSession(null, true, false,
                ConnectionReleaseMode.AFTER_STATEMENT);
        currentSession.setFlushMode(FlushMode.COMMIT);
        ManagedSessionContext.bind(currentSession);
    }

    /**
     * Close the current session and unbind it via {@link ManagedSessionContext#unbind(SessionFactory)}. The hibernate
     * property "hibernate.current_session_context_class" must be set to "managed" for this to have effect. This method
     * should be called from within an Interceptor or Filter type class that is setting up the scope of the Session,
     * when this scope is about to expire.
     */
    public void unbindAndCleanupSession() {
        org.hibernate.classic.Session currentSession = ManagedSessionContext.unbind(getSessionFactory());
        if (currentSession != null) {
            currentSession.close();
        }
    }

    /**
     * Break up a list of items into separate in clauses, to avoid limits imposed by databases or by Hibernate bug
     * http://opensource.atlassian.com/projects/hibernate/browse/HHH-2166.
     * @param items list of items to include in the in clause
     * @param columnName name of column to match against the list
     * @param blocks empty Map of HQL param name to param list of values to be set in the HQL query - it will be
     *               populated by the method
     * @return full HQL "in" clause, of the form: " columnName in (:block1) or ... or columnName in (:blockN)"
     */
    public static String buildInClause(List<? extends Serializable> items, String columnName,
            Map<String, List<? extends Serializable>> blocks) {
        StringBuffer inClause = new StringBuffer();
        for (int i = 0; i < items.size(); i += MAX_IN_CLAUSE_LENGTH) {
            List<? extends Serializable> block = items.subList(i, Math.min(items.size(), i + MAX_IN_CLAUSE_LENGTH));
            String paramName = "block" + (i / MAX_IN_CLAUSE_LENGTH);
            if (inClause.length() > 0) {
                inClause.append(" or");
            }
            inClause.append(" " + columnName + " in (:" + paramName + ")");
            blocks.put(paramName, block);
        }
        return inClause.toString();
    }

    /**
     * Bind the parameters returned by {@link #buildInClause(List, String, Map)} to a hibernate Query.
     * @param query hibernate query to bind to
     * @param blocks blocks to be bound to query
     */
    public static void bindInClauseParameters(Query query, Map<String, List<? extends Serializable>> blocks) {
        for (Map.Entry<String, List<? extends Serializable>> block : blocks.entrySet()) {
            query.setParameterList(block.getKey(), block.getValue());
        }
    }

}