Java tutorial
/** * Copyright (c) 2009--2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package com.redhat.rhn.common.hibernate; import com.redhat.rhn.common.conf.Config; import com.redhat.rhn.common.conf.ConfigDefaults; import com.redhat.rhn.common.finder.FinderFactory; import org.apache.log4j.Logger; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.metadata.ClassMetadata; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.Set; /** * Manages the lifecycle of the Hibernate SessionFactory and associated * thread-scoped Hibernate sessions * @version $Rev$ */ class ConnectionManager { private static final Logger LOG = Logger.getLogger(ConnectionManager.class); private static final String[] PACKAGE_NAMES = { "com.redhat.rhn.domain", "com.redhat.rhn.taskomatic" }; private final List<Configurator> configurators = new LinkedList<Configurator>(); private SessionFactory sessionFactory; private final ThreadLocal<SessionInfo> SESSION_TLS = new ThreadLocal<SessionInfo>() { @Override public SessionInfo get() { SessionInfo result = super.get(); return result; } }; private final Set<String> packageNames = new HashSet<String>(Arrays.asList(PACKAGE_NAMES)); /** * enable possibility to load hbm.xml files from different path */ void setAdditionalPackageNames(String[] packageNamesIn) { for (String pn : packageNamesIn) { packageNames.add(pn); } } /** * Register a class with HibernateFactory, to give the registered class a * chance to modify the Hibernate configuration before creating the * SessionFactory. * @param c Configurator to override Hibernate configuration. */ public void addConfigurator(Configurator c) { // Yes, this is a race condition, but it will only ever happen at // startup, when we really shouldn't have multiple threads running, // so it isn't a real race condition. configurators.add(c); } public boolean isTransactionPending() { boolean retval = false; SessionInfo info = threadSessionInfo(); if (info != null) { retval = info.getTransaction() != null; } return retval; } public ClassMetadata getMetadata(Object target) { ClassMetadata retval = null; if (target != null) { if (target instanceof Class) { retval = sessionFactory.getClassMetadata((Class) target); } else { retval = sessionFactory.getClassMetadata(target.getClass()); } } return retval; } /** * Close the sessionFactory */ public synchronized void close() { try { sessionFactory.close(); } catch (HibernateException e) { LOG.debug("Could not close the SessionFactory", e); } finally { sessionFactory = null; } } public boolean isClosed() { return sessionFactory == null; } public boolean isInitialized() { return sessionFactory != null; } public synchronized void initialize() { if (isInitialized()) { return; } createSessionFactory(); } /** * Create a SessionFactory, loading the hbm.xml files from the specified * location. * @param packageNames Package name to be searched. */ private void createSessionFactory() { if (sessionFactory != null && !sessionFactory.isClosed()) { return; } List<String> hbms = new LinkedList<String>(); for (Iterator<String> iter = packageNames.iterator(); iter.hasNext();) { String pn = iter.next(); hbms.addAll(FinderFactory.getFinder(pn).find("hbm.xml")); if (LOG.isDebugEnabled()) { LOG.debug("Found: " + hbms); } } try { Configuration config = new Configuration(); /* * Let's ask the RHN Config for all properties that begin with * hibernate.* */ LOG.info("Adding hibernate properties to hibernate Configuration"); Properties hibProperties = Config.get().getNamespaceProperties("hibernate"); hibProperties.put("hibernate.connection.username", Config.get().getString(ConfigDefaults.DB_USER)); hibProperties.put("hibernate.connection.password", Config.get().getString(ConfigDefaults.DB_PASSWORD)); hibProperties.put("hibernate.connection.url", ConfigDefaults.get().getJdbcConnectionString()); config.addProperties(hibProperties); // Force the use of our txn factory if (config.getProperty(Environment.TRANSACTION_STRATEGY) != null) { throw new IllegalArgumentException("The property " + Environment.TRANSACTION_STRATEGY + " can not be set in a configuration file;" + " it is set to a fixed value by the code"); } for (Iterator<String> i = hbms.iterator(); i.hasNext();) { String hbmFile = i.next(); if (LOG.isDebugEnabled()) { LOG.debug("Adding resource " + hbmFile); } config.addResource(hbmFile); } if (configurators != null) { for (Iterator<Configurator> i = configurators.iterator(); i.hasNext();) { Configurator c = i.next(); c.addConfig(config); } } // add empty varchar warning interceptor EmptyVarcharInterceptor interceptor = new EmptyVarcharInterceptor(); interceptor.setAutoConvert(true); config.setInterceptor(interceptor); sessionFactory = config.buildSessionFactory(); } catch (HibernateException e) { LOG.error("FATAL ERROR creating HibernateFactory", e); } } private SessionInfo threadSessionInfo() { return SESSION_TLS.get(); } /** * Commit the transaction for the current session. This method or * {@link #rollbackTransaction}can only be called once per session. * * @throws HibernateException if the commit fails */ public void commitTransaction() throws HibernateException { SessionInfo info = threadSessionInfo(); if (info == null) { return; } if (info.getSession() == null) { // Session was never started return; } Transaction txn = info.getTransaction(); if (txn != null) { txn.commit(); info.setTransaction(null); } } /** * Roll the transaction for the current session back. This method or * {@link #commitTransaction}can only be called once per session. * * @throws HibernateException if the commit fails */ public void rollbackTransaction() throws HibernateException { SessionInfo info = threadSessionInfo(); if (info == null) { return; } if (info.getSession() == null) { return; } Transaction txn = info.getTransaction(); if (txn != null) { txn.rollback(); info.setTransaction(null); } } /** * Returns the Hibernate session stored in ThreadLocal storage. If not * present, creates a new one and stores it in ThreadLocal; creating the * session also begins a transaction implicitly. * * @return Session Session asked for */ public Session getSession() { if (!isInitialized()) { initialize(); } return getInternalSession(); } private Session getInternalSession() { SessionInfo info = threadSessionInfo(); if (info == null || info.getSession() == null) { try { if (LOG.isDebugEnabled()) { LOG.debug("YYY Opening Hibernate Session"); } info = new SessionInfo(sessionFactory.openSession()); // Automatically start a transaction info.setTransaction(info.getSession().beginTransaction()); } catch (HibernateException e) { throw new HibernateRuntimeException("couldn't open session", e); } SESSION_TLS.set(info); } return info.getSession(); } /** * Closes the Hibernate Session stored in ThreadLocal storage. */ public void closeSession() { SessionInfo info = threadSessionInfo(); if (info == null) { return; } Session session = info.getSession(); try { Transaction txn = info.getTransaction(); if (txn != null && !txn.wasCommitted() && !txn.wasRolledBack()) { try { txn.commit(); } catch (HibernateException e) { txn.rollback(); } } } catch (HibernateException e) { LOG.error(e); } finally { if (session != null) { try { if (session.isOpen()) { if (LOG.isDebugEnabled()) { LOG.debug("YYY Closing Hibernate Session"); } session.close(); } } catch (HibernateException e) { throw new HibernateRuntimeException("couldn't close session"); } finally { SESSION_TLS.set(null); } } else { SESSION_TLS.set(null); } } } }