package org.infinispan.context;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.io.Serializable;
import javax.transaction.TransactionManager;
import org.infinispan.Cache;
import org.infinispan.commands.VisitableCommand;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.context.impl.LocalTxInvocationContext;
import org.infinispan.interceptors.base.CommandInterceptor;
import org.infinispan.interceptors.impl.InvocationContextInterceptor;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.marshall.core.ExternalPojo;
import org.infinispan.test.SingleCacheManagerTest;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.transaction.LockingMode;
import org.infinispan.util.concurrent.locks.LockManager;
import org.testng.annotations.Test;
/**
* This is to test that contexts are properly constructed and cleaned up wven when using marshalled values and the
* explicit lock() API.
*
* @author Manik Surtani
* @version 4.1
*/
@Test (testName = "context.MarshalledValueContextTest", groups = "functional")
public class MarshalledValueContextTest extends SingleCacheManagerTest {
@Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
ConfigurationBuilder c = TestCacheManagerFactory.getDefaultCacheConfiguration(true);
c
.storeAsBinary().enable()
.transaction().lockingMode(LockingMode.PESSIMISTIC);
return TestCacheManagerFactory.createCacheManager(c);
}
public void testContentsOfContext() throws Exception {
Cache<Key, String> c = cacheManager.getCache();
ContextExtractingInterceptor cex = new ContextExtractingInterceptor();
assertTrue(c.getAdvancedCache().getAsyncInterceptorChain().addInterceptorAfter(cex, InvocationContextInterceptor.class));
c.put(new Key("k"), "v");
assertEquals("v", c.get(new Key("k")));
TransactionManager tm = c.getAdvancedCache().getTransactionManager();
tm.begin();
c.getAdvancedCache().lock(new Key("k"));
LockManager lockManager = TestingUtil.extractComponent(c, LockManager.class);
assertTrue(cex.ctx instanceof LocalTxInvocationContext);
assertEquals("Looked up key should not be in transactional invocation context " +
"as we don't perform any changes", 0, cex.ctx.getLookedUpEntries().size());
assertEquals("Only one lock should be held", 1, lockManager.getNumberOfLocksHeld());
c.put(new Key("k"), "v2");
assertEquals("Still should only be one entry in the context", 1, cex.ctx.getLookedUpEntries().size());
assertEquals("Only one lock should be held", 1, lockManager.getNumberOfLocksHeld());
tm.commit();
assertEquals("No locks should be held anymore", 0, lockManager.getNumberOfLocksHeld());
assertEquals("v2", c.get(new Key("k")));
}
private static class ContextExtractingInterceptor extends CommandInterceptor {
InvocationContext ctx;
@Override
protected Object handleDefault(InvocationContext ctx, VisitableCommand command) throws Throwable {
this.ctx = ctx;
return super.invokeNextInterceptor(ctx, command);
}
}
private static class Key implements Serializable, ExternalPojo {
String actualKey;
private Key(String actualKey) {
this.actualKey = actualKey;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (actualKey != null ? !actualKey.equals(key.actualKey) : key.actualKey != null) return false;
return true;
}
@Override
public int hashCode() {
return actualKey != null ? actualKey.hashCode() : 0;
}
}
}