/** * Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2006-2016 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.glite.security.voms.admin.persistence; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Enumeration; import java.util.Properties; import org.apache.commons.lang.Validate; import org.glite.security.voms.admin.error.VOMSFatalException; import org.glite.security.voms.admin.persistence.error.VOMSDatabaseException; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.cfg.Configuration; import org.hibernate.resource.transaction.spi.TransactionStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HibernateFactory { private static final Logger log = LoggerFactory .getLogger(HibernateFactory.class); private static SessionFactory sessionFactory; private static Metadata metadata; private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>(); private static final ThreadLocal<Transaction> threadTransaction = new ThreadLocal<Transaction>(); public static synchronized void initialize(MetadataSources metadataSources) { Validate.notNull(metadataSources); if (sessionFactory != null) { throw new VOMSDatabaseException( "Hibernate session factory already initialized!"); } try { metadata = metadataSources.buildMetadata(); sessionFactory = metadata.getSessionFactoryBuilder().build(); }catch (Throwable e) { log.error("Hibernate session factory creation failed!", e); throw new ExceptionInInitializerError(e); } } public static synchronized void initialize(Configuration configuration) { Validate.notNull(configuration); if (sessionFactory != null) { throw new VOMSDatabaseException( "Hibernate session factory already initialized!"); } try { sessionFactory = configuration.buildSessionFactory(); } catch (HibernateException e) { log.error("Hibernate session factory creation failed!", e); throw new ExceptionInInitializerError(e); } } public static synchronized void initialize(Properties databaseProperties) { Validate.notNull(databaseProperties); if (sessionFactory != null) { throw new VOMSDatabaseException( "Hibernate session factory already initialized!"); } try { Configuration hibernateConf = new Configuration(); hibernateConf.addProperties(databaseProperties); sessionFactory = hibernateConf.configure().buildSessionFactory(); } catch (HibernateException e) { log.error("Hibernate session factory creation failed!", e); throw new ExceptionInInitializerError(e); } } public static synchronized void shutdown() { if (sessionFactory != null){ sessionFactory.close(); } unregisterSQLDrivers(); cleanupThreadLocals(); } protected static void unregisterSQLDrivers() { Enumeration<Driver> drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); try { DriverManager.deregisterDriver(driver); } catch (SQLException e) { log.warn("Error deregistering driver {}", driver, e); } } } protected static void cleanupThreadLocals() { if (threadSession != null) { threadSession.remove(); } if (threadTransaction != null) { threadTransaction.remove(); } } public static Metadata getMetadata() { return metadata; } public static SessionFactory getFactory() { return sessionFactory; } public static Session getSession() { Session s = (Session) threadSession.get(); try { if (s == null) { s = sessionFactory.openSession(); threadSession.set(s); log.debug("Opened new session for thread {}. Session: {}", Thread.currentThread(), s); } } catch (HibernateException ex) { log.error("Error getting hibernate session!", ex); throw new VOMSFatalException(ex.getMessage(), ex); } return s; } public static void closeSession() { try { Session s = (Session) threadSession.get(); threadSession.set(null); if (s != null) { if (s.isOpen()){ log.debug("Closing session for thread {}", Thread.currentThread()); s.close(); } else { log.debug("Session is already closed for thread {}", Thread.currentThread()); } } else { log.debug("Attempted to close a null session for thread {}", Thread.currentThread()); } } catch (HibernateException ex) { log.error("Error closing hibernate session!", ex); throw new VOMSDatabaseException(ex.getMessage(), ex); } } public static void beginTransaction() { Transaction tx = (Transaction) threadTransaction.get(); try { if (tx == null) { tx = getSession().beginTransaction(); threadTransaction.set(tx); if (log.isDebugEnabled()){ log.debug("Started transation {} for thread {}. ", tx, Thread.currentThread()); } } } catch (HibernateException ex) { log.error("Error creating hibernate transaction!", ex); throw new VOMSDatabaseException(ex.getMessage(), ex); } } public static void commitTransaction() { Transaction tx = (Transaction) threadTransaction.get(); try { if (tx != null && !tx.getStatus().equals(TransactionStatus.COMMITTED) && !tx.getStatus().equals(TransactionStatus.ROLLING_BACK) && !tx.getStatus().equals(TransactionStatus.ROLLED_BACK)) { if (log.isDebugEnabled()){ log.debug("Committing transaction {} for thread {}", tx, Thread.currentThread()); } tx.commit(); } threadTransaction.set(null); } catch (HibernateException ex) { log.error("Error committing hibernate transaction:" + ex.getMessage()); rollbackTransaction(); if (log.isDebugEnabled()){ log.error("Error committing hibernate transaction!", ex); } throw new VOMSDatabaseException(ex.getMessage(), ex); } } public static void rollbackTransaction() { Transaction tx = (Transaction) threadTransaction.get(); TransactionStatus status = tx.getStatus(); log.warn("Rolling back transaction {}", tx); try { threadTransaction.set(null); if (tx != null && !tx.getStatus().equals(TransactionStatus.COMMITTED) && !tx.getStatus().equals(TransactionStatus.ROLLING_BACK) && !tx.getStatus().equals(TransactionStatus.ROLLED_BACK)){ if (log.isDebugEnabled()){ log.debug("Rolling back transaction {} for thread {}", tx, Thread.currentThread()); } tx.rollback(); } } catch (HibernateException ex) { log.error("Error rolling back hibernate transaction:" + ex.getMessage(),ex); throw new VOMSDatabaseException(ex.getMessage(), ex); } finally { closeSession(); } } }