com.cosylab.cdb.jdal.hibernate.HibernateUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.cosylab.cdb.jdal.hibernate.HibernateUtil.java

Source

/*******************************************************************************
 * ALMA - Atacama Large Millimeter Array
 * Copyright (c) COSYLAB - Control System Laboratory, 2011
 * (in the framework of the ALMA collaboration).
 * All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *******************************************************************************/
package com.cosylab.cdb.jdal.hibernate;

import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

/**
 * Basic Hibernate helper class, handles SessionFactory, Session and Transaction.
 * <p>
 * Holds Session and Transactions in thread local variables. All
 * exceptions are wrapped in an unchecked HibernateUtilException.
 */
@SuppressWarnings("unchecked")
public class HibernateUtil {

    @SuppressWarnings("serial")
    public static class HibernateUtilException extends Exception {
        public HibernateUtilException(String message, Throwable cause) {
            super(message, cause);
        }

        public HibernateUtilException(Throwable cause) {
            super(cause);
        }

    }

    /**
     * Singleton accessor
     * @return
     */
    public static synchronized HibernateUtil getInstance(Logger logger) {
        if (instance == null) {
            instance = new HibernateUtil(logger);
        }
        return instance;
    }

    /**
     * Nulls the instance field, so that subsequent calls to {@link #getInstance(Logger)} will create a new instance.
     * This probably only makes sense between junit tests that want to start out fresh.
     */
    public static void clearInstance() {
        instance = null;
    }

    private static HibernateUtil instance;

    private final Logger logger;

    private Configuration configuration;
    private SessionFactory sessionFactory;
    private final ThreadLocal threadSession = new ThreadLocal();
    private final ThreadLocal threadTransaction = new ThreadLocal();
    private final ThreadLocal threadInterceptor = new ThreadLocal();

    private static final String HIBERNATE_FILENAME_KEY = "cdb_rdb.hibernate.cfg.filename";
    public static final String HIBERNATE_FILENAME_DEFAULT = "cdb_rdb-hibernate.cfg.xml";

    private final String getConfigurationFileName() {
        String ret = System.getProperty(HIBERNATE_FILENAME_KEY, HIBERNATE_FILENAME_DEFAULT);
        logger.fine("Will try to load hibernate config file '" + ret + "' from the classpath.");
        return ret;
    }

    private HibernateUtil(Logger logger) {
        this.logger = logger;
        // Create the initial SessionFactory from the default configuration files
        try {
            configuration = new AnnotationConfiguration();
            sessionFactory = configuration.configure(getConfigurationFileName()).buildSessionFactory();
            // We could also let Hibernate bind it to JNDI:
            // configuration.configure().buildSessionFactory()
        } catch (Throwable ex) {
            // @TODO HSO: now that we moved this code from static {} initializer to the ctor,
            //            should we throw or at least log the exception?

            // We have to catch Throwable, otherwise we will miss
            // NoClassDefFoundError and other subclasses of Error

            // commented out - will be provided dynamically for the tests...
            //log.error("Building SessionFactory failed.", ex);
            //throw new ExceptionInInitializerError(ex);
        }
    }

