package clusterj;

// Main.java

/*
 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

 CREATE SCHEMA IF NOT EXISTS `clusterj` DEFAULT CHARACTER SET latin1 COLLATE latin1_bin ;

 -- -----------------------------------------------------
 -- Table `clusterj`.`example`
 -- -----------------------------------------------------
 CREATE  TABLE IF NOT EXISTS `clusterj`.`example` (
 `number` BIGINT UNSIGNED NOT NULL ,
 PRIMARY KEY (`number`) ,
 UNIQUE INDEX `number_UNIQUE` USING HASH (`number` ASC) )
 ENGINE = ndbcluster;

 SET SQL_MODE=@OLD_SQL_MODE;
 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
 */

// Set java.library.path variable to point to the directory containing the Cluster ndbclient library.
// -Djava.library.path=C:\Work\Programming\MySQL\MySQL-Cluster\mysql-cluster-gpl-7.1.3-win32\lib

import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.mysql.clusterj.ClusterJHelper;
import com.mysql.clusterj.Session;
import com.mysql.clusterj.SessionFactory;

public class Main {

	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(2);
		// 1. Manager created in main thread,
		Manager manager = new Manager();
		
		//insert(1); // 2. Remove the comment to get this work.

		// 3. Inserting a row from different thread.
		pool.submit(new Insert(2));
	}

	private static void insert(long number) {
		Session session = Manager.getSessionFactory().getSession();
		IEntity entity = session.newInstance(IEntity.class);
		entity.setNumber(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:1186");
		properties.put("com.mysql.clusterj.database", "clusterj");
		sessionfactory = ClusterJHelper.getSessionFactory(properties);

		return;
	}

	public static SessionFactory getSessionFactory() {
		return sessionfactory;
	}
}

class Insert implements Runnable {

	SessionFactory sessionfactory;
	long number;

	Insert(long number) {
		this.number = number;
		return;
	}

	private void insert(long number) {
		Session session = Manager.getSessionFactory().getSession();
		IEntity entity = session.newInstance(IEntity.class); // Crash from here.
		entity.setNumber(number);
		session.currentTransaction().begin();
		session.persist(entity);
		session.currentTransaction().commit();
		return;
	}

	@Override
	public void run() {
		insert(this.number);
	}
}

