package regression;

import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import junit.framework.TestCase;

import testsuite.clusterj.model.Employee;

import com.mysql.clusterj.ClusterJHelper;
import com.mysql.clusterj.Session;
import com.mysql.clusterj.SessionFactory;

public class Bug54619 extends TestCase {

    public void test() {
        main(null);
    }

    public static void main(String[] args) {

        /*
         * MySQL Cluster generic Linux and Windows 7.1.3
         * 
         * Session factory in a different thread than sessions crashes JVM.
         * 
         * If SessionFactory is initialized in a different thread than where
         * sessions are created, session.newInstance call will crash JVM. This
         * happens on Windows and Linux. In Windows the crash seems to be coming
         * from DomainFieldHandlerImpl and from line table.getColumn(columnName);.
         * 
         * Workaround is to insert a dummy row (most likely any db access works)
         * from same thread where the SessionFactory is created. After this the
         * session seem to be working from other thread.
         */
        ExecutorService pool = Executors.newFixedThreadPool(20);
        // 1. Manager created in main thread,
        Manager manager = new Manager();
        
        //insert(1); // 2. Remove the comment to get this to work.

        // 3. Inserting a row from different thread.
//      pool.submit(new Insert(2));
        for (int i = 0; i < 20; ++i) {
            pool.submit(new Insert(i));
        }
        // wait for all threads to complete
        pool.shutdown();
        try {
            pool.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            fail("Interrupted pool.awaitTermination");
        }
        pool.shutdownNow();
    }

    private static void insert(int number) {
        Session session = Manager.getSessionFactory().getSession();
        Employee entity = session.newInstance(Employee.class);
        entity.setId(number);
        session.currentTransaction().begin();
        session.persist(entity);
        session.currentTransaction().commit();

        return;
    }

}

class Manager {

    static SessionFactory sessionfactory;

    Manager() {
        createClusterJSession();
        return;
    }

    private void createClusterJSession() {
        Properties properties = new Properties();
        properties.put("com.mysql.clusterj.connectstring", "localhost:9311");
        properties.put("com.mysql.clusterj.database", "test");
        sessionfactory = ClusterJHelper.getSessionFactory(properties);

        return;
    }

    public static SessionFactory getSessionFactory() {
        return sessionfactory;
    }
}

class Insert implements Runnable {

    SessionFactory sessionfactory;
    int number;

    Insert(int number) {
        this.number = number;
        return;
    }

    private void insert(int number) {
        Session session = Manager.getSessionFactory().getSession();
        Employee entity = session.newInstance(Employee.class); // Crash from here.
        entity.setId(number);
        session.currentTransaction().begin();
        session.persist(entity);
        session.currentTransaction().commit();
        return;
    }

    public void run() {
        insert(this.number);
    }
}


