package org.jboss.cache.transaction;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jboss.cache.CacheException;
import org.jboss.cache.TransactionTable;
import org.jboss.cache.TreeCache;

import javax.transaction.NotSupportedException;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;

/**
 * Created by IntelliJ IDEA.
 * User: bela
 * Date: Jun 9, 2004
 * Time: 9:05:19 AM
 */
public class PrepareTxTest extends TestCase {
   TreeCache cache;

   protected void setUp() throws Exception {
      super.setUp();
      cache=new TreeCache();
      cache.setCacheMode("local");
      cache.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
      cache.createService();
      cache.startService();
   }

   protected void tearDown() throws Exception {
      super.tearDown();
      Transaction t = cache.getTransactionManager().getTransaction();
      try
      {
         if ( t != null ) t.rollback();
      }
      catch (Exception e)
      {
      }
      cache.stopService();
      cache.destroyService();
   }




   /** Tests cache modification <em>inside</em> the afterCompletion() callback. Reproduces a bug fixed in
    * connection with JBossCache being used as Hibernate's second level cache 
    * @throws Exception
    * @throws NotSupportedException
    */
   public void testCacheModificationInBeforeCompletionPhase() throws Exception, NotSupportedException {
      int numLocks=0;
      DummyTransactionManager mgr=DummyTransactionManager.getInstance();
      mgr.begin();
      Transaction tx=mgr.getTransaction();

      // this will cause the cache to register with TransactionManager for TX completion callbacks
      cache.put("/one/two/three", "key1", "val1");
      System.out.println("before commit:\n" + cache.printLockInfo());
      numLocks=cache.getNumberOfLocksHeld();
      assertEquals(4, numLocks);

      // we register *second*
      tx.registerSynchronization(new Synchronization() {

         public void beforeCompletion() {
            try {
               cache.put("/a/b/c", null);
               System.out.println("before commit:\n" + cache.printLockInfo());
            }
            catch(CacheException e) {
               e.printStackTrace();
            }
         }

         public void afterCompletion(int status) {
         }
      });

      tx.commit();
      System.out.println("after commit:\n" + cache.printLockInfo());
      numLocks=cache.getNumberOfLocksHeld();
      assertEquals(0, numLocks);

      int num_local_txs, num_global_txs;
      TransactionTable tx_table=cache.getTransactionTable();
      num_local_txs=tx_table.getNumLocalTransactions();
      num_global_txs=tx_table.getNumGlobalTransactions();
      System.out.println("Number of Transactions: " + num_local_txs + "\nNumber of GlobalTransactions: " +
                         num_global_txs + "\nTransactionTable:\n " + tx_table.toString(true));
      assertEquals(num_local_txs, num_global_txs);
      assertEquals(0, num_local_txs);
   }



   /** Tests cache modification <em>inside</em> the afterCompletion() callback. Reproduces a bug fixed in
     * connection with JBossCache being used as Hibernate's second level cache
     * @throws Exception
     * @throws NotSupportedException
     */
    public void testCacheModificationInAfterCompletionPhase() throws Exception, NotSupportedException {
       int numLocks=0;
       DummyTransactionManager mgr=DummyTransactionManager.getInstance();
       mgr.begin();
       Transaction tx=mgr.getTransaction();

       // this will cause the cache to register with TransactionManager for TX completion callbacks
       cache.put("/one/two/three", "key1", "val1");
       System.out.println("before commit:\n" + cache.printLockInfo());
       numLocks=cache.getNumberOfLocksHeld();
       assertEquals(4, numLocks);

       // we register *second*
       tx.registerSynchronization(new Synchronization() {

          public void beforeCompletion() {
          }

          public void afterCompletion(int status) {
             try {
                cache.put("/a/b/c", null);
                System.out.println("before commit:\n" + cache.printLockInfo());
             }
             catch(CacheException e) {
                e.printStackTrace();
             }
          }
       });

       tx.commit();
       System.out.println("after commit:\n" + cache.printLockInfo());
       numLocks=cache.getNumberOfLocksHeld();
       assertEquals(0, numLocks);

       int num_local_txs, num_global_txs;
       TransactionTable tx_table=cache.getTransactionTable();
       num_local_txs=tx_table.getNumLocalTransactions();
       num_global_txs=tx_table.getNumGlobalTransactions();
       System.out.println("Number of Transactions: " + num_local_txs + "\nNumber of GlobalTransactions: " +
                          num_global_txs + "\nTransactionTable:\n " + tx_table.toString(true));
       assertEquals(num_local_txs, num_global_txs);
       assertEquals(0, num_local_txs);
    }



   public static Test suite() {
      return new TestSuite(PrepareTxTest.class);
   }

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

}
