package org.jboss.cache.transaction;
import junit.framework.TestCase;
import org.jboss.cache.TreeCache;
import org.jboss.cache.DummyTransactionManagerLookup;
import org.jboss.cache.TransactionManagerLookup;
import javax.transaction.TransactionManager;
import javax.transaction.Transaction;
import javax.transaction.SystemException;
import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.RollbackException;
import javax.transaction.Synchronization;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
/**
* This test checks how the cache behaves when a JTA STATUS_UNKNOWN is passed in to the cache during afterCompletion().
*
* @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
*/
public class StatusUnknownTest extends TestCase
{
private TreeCache cache;
private TransactionManager tm;
protected void setUp() throws Exception
{
cache = new TreeCache();
cache.setTransactionManagerLookupClass(HeuristicFailingDummyTransactionManagerLookup.class.getName());
cache.startService();
tm = cache.getTransactionManager();
}
protected void tearDown()
{
cache.stopService();
}
public void testStatusUnknown() throws Exception
{
tm.begin();
cache.put("/a/b/c", "k", "v");
assertEquals(4, cache.getNumberOfLocksHeld());
assertTrue(cache.exists("/a/b/c"));
tm.commit();
assertEquals(0, cache.getNumberOfLocksHeld());
assertFalse(cache.exists("/a/b/c"));
}
public static class HeuristicFailingDummyTransactionManager extends DummyTransactionManager
{
public void begin() throws SystemException, NotSupportedException
{
super.begin();
Transaction tx = new HeuristicFailingDummyTransaction(this);
setTransaction(tx);
}
public static DummyTransactionManager getInstance()
{
if(instance == null)
{
instance=new HeuristicFailingDummyTransactionManager();
try
{
Properties p=new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.cache.transaction.DummyContextFactory");
Context ctx=new InitialContext(p);
ctx.bind("java:/TransactionManager", instance);
ctx.bind("UserTransaction", new DummyUserTransaction(instance));
}
catch(NamingException e)
{
log.error("binding of DummyTransactionManager failed", e);
}
}
return instance;
}
}
public static class HeuristicFailingDummyTransaction extends DummyTransaction
{
public HeuristicFailingDummyTransaction(DummyBaseTransactionManager mgr)
{
super(mgr);
}
public void commit() throws RollbackException
{
status= Status.STATUS_PREPARING;
try
{
notifyBeforeCompletion();
notifyAfterCompletion(Status.STATUS_UNKNOWN);
}
finally
{
// Disassociate tx from thread.
tm_.setTransaction(null);
}
}
protected void notifyAfterCompletion(int status)
{
List tmp;
synchronized(participants)
{
tmp=new LinkedList(participants);
}
for(Iterator it=tmp.iterator(); it.hasNext();)
{
Synchronization s=(Synchronization)it.next();
try
{
s.afterCompletion(status);
}
catch(Throwable t)
{
throw (RuntimeException) t;
}
}
synchronized(participants)
{
participants.clear();
}
}
}
public static class HeuristicFailingDummyTransactionManagerLookup implements TransactionManagerLookup
{
public TransactionManager getTransactionManager() throws Exception
{
return HeuristicFailingDummyTransactionManager.getInstance();
}
}
}