/*
* Created on 17-Feb-2005
*
*
*
*/
package org.jboss.cache.optimistic;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
import org.jboss.cache.InvocationContext;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.interceptors.Interceptor;
import org.jboss.cache.interceptors.InvocationContextInterceptor;
import org.jboss.cache.interceptors.OptimisticCreateIfNotExistsInterceptor;
import org.jboss.cache.interceptors.OptimisticNodeInterceptor;
import org.jboss.cache.interceptors.OptimisticValidatorInterceptor;
import org.jboss.cache.loader.SamplePojo;
import org.jboss.cache.marshall.MethodCall;
import org.jboss.cache.marshall.MethodCallFactory;
import org.jboss.cache.marshall.MethodDeclarations;
import org.jboss.cache.misc.TestingUtil;
import org.jboss.cache.transaction.GlobalTransaction;
import org.jboss.cache.transaction.OptimisticTransactionEntry;
import org.jboss.cache.transaction.TransactionTable;
import org.jboss.cache.util.CachePrinter;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* @author xenephon
*/
@Test(groups = "functional")
public class ValidatorInterceptorTest extends AbstractOptimisticTestCase
{
private CacheSPI<Object, Object> cache;
private TransactionManager mgr;
private MockInterceptor dummy;
@BeforeMethod
public void setUp() throws Exception
{
cache = createCacheWithListener();
mgr = cache.getTransactionManager();
Interceptor ici = TestingUtil.findInterceptor(cache, InvocationContextInterceptor.class);
Interceptor validateInterceptor = TestingUtil.findInterceptor(cache, OptimisticValidatorInterceptor.class);
Interceptor interceptor = TestingUtil.findInterceptor(cache, OptimisticCreateIfNotExistsInterceptor.class);
Interceptor nodeInterceptor = TestingUtil.findInterceptor(cache, OptimisticNodeInterceptor.class);
dummy = new MockInterceptor();
ici.setNext(validateInterceptor);
validateInterceptor.setNext(interceptor);
interceptor.setNext(nodeInterceptor);
nodeInterceptor.setNext(dummy);
TestingUtil.replaceInterceptorChain(cache, ici);
cache.addInterceptor(new ResetRemoteFlagInterceptor(), InvocationContextInterceptor.class);
System.out.println("Interceptors: " + CachePrinter.printCacheInterceptors(cache));
}
@AfterMethod
public void tearDown()
{
TestingUtil.killCaches(cache);
}
public void testTransactionvalidateMethod() throws Throwable
{
mgr.begin();
Transaction tx = mgr.getTransaction();
// inject InvocationContext
cache.getInvocationContext().setTransaction(tx);
cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx, true));
SamplePojo pojo = new SamplePojo(21, "test");
Map<Object, Object> temp = new HashMap<Object, Object>();
temp.put("key1", pojo);
cache.put("/one/two", temp);
assertEquals(null, dummy.getCalled());
TransactionTable table = cache.getTransactionTable();
GlobalTransaction gtx = table.get(tx);
OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);
TransactionWorkspace<Object, Object> workspace = entry.getTransactionWorkSpace();
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertTrue(!cache.exists("/one/two"));
assertEquals(null, dummy.getCalled());
//now let us do a prepare
MethodCall prepareMethod = MethodCallFactory.create(MethodDeclarations.optimisticPrepareMethod_id, gtx, entry.getModifications(), null, gtx.getAddress(), Boolean.FALSE);
TestingUtil.getRemoteDelegate(cache)._replicate(prepareMethod);
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertTrue(!cache.exists("/one/two"));
assertEquals(prepareMethod.getMethod(), dummy.getCalled());
mgr.commit();
}
public void testTransactionValidateFailureMethod() throws Exception
{
mgr.begin();
Transaction tx = mgr.getTransaction();
// inject InvocationContext
cache.getInvocationContext().setTransaction(tx);
cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx, true));
SamplePojo pojo = new SamplePojo(21, "test");
Map<Object, Object> temp = new HashMap<Object, Object>();
temp.put("key1", pojo);
cache.put("/one/two", temp);
assertEquals(null, dummy.getCalled());
TransactionTable table = cache.getTransactionTable();
GlobalTransaction gtx = table.get(tx);
OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);
TransactionWorkspace<Object, Object> workspace = entry.getTransactionWorkSpace();
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertTrue(!cache.exists("/one/two"));
assertEquals(null, dummy.getCalled());
//lets change one of the underlying version numbers
workspace.getNode(Fqn.fromString("/one/two")).getNode().setVersion(new DefaultDataVersion(2));
//now let us do a prepare
MethodCall prepareMethod = MethodCallFactory.create(MethodDeclarations.optimisticPrepareMethod_id, gtx, entry.getModifications(), null, gtx.getAddress(), Boolean.FALSE);
try
{
TestingUtil.getRemoteDelegate(cache)._replicate(prepareMethod);
fail();
}
catch (Throwable t)
{
assertTrue(true);
}
mgr.commit();
}
public void testTransactionValidateCommitMethod() throws Throwable
{
mgr.begin();
Transaction tx = mgr.getTransaction();
// inject InvocationContext
cache.getInvocationContext().setTransaction(tx);
cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx, true));
Object pojo = new SamplePojo(21, "test");
cache.put("/one/two", Collections.singletonMap((Object) "key1", pojo));
assertEquals(null, dummy.getCalled());
TransactionTable table = cache.getTransactionTable();
GlobalTransaction gtx = table.get(tx);
OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);
TransactionWorkspace<Object, Object> workspace = entry.getTransactionWorkSpace();
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertTrue(!cache.exists("/one/two"));
assertEquals(null, dummy.getCalled());
//lets change one of the underlying version numbers
//now let us do a prepare
MethodCall prepareMethod = MethodCallFactory.create(MethodDeclarations.optimisticPrepareMethod_id, gtx, entry.getModifications(), null, gtx.getAddress(), Boolean.FALSE);
try
{
TestingUtil.getRemoteDelegate(cache)._replicate(prepareMethod);
fail();
}
catch (Throwable t)
{
assertTrue(true);
}
MethodCall commitMethod = MethodCallFactory.create(MethodDeclarations.commitMethod_id, gtx);
TestingUtil.getRemoteDelegate(cache)._replicate(commitMethod);
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertEquals(commitMethod.getMethod(), dummy.getCalled());
NodeSPI<Object, Object> node = workspace.getNode(Fqn.ROOT).getNode();
//assert we can navigate
assertNotNull(node);
node = (NodeSPI<Object, Object>) node.getChild("one");
assertEquals(new DefaultDataVersion(0), node.getVersion());
assertNotNull(node);
node = (NodeSPI<Object, Object>) node.getChild("two");
assertNotNull(node);
assertEquals(new DefaultDataVersion(1), node.getVersion());
assertEquals(pojo, node.get("key1"));
mgr.commit();
}
public void testTransactionValidateFailRemoteCommitMethod() throws Throwable
{
mgr.begin();
Transaction tx = mgr.getTransaction();
// inject InvocationContext
cache.getInvocationContext().setTransaction(tx);
cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx, true));
SamplePojo pojo = new SamplePojo(21, "test");
Map<Object, Object> temp = new HashMap<Object, Object>();
temp.put("key1", pojo);
cache.put("/one/two", temp);
assertEquals(null, dummy.getCalled());
TransactionTable table = cache.getTransactionTable();
GlobalTransaction gtx = table.get(tx);
OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);
@SuppressWarnings("unchecked") TransactionWorkspace<Object, Object> workspace = entry.getTransactionWorkSpace();
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertTrue(!cache.exists("/one/two"));
assertEquals(null, dummy.getCalled());
//lets change one of the underlying version numbers
//now let us do a prepare
MethodCall prepareMethod = MethodCallFactory.create(MethodDeclarations.optimisticPrepareMethod_id, gtx, entry.getModifications(), null, gtx.getAddress(), Boolean.FALSE);
try
{
TestingUtil.getRemoteDelegate(cache)._replicate(prepareMethod);
fail();
}
catch (Throwable t)
{
assertTrue(true);
}
MethodCall commitMethod = MethodCallFactory.create(MethodDeclarations.commitMethod_id, gtx);
TestingUtil.getRemoteDelegate(cache)._replicate(commitMethod);
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertEquals(commitMethod.getMethod(), dummy.getCalled());
NodeSPI<Object, Object> node = workspace.getNode(Fqn.fromString("/")).getNode();
//assert we can navigate
assertNotNull(node);
node = (NodeSPI<Object, Object>) node.getChild("one");
assertEquals(new DefaultDataVersion(0), node.getVersion());
assertNotNull(node);
assertTrue(cache.exists(node.getFqn()));
node = (NodeSPI<Object, Object>) node.getChild("two");
assertNotNull(node);
assertTrue(cache.exists(node.getFqn()));
assertEquals(new DefaultDataVersion(1), node.getVersion());
assertEquals(pojo, node.get("key1"));
mgr.commit();
}
public void testTransactionValidateRollbackMethod() throws Throwable
{
mgr.begin();
Transaction tx = mgr.getTransaction();
// inject InvocationContext
cache.getInvocationContext().setTransaction(tx);
cache.getInvocationContext().setGlobalTransaction(cache.getCurrentTransaction(tx, true));
SamplePojo pojo = new SamplePojo(21, "test");
Map<Object, Object> temp = new HashMap<Object, Object>();
temp.put("key1", pojo);
cache.put("/one/two", temp);
assertEquals(null, dummy.getCalled());
TransactionTable table = cache.getTransactionTable();
GlobalTransaction gtx = table.get(tx);
OptimisticTransactionEntry entry = (OptimisticTransactionEntry) table.get(gtx);
TransactionWorkspace<Object, Object> workspace = entry.getTransactionWorkSpace();
assertEquals(3, workspace.getNodes().size());
assertNotNull(workspace.getNode(Fqn.fromString("/one/two")));
assertEquals(pojo, workspace.getNode(Fqn.fromString("/one/two")).get("key1"));
assertEquals(1, workspace.getNode(Fqn.fromString("/one/two")).getMergedData().size());
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
assertTrue(!cache.exists("/one/two"));
assertEquals(null, dummy.getCalled());
//lets change one of the underlying version numbers
//now let us do a prepare
MethodCall prepareMethod = MethodCallFactory.create(MethodDeclarations.optimisticPrepareMethod_id, gtx, entry.getModifications(), null, gtx.getAddress(), Boolean.FALSE);
try
{
TestingUtil.getRemoteDelegate(cache)._replicate(prepareMethod);
fail();
}
catch (Throwable t)
{
assertTrue(true);
}
MethodCall rollbackMethod = MethodCallFactory.create(MethodDeclarations.rollbackMethod_id, gtx);
TestingUtil.getRemoteDelegate(cache)._replicate(rollbackMethod);
assertEquals(0, workspace.getNodes().size());
assertNull(workspace.getNode(Fqn.fromString("/one/two")));
assertNull(workspace.getNode(Fqn.fromString("/one")));
assertTrue(entry.getLocks().isEmpty());
assertEquals(1, entry.getModifications().size());
mgr.commit();
}
public static class ResetRemoteFlagInterceptor extends Interceptor
{
@Override
public Object invoke(InvocationContext ctx) throws Throwable
{
log.trace("Setting isRemote on gtx " + ctx.getGlobalTransaction() + " to true");
ctx.getGlobalTransaction().setRemote(true);
return nextInterceptor(ctx);
}
}
}