/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.jfox.tm.test;

import java.sql.Connection;
import java.sql.Statement;
import javax.transaction.TransactionManager;
import javax.transaction.RollbackException;
import javax.transaction.Transaction;
import javax.sql.XAConnection;

import com.mysql.jdbc.jdbc2.optional.MysqlXaDataSource;
import junit.framework.TestCase;
import org.jfox.tm.TxManager;

/**
 * 
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class TxTest extends TestCase {
  private MysqlXaDataSource mysqlDS = null;
  private TransactionManager tm = null;
  private XAConnection xaconn = null;

  protected void setUp() throws Exception {
    mysqlDS = new MysqlXaDataSource();
    mysqlDS.setURL("jdbc:mysql://localhost/test");
    mysqlDS.setUser("root");
    mysqlDS.setPassword("");
    xaconn = mysqlDS.getXAConnection();
    tm = TxManager.getInstance();
  }

  protected void tearDown() throws Exception {
    super.tearDown();
  }

  public void testSimpleCommit(){
    try {
      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      Connection conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"hello :)\"");
      tm.commit();

    }
    catch(Exception e){
      e.printStackTrace();
      fail(e.getMessage());
    }
  }

  public void testSimpleRollback(){
    try {
      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      Connection conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"" + getName() + " :(\"");
      tm.rollback();
    }
    catch(Exception e){
      fail(e.getMessage());
    }
  }

  public void testTMJoin(){
    try {
      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      Connection conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"" + getName() + "\"");

      XAConnection xaconn2 = mysqlDS.getXAConnection();
      // will join to current tx
      boolean b = tm.getTransaction().enlistResource(xaconn2.getXAResource());
      System.out.println(b);
      Connection conn2 = xaconn2.getConnection();
      Statement stm2 = conn2.createStatement();
      stm2.executeUpdate("insert into user set name=\"" + getName() +  " TMJOIN \"");

      tm.commit();
    }
    catch(Exception e){
      fail(e.getMessage());
    }
  }


  public void testRollbackOnly(){
    Connection conn = null;
    try {
      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"hello :)\"");
      tm.setRollbackOnly();
      tm.commit();
    }
    catch(RollbackException e){
      // 我们期望的例外
      e.printStackTrace();
    }
    catch(Exception e){
      fail(e.getMessage());
    }
  }

  public void testTwoPhaseCommit() {
    try {
      MysqlXaDataSource mysqlDS2 = new MysqlXaDataSource();
      mysqlDS2.setURL("jdbc:mysql://localhost/yang");
      mysqlDS2.setUser("root");
      mysqlDS2.setPassword("");
      XAConnection xaconn2 = mysqlDS2.getXAConnection();

      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      tm.getTransaction().enlistResource(xaconn2.getXAResource());

      Connection conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"" + getName() + "\"");

      Connection conn2 = xaconn2.getConnection();
      Statement stm2 = conn2.createStatement();
      stm2.executeUpdate("insert into yang set name=\"" + getName() + "\"");

      tm.commit();
    }
    catch(Exception e){
      fail(e.getMessage());
    }
  }

  public void testSimpleSupendResume(){
    try {
      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      Connection conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"" + getName() + "\"");

      Transaction oldTrans = tm.suspend();

      tm.resume(oldTrans);
      tm.commit();


    }
    catch(Exception e){
      fail(e.getMessage());
    }
  }

  public void testSupendResumeWithSameResource(){
    try {
      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      Connection conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"" + getName() + "\"");

      Transaction oldTrans = tm.suspend();

      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      Connection conn2 = xaconn.getConnection();
      Statement stm2 = conn2.createStatement();
      stm2.executeUpdate("insert into user set name=\"" + getName() + "\"");
      tm.commit();

      tm.resume(oldTrans);
      tm.commit();


    }
    catch(Exception e){
      fail(e.getMessage());
    }
  }

  public void testSupendResumeWithDifferentResource(){
    try {
      tm.begin();
      tm.getTransaction().enlistResource(xaconn.getXAResource());
      Connection conn = xaconn.getConnection();
      Statement stm = conn.createStatement();
      stm.executeUpdate("insert into user set name=\"" + getName() + "\"");

      Transaction oldTrans = tm.suspend();

      tm.begin();
      MysqlXaDataSource mysqlDS2 = new MysqlXaDataSource();
      mysqlDS2.setURL("jdbc:mysql://localhost/yang");
      mysqlDS2.setUser("root");
      mysqlDS2.setPassword("");
      XAConnection xaconn2 = mysqlDS2.getXAConnection();
      tm.getTransaction().enlistResource(xaconn2.getXAResource());
      Connection conn2 = xaconn2.getConnection();
      Statement stm2 = conn2.createStatement();
      stm2.executeUpdate("insert into yang set name=\"" + getName() + "\"");
      tm.commit();

      tm.resume(oldTrans);
      tm.commit();

    }
    catch(Exception e){
      fail(e.getMessage());
    }
  }

  public void testMultiThread() {

    try {
      Thread[] threads = new Thread[80];
      Thread t = null;
      for(int i=0; i<threads.length ;i++){
        t = new TxThread(i + "");
        threads[i] = t;
        t.start();
      }

      for(int i=0; i<threads.length ;i++){
        threads[i].join();
      }

    }
    catch(Exception e){
      e.printStackTrace();
    }

  }

  class TxThread extends Thread {
    public TxThread(String name) {
      super(name);
    }

    public void run() {
      try {
        System.out.println("Thread " + this.getName() + " start");
        tm.begin();
        xaconn = mysqlDS.getXAConnection();
        tm.getTransaction().enlistResource(xaconn.getXAResource());
        Connection conn = xaconn.getConnection();
        Statement stm = conn.createStatement();
        stm.executeUpdate("insert into user set name=\"" + TxTest.this.getName() + " " + this.getName() + "\"");
        tm.commit();
      }
      catch(Exception e){
        e.printStackTrace();
        fail(e.getMessage());
      }
    }
  }
}