/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.transaction;

import junit.framework.TestCase;
import org.jboss.cache.TreeCache;
import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
import org.jboss.cache.misc.TestingUtil;

import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

/**
 * Tests cleaning of invocation contexts on completion of txs
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 */
public class InvocationContextCleanupTest extends TestCase
{
    private TreeCache[] caches;

    private TreeCache createCache(boolean optimistic) throws Exception
    {
        TreeCache cache = new TreeCache();
        cache.setCacheMode(TreeCache.REPL_SYNC);
        if (optimistic) cache.setNodeLockingScheme("OPTIMISTIC");
        cache.setClusterName("InvocationContextCleanupTest");
        cache.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
        cache.setLockAcquisitionTimeout(2000);
        cache.startService();
        return cache;
    }

    protected void tearDown()
    {
        if (caches != null)
        {
            for (int i=0; i<caches.length; i++)
            {
                if (caches[i] != null)
                {
                    caches[i].stopService();
                    caches[i] = null;
                }
            }
            caches = null;
        }
    }

    public void testInvocationContextCleanupPessimistic() throws Exception
    {
        test2CachesSync(false);
    }

    private void test2CachesSync(boolean optimistic) throws Exception
    {
        caches = new TreeCache[2];
        caches[0] = createCache(optimistic);
        caches[1] = createCache(optimistic);

        TestingUtil.blockUntilViewsReceived(caches, 2000);

        TransactionManager mgr = caches[0].getTransactionManager();

        mgr.begin();

        OrderedSynchronizationHandler orderedHandler = OrderedSynchronizationHandler.getInstance(mgr.getTransaction());
        orderedHandler.registerAtTail(new DummySynchronization(caches[0], mgr));

        caches[0].put("/test", "x", "y");
        try
        {
            mgr.commit();
        }
        finally
        {
        }

        System.out.println(caches[0].printLockInfo());
        System.out.println(caches[1].printLockInfo());
        assertEquals("y", caches[0].get("/test", "x"));
        assertEquals("y", caches[1].get("/test", "x"));
    }

    public static class DummySynchronization implements Synchronization
    {
        private TreeCache cache;
        private TransactionManager mgr;

        public DummySynchronization(TreeCache cache, TransactionManager mgr)
        {
            this.cache = cache;
            this.mgr = mgr;
        }

        public void beforeCompletion()
        {
            // before returning, do a put (non-tx) on the cache!!
            Transaction tx = null;
            try
            {
                tx = mgr.suspend();
            }
            catch (SystemException e)
            {
                throw new RuntimeException("Unable to sustend transaction! " + e.getMessage() );
            }

            try
            {
                cache.put("/test", "blah", "blahblah");
                assertTrue("Should fail with a lock exception!", false);
            }
            catch (Exception e)
            {
                assertTrue("Should fail!", true);
            }
            finally
            {
                if (tx != null) try
                {
                    mgr.resume(tx);
                }
                catch (Exception e)
                {
                }
            }
        }

        public void afterCompletion(int i)
        {
            // do nothing
        }
    }
}