    /**
     * Use default configuration and add properties from Properties.
     * Build session factory from combined configuration.
     * @param config
     */
    public void setConfiguration(Properties extraProperties) {
        try {
            Configuration config = new AnnotationConfiguration();
            config.configure(getConfigurationFileName());
            config.addProperties(extraProperties);
            sessionFactory = config.buildSessionFactory();
            configuration = config;
        } catch (Throwable ex) {
            // We have to catch Throwable, otherwise we will miss
            // NoClassDefFoundError and other subclasses of Error
            logger.log(Level.SEVERE, "Building SessionFactory failed.", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    /**
     * Set your own configuration and build session factory from it.
     * Used to tests.
     * @param config
     */
    public void setConfiguration(Configuration config) {
        try {
            sessionFactory = config.buildSessionFactory();
            configuration = config;
        } catch (Throwable ex) {
            // We have to catch Throwable, otherwise we will miss
            // NoClassDefFoundError and other subclasses of Error
            logger.log(Level.SEVERE, "Building SessionFactory failed.", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    /**
      * Returns the SessionFactory used for this static class.
      *
      * @return SessionFactory
      */
    public SessionFactory getSessionFactory() {
        /* Instead of a static variable, use JNDI:
        SessionFactory sessions = null;
        try {
                Context ctx = new InitialContext();
                String jndiName = "java:hibernate/HibernateFactory";
                sessions = (SessionFactory)ctx.lookup(jndiName);
        } catch (NamingException ex) {
                throw new HibernateUtilException(ex);
        }
        return sessions;
         */
        return sessionFactory;
    }

    /**
     * Returns the original Hibernate configuration.
     *
     * @return Configuration
     */
    public Configuration getConfiguration() {
        return configuration;
    }

    /**
     * Rebuild the SessionFactory with the static Configuration.
     *
     */
    public void rebuildSessionFactory() throws HibernateUtilException {
        synchronized (sessionFactory) {
            try {
                sessionFactory = getConfiguration().buildSessionFactory();
            } catch (Exception ex) {
                throw new HibernateUtilException(ex);
            }
        }
    }

    /**
     * Rebuild the SessionFactory with the given Hibernate Configuration.
     *
     * @param cfg
     */
    public void rebuildSessionFactory(Configuration cfg) throws HibernateUtilException {
        synchronized (sessionFactory) {
            try {
                sessionFactory = cfg.buildSessionFactory();
                configuration = cfg;
            } catch (Exception ex) {
                throw new HibernateUtilException(ex);
            }
        }
    }

    /**
     * Retrieves the current Session local to the thread.
     * <p/>
     * If no Session is open, opens a new Session for the running thread.
     *
     * @return Session
     */
    public Session getSession() throws HibernateUtilException {
        Session s = (Session) threadSession.get();
        try {
            if (s == null) {
                //log.debug("Opening new Session for this thread.");
                //System.err.println("Opening new Session for this thread.");
                if (getInterceptor() != null) {
                    //System.err.println("Using interceptor: " + getInterceptor().getClass());
                    s = getSessionFactory().openSession(getInterceptor());
                } else {
                    //System.err.println("Without interceptor");
                    s = getSessionFactory().openSession();
                }
                threadSession.set(s);
            }
        } catch (HibernateException ex) {
            throw new HibernateUtilException(ex);
        }
        return s;
    }

    /**
     * Closes the Session local to the thread.
     */
    public void closeSession() throws HibernateUtilException {
        try {
            Session s = (Session) threadSession.get();
            threadSession.set(null);
            // Added to correctly handle situations where persist() alone cause an exception and commitTransaction() or rollbackTransactions() doesn't occur
            // (for example where we have unique index constraints)
            if (threadTransaction.get() != null)
                rollbackTransaction();

            if (s != null && s.isOpen()) {
                //System.err.println("Closing Session of this thread.");
                s.close();
            }
        } catch (HibernateException ex) {
            throw new HibernateUtilException(ex);
        }
    }

    /**
     * Start a new database transaction.
     */
    public void beginTransaction() throws HibernateUtilException {
        Transaction tx = (Transaction) threadTransaction.get();
        try {
            if (tx == null) {
                //System.err.println("Starting new database transaction in this thread.");
                tx = getSession().beginTransaction();
                threadTransaction.set(tx);
            }
        } catch (HibernateException ex) {
            throw new HibernateUtilException(ex);
        }
    }

    /**
     * Commit the database transaction.
     */
    public void commitTransaction() throws HibernateUtilException {
        Transaction tx = (Transaction) threadTransaction.get();
        try {
            if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
                //System.err.println("Committing database transaction of this thread.");
                tx.commit();
            }
            threadTransaction.set(null);
        } catch (HibernateException ex) {
            rollbackTransaction();
            throw new HibernateUtilException(ex);
        }
    }

    /**
     * Commit the database transaction.
     */
    public void rollbackTransaction() throws HibernateUtilException {
        Transaction tx = (Transaction) threadTransaction.get();
        try {
            threadTransaction.set(null);
            if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
                //System.err.println("Tyring to rollback database transaction of this thread.");
                tx.rollback();
            }
        } catch (HibernateException ex) {
            throw new HibernateUtilException(ex);
        }
    }

    /**
     * Reconnects a Hibernate Session to the current Thread.
     *
     * @param session The Hibernate Session to be reconnected.
     */
    @SuppressWarnings("deprecation")
    public void reconnect(Session session) throws HibernateUtilException {
        try {
            session.reconnect();
            threadSession.set(session);
        } catch (HibernateException ex) {
            throw new HibernateUtilException(ex);
        }
    }

    /**
     * Disconnect and return Session from current Thread.
     *
     * @return Session the disconnected Session
     */
    public Session disconnectSession() throws HibernateUtilException {

        Session session = getSession();
        try {
            threadSession.set(null);
            if (session.isConnected() && session.isOpen())
                session.disconnect();
        } catch (HibernateException ex) {
            throw new HibernateUtilException(ex);
        }
        return session;
    }

    /**
     * Register a Hibernate interceptor with the current thread.
     * <p>
     * Every Session opened is opened with this interceptor after
     * registration. Has no effect if the current Session of the
     * thread is already open, effective on next close()/getSession().
     */
    public void registerInterceptor(Interceptor interceptor) {
        threadInterceptor.set(interceptor);
    }

    private Interceptor getInterceptor() {
        Interceptor interceptor = (Interceptor) threadInterceptor.get();
        return interceptor;
    }

    public List getList(Class type) throws HibernateUtilException {
        List result = null;
        try {
            beginTransaction();
            Session session = getSession();

            result = session.createCriteria(type).list();

            commitTransaction();
        } catch (Throwable thr) {
            throw new HibernateUtilException(thr);
        } finally {
            closeSession();
        }
        return result;
    }

}