package org.jboss.cache.aop;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.transaction.DummyTransactionManager;
import org.jboss.cache.misc.TestingUtil;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.*;
import java.util.Properties;

//import org.jboss.test.JBossTestCase;


/**
 * LocalTestCase.java that uses standalone aop package.
 * <p/>
 * <p/>
 * Created: Mon May 05 17:30:11 2003
 */

public class ReplicatedTxAopTest extends TestCase
{
//   Category log = getLog();
   Log log=LogFactory.getLog(ReplicatedTxAopTest.class);
   TreeCacheAopTester tester, tester1;
   final String FACTORY = "org.jboss.cache.transaction.DummyContextFactory";
   DummyTransactionManager tx_mgr;
   Throwable t1_ex, t2_ex;
   long start=0;


   public ReplicatedTxAopTest(String name)
   {
      super(name);
   }

   protected void setUp() throws Exception
   {
      super.setUp();
      log.info("setUp() ....");
      String configFile = "META-INF/replSync-service.xml";
      tester = new TreeCacheAopTester(configFile);
      tester1 = new TreeCacheAopTester(configFile);

      System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FACTORY);

      tx_mgr = DummyTransactionManager.getInstance();
      t1_ex = t2_ex = null;
   }

   protected void tearDown() throws Exception
   {
      super.tearDown();
      tester.stop();
      tester1.stop();
      tester = null;
      tester1 = null;

      DummyTransactionManager.destroy();
   }

//   public void testDummy() {}

   public void testSetup()
   {
      log.info("testSetup() ....");
      try {
         tester.testSetup();
         tester1.testSetup();
      } catch (Exception ex) {
         ex.printStackTrace();
         fail("testSetup(): fails. " + ex.toString());
      }
   }

   UserTransaction getTransaction() throws SystemException, NotSupportedException, NamingException
   {
      Properties prop = new Properties();
      prop.put(Context.INITIAL_CONTEXT_FACTORY,
          "org.jboss.cache.transaction.DummyContextFactory");
      return (UserTransaction)new InitialContext(prop).lookup("UserTransaction");
   }

   public void testSimple() throws Exception
   {
      log.info("testSimple() ....");
      UserTransaction tx = getTransaction();
      tx.begin();
      tester.createPerson("/person/test1", "Harald Gliebe", 32);
      tx.commit();
      tx.begin();
      tester.setName("/person/test1", "Benoit");
      tx.commit();
      assertEquals((Object) "Benoit", (Object) tester.getName("/person/test1"));
      assertEquals((Object) "Benoit", (Object) tester1.getName("/person/test1"));
      tx.begin();
      tester.setAge("/person/test1", 61);
      tx.commit();
      assertEquals(61, tester.getAge("/person/test1"));
      assertEquals(61, tester1.getAge("/person/test1"));
   }

   public void testModification() throws Exception
   {
      UserTransaction tx = getTransaction();
      tx.begin();
      tester.createPerson("/person/test2", "Harald", 32);
      tester.setName("/person/test2", "Harald Gliebe");
      tx.commit();
      tx.begin();
      tester1.setName("/person/test2", "Benoit");
      tx.commit();
      assertEquals((Object) tester.getName("/person/test2"), (Object) "Benoit");
      assertEquals((Object) tester1.getName("/person/test2"), (Object) "Benoit");
      tx.begin();
      tester1.setName("/person/test2", "Harald");
      tx.rollback();
      assertEquals((Object) tester.getName("/person/test2"), (Object) "Benoit");
      assertEquals((Object) tester1.getName("/person/test2"), (Object) "Benoit");
      tester.removePerson("/person/test2");
   }



   public void testConcurrentPuts() throws Exception
   {
      tester.setSyncCommitPhase(true);

      Thread t1 = new Thread()
      {
         Transaction tx;

         public void run()
         {
            try {
               tester.createPerson("/person/test6", "p6", 50);
               UserTransaction tx = getTransaction();
               tx.begin();
               tester.addLanguage("/person/test6", "German");
               TestingUtil.sleepThread(4000);
               tx.commit();
            }
            catch(RollbackException rollback) {
               ;
            }
            catch (Exception ex) {
               t1_ex = ex;
            }
         }
      };

      Thread t2 = new Thread()
      {
         Transaction tx;

         public void run()
         {
            try {
               TestingUtil.sleepThread(1000); // give Thread1 time to createPerson
               UserTransaction tx = getTransaction();
               tx.begin();
               tester.addLanguage("/person/test6", "English");
               tx.commit();
            }
            catch(RollbackException rollback) {
               ;
            }
            catch (Exception ex) {
               t2_ex = ex;
            }
         }
      };

      t1.start();
      t2.start();

      t1.join();
      t2.join();

      // t2 should rollback due to timeout while t2 should succeed
      if(t2_ex != null)
         fail("Thread1 failed: " + t2_ex);
      if(t1_ex != null)
         fail("Thread2 failed: " + t1_ex);

      int size = tester.getLanguagesSize("/person/test6");
      assertEquals("number of languages should be 2, but is " + size + " (" +
                   tester.getLanguages("/person/test6") + ")",
                   2, size);
      System.out.println("tester: " + tester.getLanguages("/person/test6"));
      size = tester1.getLanguagesSize("/person/test6");
      assertEquals("number of languages should be 2, but is " + size + " (" +
                   tester.getLanguages("/person/test6") + ")",
                   2, size);
      System.out.println("tester1: " + tester1.getLanguages("/person/test6"));
   }

   void log(String s) {
      long now;
      if(start == 0)
         start=System.currentTimeMillis();
      now=System.currentTimeMillis();

      System.out.println("[" + Thread.currentThread().getName() + "] [" + (now - start) + "] " + s);
    }


   public static Test suite() throws Exception
   {
      return new TestSuite(ReplicatedTxAopTest.class);
   }


   public static void main(String[] args) throws Exception
   {
      junit.textui.TestRunner.run(suite());
   }

}

