/*
 * Created on 17-Feb-2005
 *
 *
 *
 */
package org.jboss.cache.optimistic;

import junit.framework.Test;
import junit.framework.TestSuite;
import org.jboss.cache.Fqn;
import org.jboss.cache.OptimisticTransactionEntry;
import org.jboss.cache.TreeCache;
import org.jboss.cache.misc.TestingUtil;
import org.jboss.cache.interceptors.Interceptor;
import org.jboss.cache.interceptors.OptimisticCreateIfNotExistsInterceptor;
import org.jboss.cache.loader.SamplePojo;
import org.jboss.cache.transaction.DummyTransactionManager;

import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

/**
 * @author xenephon
 */
public class ThreadedOptimisticCreateIfNotExistsInterceptorTest extends AbstractOptimisticTestCase
{

    /**
     * @param name
     */
    public ThreadedOptimisticCreateIfNotExistsInterceptorTest(String name)
    {
        super(name);

    }

    protected void setTransactionsInInvocationCtx(TransactionManager mgr, TreeCache cache) throws Exception
    {
        cache.getInvocationContext().setTransaction(mgr.getTransaction());
        cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction());
    }

    protected void resetInvocationCtx(TreeCache cache)
    {
        cache.getInvocationContext().setTransaction(null);
        cache.getInvocationContext().setGlobalTransaction(null);
    }

    public void testDifferentTransactions() throws Exception
    {

        int numThreads = 100;
        final int minSleep = 0;
        final int maxSleep = 1000;
        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor dummy = new MockInterceptor();
        dummy.setCache(cache);
        interceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

        Runnable run = new Runnable()
        {

            public void run()
            {
                try
                {
                    //start a new transaction in this thread
                    DummyTransactionManager mgr = DummyTransactionManager.getInstance();
                    mgr.begin();
                    setTransactionsInInvocationCtx(mgr, cache);
                    SamplePojo pojo = new SamplePojo(21, "test");

                    cache.put("/one", "key1", pojo);

                    randomSleep(minSleep, maxSleep);

                    cache.put("/one/two", "key2", pojo);

                    OptimisticTransactionEntry entry = (OptimisticTransactionEntry) cache.getTransactionTable().get(cache.getCurrentTransaction());
                    assertEquals(3, entry.getTransactionWorkSpace().getNodes().size());
                    assertTrue(entry.getTransactionWorkSpace().getNode(Fqn.fromString("/")) != null);
                    assertTrue(entry.getTransactionWorkSpace().getNode(Fqn.fromString("/one")) != null);
                    assertTrue(entry.getTransactionWorkSpace().getNode(Fqn.fromString("/one/two")) != null);
                    mgr.commit();
                    resetInvocationCtx(cache);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        };
        Thread[] threads = new Thread[numThreads];
        for (int i = 0; i < numThreads; i++)
        {
            Thread t = new Thread(run);
            t.start();
            threads[i] = t;
        }
        for (int i = 0; i < numThreads; i++)
        {
            threads[i].join();
        }

        assertEquals((2 * numThreads), listener.getNodesAdded());
        cache.stopService();
    }

    public void testDifferentThreadsSameTransaction() throws Exception
    {
        int numThreads = 100;
        final int minSleep = 0;
        final int maxSleep = 500;
        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

        Interceptor interceptor = new OptimisticCreateIfNotExistsInterceptor();
        interceptor.setCache(cache);
        Interceptor dummy = new MockInterceptor();
        dummy.setCache(cache);
        interceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

        final DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        mgr.begin();
        final Transaction tx = mgr.getTransaction();

        Runnable run = new Runnable()
        {

            public void run()
            {
                try
                {
                    //start a new transaction in this thread

                    mgr.setTransaction(tx);
                    SamplePojo pojo = new SamplePojo(21, "test");

                    setTransactionsInInvocationCtx(mgr, cache);
                    cache.put("/one", "key1", pojo);
                    OptimisticTransactionEntry entry = (OptimisticTransactionEntry) cache.getTransactionTable().get(cache.getCurrentTransaction());

                    randomSleep(minSleep, maxSleep);

                    cache.put("/one/two", "key2", pojo);
                    assertEquals(3, entry.getTransactionWorkSpace().getNodes().size());
                    assertTrue(entry.getTransactionWorkSpace().getNode(Fqn.fromString("/")) != null);
                    assertTrue(entry.getTransactionWorkSpace().getNode(Fqn.fromString("/one")) != null);
                    assertTrue(entry.getTransactionWorkSpace().getNode(Fqn.fromString("/one/two")) != null);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
                finally
                {
                    resetInvocationCtx(cache);
                }
            }
        };
        Thread[] threads = new Thread[numThreads];
        for (int i = 0; i < numThreads; i++)
        {
            Thread t = new Thread(run);
            t.start();
            threads[i] = t;
        }
        for (int i = 0; i < numThreads; i++)
        {
            threads[i].join();
        }
        mgr.commit();

        TestingUtil.sleepThread((long)4000);

        assertEquals(2, listener.getNodesAdded());
        cache.stopService();
    }

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

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