package util;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;

/**
 * スレッドローカルなセッション管理クラス
 */
public class SessionManager {
    /**
     * シングルトンのセッションファクトリ
     */
    private static final SessionFactory sessionFactory;
    static{
        try{
            sessionFactory = new Configuration().configure().buildSessionFactory();
        }catch(Throwable e){
            e.printStackTrace();
            throw new ExceptionInInitializerError(e);
        }
    }

    /**
     * スレッドローカルな現在のセッション
     */
    private static final ThreadLocal currentSession = new ThreadLocal();
    /**
     * スレッドローカルな現在のトランザクション
     */
    private static final ThreadLocal currentTransaction = new ThreadLocal();

    /**
     * 現在のスレッドに対応するセッションを取得する
     * @return Session
     * @throws HibernateException
     */
    public static Session getCurrentSession() throws HibernateException{
        Session session = (Session) currentSession.get();
        if( session == null ){
            session = sessionFactory.openSession();
            currentSession.set(session);
        }
        return session;
    }

    /**
     * セッションを閉じる
     * @throws HibernateException
     */
    public static void closeSession() throws HibernateException{
        //トランザクションが終了してない場合は、ロールバックを行う
        rollback();
        
        Session session = (Session) currentSession.get();
        if( session != null ){
            currentSession.set(null);
            session.close();
        }
    }
    
    /**
     * トランザクションを開始する
     * @throws HibernateException
     */
    public static void beginTransaction() throws HibernateException{
        Transaction transaction = (Transaction) currentTransaction.get();
        if( transaction == null ){
            Session session = getCurrentSession();
            transaction = session.beginTransaction();
            currentTransaction.set(transaction);
        }
    }
    
    /**
     * トランザクションをコミットする
     * @throws HibernateException
     */
    public static void commit() throws HibernateException{
        Transaction transaction = (Transaction) currentTransaction.get();
        if( transaction != null ){
            currentTransaction.set(null);
            transaction.commit();
        }
    }
    
    /**
     * トランザクションをロールバックする
     * @throws HibernateException
     */
    public static void rollback() throws HibernateException{
        Transaction transaction = (Transaction) currentTransaction.get();
        if( transaction != null ){
            currentTransaction.set(null);
            transaction.rollback();
        }
    }

}