package org.hibernate.tutorial.util;import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;public class HibernateUtil {private static final SessionFactory sessionFactory;static {try {// Create the SessionFactory from hibernate.cfg.xmlsessionFactory = new Configuration().configure().buildSessionFactory();} catch (Throwable ex) {// Make sure you log the exception, as it might be swallowedSystem.err.println("Initial SessionFactory creation failed." + ex);throw new ExceptionInInitializerError(ex);}}public static SessionFactory getSessionFactory() {return sessionFactory;}}
private Long createAndStoreEvent(String title, Date theDate) {Session session = HibernateUtil.getSessionFactory().getCurrentSession();session.beginTransaction();Event theEvent = new Event();theEvent.setTitle(title);theEvent.setDate(theDate);session.save(theEvent);session.getTransaction().commit();return theEvent.getId();}
public final Session currentSession() throws HibernateException {Session current = existingSession( factory );if (current == null) {current = buildOrObtainSession();// register a cleanup synchcurrent.getTransaction().registerSynchronization( buildCleanupSynch() );// wrap the session in the transaction-protection proxyif ( needsWrapping( current ) ) {current = wrap( current );//Warp Here????}// then bind itdoBind( current, factory );}return current;}
/*** {@inheritDoc}*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// If close() is called, guarantee unbind()if ( "close".equals( method.getName()) ) {unbind( realSession.getSessionFactory() );}else if ( "toString".equals( method.getName() )|| "equals".equals( method.getName() )|| "hashCode".equals( method.getName() )|| "getStatistics".equals( method.getName() )|| "isOpen".equals( method.getName() ) ) {// allow these to go through the the real session no matter what}else if ( !realSession.isOpen() ) {// essentially, if the real session is closed allow any// method call to pass through since the real session// will complain by throwing an appropriate exception;// NOTE that allowing close() above has the same basic effect,// but we capture that there simply to perform the unbind...}else if ( !realSession.getTransaction().isActive() ) {// limit the methods available if no transaction is activeif ( "beginTransaction".equals( method.getName() )|| "getTransaction".equals( method.getName() )|| "isTransactionInProgress".equals( method.getName() )|| "setFlushMode".equals( method.getName() )|| "getSessionFactory".equals( method.getName() ) ) {log.trace( "allowing method [" + method.getName() + "] in non-transacted context" );}else if ( "reconnect".equals( method.getName() )|| "disconnect".equals( method.getName() ) ) {// allow these (deprecated) methods to pass through}else {throw new HibernateException( method.getName() + " is not valid without active transaction" );}}log.trace( "allowing proxied method [" + method.getName() + "] to proceed to real session" );return method.invoke( realSession, args );}catch ( InvocationTargetException e ) {if ( e.getTargetException() instanceof RuntimeException ) {throw ( RuntimeException ) e.getTargetException();}else {throw e;}}}
A CurrentSessionContext impl which scopes the notion of current session by the current thread of execution. Unlike the JTA counterpart, threads do not give us a nice hook to perform any type of cleanup making it questionable for this impl to actually generate Session instances. In the interest of usability, it was decided to have this default impl actually generate a session upon first request and then clean it up after the org.hibernate.Transaction associated with that session is committed/rolled-back. In order for ensuring that happens, the sessions generated here are unusable until after Session.beginTransaction() has been called. If close() is called on a session managed by this class, it will be automatically unbound.
Additionally, the static bind and unbind methods are provided to allow application code to explicitly control opening and closing of these sessions. This, with some from of interception, is the preferred approach. It also allows easy framework integration and one possible approach for implementing long-sessions.
The buildOrObtainSession, isAutoCloseEnabled, isAutoFlushEnabled, getConnectionReleaseMode, and buildCleanupSynch methods are all provided to allow easy subclassing (for long-running session scenarios, for example).