/*
 * Created on 2005.05.15.
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.etixpert.evolution;

import org.hibernate.*;
import org.hibernate.cfg.*;
import org.apache.log4j.*;
import java.io.*;
import java.util.ResourceBundle;
import java.sql.*;
import java.util.*;

public class HibernateUtil {

    private static Logger log = Logger.getLogger("mainControl.hibernate");

    private static final SessionFactory sessionFactory;
    private static  Configuration conf;

    static {
        try {
            // Create the SessionFactory
            ResourceBundle bundle = ResourceBundle.getBundle("evolution" );
  
            
            conf=new Configuration().configure(new File(bundle.getString("hibernateconfig")));
            //conf=new Configuration().configure(new File("c:/work/evolution/web/WEB-INF/hibernate.test.cfg.xml "));
           /* Enumeration e = bundle.getKeys();
            while (e.hasMoreElements()) {
            	String s = (String) e.nextElement();
            	
            	if (s.toLowerCase().startsWith("hibernate.connection")) {
            		//log.info("Replacing info "+s +"("+conf.getProperty(s)+") to "+bundle.getString(s));
            		conf = conf.setProperty(s, bundle.getString(s));
            	}
            } */
            sessionFactory = conf.buildSessionFactory();
            
        	//sessionFactory = new Configuration().configure(new File("/usr/share/tomcat5/webapps/evolution/WEB-INF/hibernate.cfg.xml")).buildSessionFactory();

        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            log.error("Initial SessionFactory creation failed.", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static final ThreadLocal session = new ThreadLocal();

    public synchronized static Session currentSession() {
        log.debug("Getting hibernate session");
    	Session s = (Session) session.get();
        // Open a new Session, if this Thread has none yet
        if (s == null) {
            s = sessionFactory.openSession();
            session.set(s);
            
        }
        return reviveSession(s);
    }

    public static Session reviveSession(Session s) {
       
        boolean ok = true;
        Transaction tx = null;
        for (int i=0; i<3; i++) {
           try {
               tx = s.beginTransaction();
               Connection c = s.connection();
               Statement stat = c.createStatement();
               ResultSet rs = stat.executeQuery("select 1+1");
               rs.next();
               rs.close();
               stat.close();
               ok = true;
               if (i>0) log.info("Session revived successfully");
               return s;
           } catch (SQLException e) {
               log.error("SQLException while trying to executing test select (Code "+e.getSQLState()+"): "+e.getMessage());
              
               if (tx!=null) try {tx.rollback();} catch(Exception e1) {log.error("Cannot rolling back: "+e1.getMessage());}
               
               if (e.getSQLState().equalsIgnoreCase("57P01") ||
                       e.getSQLState().equalsIgnoreCase("08006")) {
                   
                   
                 if (s.isConnected()) { 
                   s.disconnect();
                   
                 }
                 String connectionURL= conf.getProperty("connection.url");
                 log.info("Trying to revive session. Trying to reconnect to URL "+connectionURL);
                 log.info("isConnected: "+s.isConnected());
   
                 Connection conn = null;
                 try {
                     conn = DriverManager.getConnection(connectionURL, conf.getProperty("connection.username"), conf.getProperty("connection.password"));
                 } catch (Exception e1) {
                     log.error("Error on creating new connection: "+e.getMessage());
                 }
                 
                 
                 if (conn!=null) s.reconnect(conn);
                 else {
                     log.warn("reconnection on the old connection connection object");
                     s.reconnect();
                 }
                 log.info("reconnected");
                   
               } else
                   return s;
              
               
           }
            
        }
        
        return s;
    }
    
    public synchronized static void closeSession() {
        log.debug("Closing hibernate session");
    	Session s = (Session) session.get();
        if (s != null)
            s.close();
        session.set(null);
    }
}