/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.passivation;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.AbstractTreeCacheListener;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.TreeCache;
import org.jboss.cache.loader.CacheLoader;
import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.misc.TestingUtil;
import org.jboss.cache.xml.XmlHelper;
import org.w3c.dom.Element;
import junit.framework.TestCase;
/**
* Tests that the TreeCacheListener implementation used by EJB3 SFSBs works.
*
* @author Brian Stansberry
*
*/
public class PassivationActivationCallbacksTestCase extends TestCase
{
private static final Fqn BASE = Fqn.fromString("/base");
private static final Log log = LogFactory.getLog(PassivationActivationCallbacksTestCase.class);
//Cache Loader fields
private TreeCache cache;
private CacheLoader loader=null;
private CacheListener listener = null;
protected void setUp() throws Exception
{
super.setUp();
log.debug("Testing " + getName());
log.debug("");
cache=new TreeCache();
cache.setCacheMode("local");
configureCache();
cache.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
cache.setIsolationLevel(IsolationLevel.SERIALIZABLE);
listener = new CacheListener();
cache.addTreeCacheListener(listener);
cache.createService();
cache.startService();
loader=cache.getCacheLoader();
}
protected void configureCache() throws Exception {
String tmp_location = null;
String OS = System.getProperty("os.name").toLowerCase();
if(OS.indexOf("win") > -1 || OS.indexOf("nt") > -1)
{
tmp_location=System.getProperty("java.io.tmpdir", "c:\\tmp\\fcl");
}
else
{
tmp_location=System.getProperty("java.io.tmpdir", "/tmp/fcl");
}
cache.setCacheLoaderConfiguration(getCacheLoaderConfig(tmp_location));
cache.setEvictionPolicyConfig(getEvictionConfig());
}
protected Element getEvictionConfig() throws Exception
{
String xml =
"<attribute name=\"EvictionPolicyConfig\">\n" +
" <config>\n" +
" <attribute name=\"wakeUpIntervalSeconds\">1</attribute>\n" +
" <region name=\"/_default_\" policyClass=\"org.jboss.cache.eviction.LRUPolicy\">\n" +
" <attribute name=\"maxNodes\">0</attribute>\n" +
" <attribute name=\"timeToLiveSeconds\">5</attribute>\n" +
" </region>\n" +
" <region name=\"/base\" policyClass=\"org.jboss.cache.eviction.LRUPolicy\">\n" +
" <attribute name=\"maxNodes\">0</attribute>\n" +
" <attribute name=\"timeToLiveSeconds\">1</attribute>\n" +
" </region>\n" +
" </config>\n" +
"</attribute>\n";
return XmlHelper.stringToElement(xml);
}
protected Element getCacheLoaderConfig(String loc) throws Exception
{
String xml = " <config>\n" +
" \n" +
" <passivation>true</passivation>\n" +
" <preload>/</preload>\n" +
"\n" +
" <cacheloader>\n" +
" <class>org.jboss.cache.loader.FileCacheLoader</class>\n" +
" <properties>" + loc + "</properties>\n" +
" <async>false</async>\n" +
" <fetchPersistentState>false</fetchPersistentState>\n" +
" <ignoreModifications>false</ignoreModifications>\n" +
" </cacheloader>\n" +
" \n" +
" </config>";
return XmlHelper.stringToElement(xml);
}
protected void tearDown() throws Exception
{
super.tearDown();
cache.remove("/");
loader.remove(Fqn.fromString("/"));
cache.stopService();
cache.destroyService();
}
public void testSimpleLifecycle() throws Exception
{
Fqn fqn = new Fqn(BASE, "bean1");
cache.put(fqn, "bean", "A bean");
TestingUtil.sleepThread(3000);
assertNull("No activation exception", listener.activationException);
assertNull("No passivation exception", listener.passivationException);
assertTrue(listener.passivated.contains(fqn));
assertFalse(listener.activated.contains(fqn));
Object obj = cache.get(fqn, "bean");
assertEquals("Got bean", "A bean", obj);
assertNull("No activation exception", listener.activationException);
assertNull("No passivation exception", listener.passivationException);
assertTrue(listener.activated.contains(fqn));
}
/**
* Mimics the TreeCacheListener used by EJB3 SFSBs.
*/
private class CacheListener extends AbstractTreeCacheListener
{
protected Log log = LogFactory.getLog(CacheListener.class);
protected Set passivated = new HashSet();
protected Set activated = new HashSet();
protected Exception passivationException;
protected Exception activationException;
public void nodeActivate(Fqn fqn, boolean pre)
{
if(pre)
return; // we are not interested in postActivate event
if(!fqn.isChildOrEquals(BASE)) return; // don't care about fqn that doesn't belong to me.
Object bean = null;
try {
bean = cache.get(fqn, "bean");
} catch (CacheException e) {
log.error("nodeActivate(): can't retrieve bean instance from: " +fqn + " with exception: " +e);
activationException = e;
return;
}
if(bean == null)
{
activationException = new IllegalStateException("nodeActivate(): null bean instance.");
throw (IllegalStateException) activationException;
}
if(log.isTraceEnabled())
{
log.trace("nodeActivate(): saw postActivate event on fqn: " +fqn);
}
activated.add(fqn);
}
public void nodePassivate(Fqn fqn, boolean pre) {
if(!pre) return; // we are not interested in postPassivate event
if(!fqn.isChildOrEquals(BASE)) return; // don't care about fqn that doesn't belong to me.
try {
// TODO Can this cause deadlock in the cache level? Should be ok but need review.
Node node = cache.get(fqn);
Object bean = node.getData().get("bean");
if (bean != null)
{
if(log.isTraceEnabled())
{
log.trace("nodePassivate(): send prePassivate event on fqn: " +fqn);
}
passivated.add(fqn);
}
} catch (CacheException e) {
log.error("nodePassivate(): can't retrieve bean instance from: " +fqn + " with exception: " +e);
passivationException = e;
return;
}
}
}
}