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

import org.jboss.cache.*;
import org.jboss.cache.interceptors.Interceptor;
import org.jboss.cache.interceptors.OptimisticCreateIfNotExistsInterceptor;
import org.jboss.cache.loader.SamplePojo;
import org.jboss.cache.marshall.MethodDeclarations;
import org.jboss.cache.transaction.DummyTransactionManager;

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

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

    protected TransactionManager txManager;
    protected Transaction tx;
    protected GlobalTransaction gtx;
    protected TransactionTable table;
    protected OptimisticTransactionEntry entry;
    protected TransactionWorkspace workspace;

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

    protected void setupTransactionsInInvocationCtx(TreeCache cache) throws Exception
    {
        txManager = DummyTransactionManager.getInstance();
        // start a tx
        txManager.begin();

        // set class level vars
        table = cache.getTransactionTable();

        // create a gtx
        gtx = cache.getCurrentTransaction();
        tx = txManager.getTransaction();
        entry = (OptimisticTransactionEntry) table.get( gtx );
        workspace = entry.getTransactionWorkSpace();

        // set invocation context elements
        cache.getInvocationContext().setGlobalTransaction(gtx);
        cache.getInvocationContext().setTransaction(tx);
    }

    public void testNodeCreation() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

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

        interceptor.setNext(dummy);

        cache.setInterceptorChain(interceptor);

        setupTransactionsInInvocationCtx(cache);

        final SamplePojo pojo = new SamplePojo(21, "test");
        cache.put("/one/two", "key1", pojo);

        assertEquals(3, workspace.getNodes().size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertNotNull(workspace.getNode(Fqn.fromString("/one/")));
        assertEquals(null, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertTrue(entry.getLocks().isEmpty());

        assertTrue(!cache.exists("/one/two"));
        assertEquals(MethodDeclarations.putKeyValMethodLocal, dummy.getCalled());

        assertEquals(2, listener.getNodesAdded());
        txManager.commit();

        cache.stopService();

    }

    public void testInvalidTransaction() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

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

        interceptor.setNext(dummy);


        cache.setInterceptorChain(interceptor);

        setupTransactionsInInvocationCtx(cache);
        final SamplePojo pojo = new SamplePojo(21, "test");
        cache.put("/one/two", "key1", pojo);

        assertEquals(3, workspace.getNodes().size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertNotNull(workspace.getNode(Fqn.fromString("/one/")));
        assertEquals(null, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertTrue(entry.getLocks().isEmpty());

        assertTrue(!cache.exists("/one/two"));
        assertEquals(MethodDeclarations.putKeyValMethodLocal, dummy.getCalled());

        assertEquals(2, listener.getNodesAdded());

        txManager.commit();
        // we should now remove stuff from the InvocationCtx
        cache.getInvocationContext().setGlobalTransaction(null);
        cache.getInvocationContext().setTransaction(null);

        try
        {
            cache.put("/one/two/three", "key1", pojo);
            assertTrue("Should never be reched", false);
        }
        catch (Throwable t)
        {
            t.printStackTrace();
            assertTrue(true);
        }

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

    }

    public void testMultiplePut() throws Exception
    {

        TestListener listener = new TestListener();
        final TreeCache cache = createCacheWithListener(listener);

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

        cache.setInterceptorChain(interceptor);
        SamplePojo pojo = new SamplePojo(21, "test");

        setupTransactionsInInvocationCtx(cache);

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

        assertEquals(3, workspace.getNodes().size());
        assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
        assertNotNull(workspace.getNode(Fqn.fromString("/one/")));
        assertEquals(null, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
        assertTrue(entry.getLocks().isEmpty());

        assertTrue(!cache.exists("/one/two"));
        assertEquals(MethodDeclarations.putKeyValMethodLocal, dummy.getCalled());

        assertEquals(2, listener.getNodesAdded());

        txManager.commit();

        cache.stopService();

    }


}
