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

import junit.framework.Assert;
import org.jboss.cache.TreeCache;
import org.jboss.cache.loader.CacheLoader;
import org.jboss.cache.transaction.DummyTransactionManager;

import javax.transaction.Transaction;

/**
 * Tests optimistic locking with cache loaders
 *
 * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik@jboss.org</a>)
 */
public class OptimisticWithCacheLoaderTest extends AbstractOptimisticTestCase
{

    public OptimisticWithCacheLoaderTest(String s)
    {
        super(s);
    }

    public void testLoaderIndependently() throws Exception
    {
        TreeCache cache = createCacheWithLoader();
        CacheLoader loader = cache.getCacheLoader();

        // test the cache loader independently first ...
        loader.remove(fqn);
        Assert.assertNull(loader.get(fqn));
        loader.put(fqn, key, value);
        Assert.assertEquals(value, loader.get(fqn).get(key));
        // clean up
        loader.remove(fqn);
        Assert.assertNull(loader.get(fqn));
    }

    public void testCacheLoadOnTree() throws Exception
    {
        TreeCache cache = createCacheWithLoader();
        CacheLoader loader = cache.getCacheLoader();

        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        Transaction tx;

        // make sure the fqn is not in cache
        Assert.assertNull(cache.get(fqn));

        // put something in the loader and make sure all tx's can see it
        loader.put(fqn, key, value);

        // start the 1st tx
        mgr.begin();
        tx = mgr.getTransaction();
        Assert.assertEquals(value, cache.get(fqn, key));
        mgr.suspend();

        // start a new tx
        mgr.begin();
        Assert.assertEquals(value, cache.get(fqn, key));
        mgr.commit();

        mgr.resume(tx);
        Assert.assertEquals(value, cache.get(fqn, key));
        mgr.commit();

        // cleanup
        loader.remove(fqn);
    }

    public void testCacheStoring() throws Exception
    {
        Transaction tx;
        TreeCache cache = createCacheWithLoader();
        CacheLoader loader = cache.getCacheLoader();

        // test the cache ...
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        assertNull(mgr.getTransaction());
        mgr.begin();
        cache.put(fqn, key, value);
        mgr.commit();

        Assert.assertEquals(value, cache.get(fqn, key));

        //now lets see if the state has been persisted in the cache loader
        Assert.assertEquals(value, loader.get(fqn).get(key));


        mgr.begin();
        cache.remove(fqn);
        mgr.commit();

        Assert.assertNull(cache.get(fqn, key));
        //now lets see if the state has been persisted in the cache loader
        Assert.assertNull(loader.get(fqn));

        mgr.begin();
        cache.put(fqn, key, value);
        tx = mgr.getTransaction();
        mgr.suspend();

        // lets see what we've got halfway within a tx
        Assert.assertNull(cache.get(fqn, key));
        Assert.assertNull(loader.get(fqn));

        mgr.resume(tx);
        mgr.commit();

        // and after committing...
        Assert.assertEquals(value, cache.get(fqn, key));
        Assert.assertEquals(value, loader.get(fqn).get(key));

        // clean up loader
        loader.remove(fqn);
    }

    public void testCacheLoading() throws Exception
    {
        TreeCache cache = createCacheWithLoader();
        CacheLoader loader = cache.getCacheLoader();

        Assert.assertNull(cache.get(fqn, key));

        // put something in the loader
        loader.put(fqn, key, value);
        Assert.assertEquals(value, loader.get(fqn).get(key));

        // test that this can now be accessed by the cache
        Assert.assertEquals(value, cache.get(fqn, key));

        // clean up loader
        loader.remove(fqn);

        // what's in the cache now?  Should not ne null...
        Assert.assertNotNull(cache.get(fqn, key));
    }

    public void testCacheLoadingWithReplication() throws Exception
    {
        TreeCache cache1 = createReplicatedCacheWithLoader(false);
        CacheLoader loader1 = cache1.getCacheLoader();

        TreeCache cache2 = createReplicatedCacheWithLoader(false);
        CacheLoader loader2 = cache2.getCacheLoader();

        // test the cache ...
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        assertNull(mgr.getTransaction());

        mgr.begin();

        // add something in cache1
        cache1.put(fqn, key, value);
        Assert.assertEquals(value, cache1.get(fqn, key));

        // test that loader1, loader2, cache2 doesnt have entry
        Assert.assertNull(loader1.get(fqn));
        Assert.assertNull(loader2.get(fqn));
        Assert.assertNull(cache2.get(fqn, key));

        // commit
        mgr.commit();

        // test that loader1, loader2, cache2 has entry
        Assert.assertEquals(value, cache1.get(fqn, key));
        Assert.assertEquals(value, loader1.get(fqn).get(key));
        Assert.assertEquals(value, loader2.get(fqn).get(key));
        Assert.assertEquals(value, cache2.get(fqn, key));

        // cache2 removes entry
        mgr.begin();
        cache2.remove(fqn);
        Assert.assertNull(cache2.get(fqn, key));
        // test that loader1, loader2 and cache2 have the entry
        Assert.assertEquals(value, cache1.get(fqn, key));
        Assert.assertEquals(value, loader1.get(fqn).get(key));
        Assert.assertEquals(value, loader2.get(fqn).get(key));

        // commit
        mgr.commit();

        // test that the entry has been removed everywhere.
        Assert.assertNull(cache1.get(fqn));
        Assert.assertNull(loader1.get(fqn));
        Assert.assertNull(loader2.get(fqn));
        Assert.assertNull(cache2.get(fqn));

    }

    public void testSharedCacheLoadingWithReplication() throws Exception
    {
        TreeCache cache1 = createReplicatedCacheWithLoader(true);
        CacheLoader loader1 = cache1.getCacheLoader();

        TreeCache cache2 = createReplicatedCacheWithLoader(true);
        CacheLoader loader2 = cache2.getCacheLoader();

        // test the cache ...
        DummyTransactionManager mgr = DummyTransactionManager.getInstance();
        assertNull(mgr.getTransaction());

        mgr.begin();

        // add something in cache1
        cache1.put(fqn, key, value);
        Assert.assertEquals(value, cache1.get(fqn, key));

        // test that loader1, loader2, cache2 doesnt have entry
        System.out.println("*** " + loader1.get(fqn));
        Assert.assertNull(loader1.get(fqn));
        Assert.assertNull(loader2.get(fqn));
        Assert.assertNull(cache2.get(fqn, key));

        // commit
        mgr.commit();

        // test that loader1, loader2, cache2 has entry
        Assert.assertEquals(value, cache1.get(fqn, key));
        Assert.assertEquals(value, loader1.get(fqn).get(key));
        Assert.assertEquals(value, loader2.get(fqn).get(key));
        Assert.assertEquals(value, cache2.get(fqn, key));

        // cache2 removes entry
        mgr.begin();
        cache2.remove(fqn);
        Assert.assertNull(cache2.get(fqn, key));
        // test that loader1, loader2 and cache2 have the entry
        Assert.assertEquals(value, cache1.get(fqn, key));
        Assert.assertEquals(value, loader1.get(fqn).get(key));
        Assert.assertEquals(value, loader2.get(fqn).get(key));

        // commit
        mgr.commit();

        // test that the entry has been removed everywhere.
        Assert.assertNull(cache1.get(fqn));
        Assert.assertNull(loader1.get(fqn));
        Assert.assertNull(loader2.get(fqn));
        Assert.assertNull(cache2.get(fqn));

    }
}
