/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.cache.statetransfer;
import junit.framework.TestCase;
import org.jboss.cache.Fqn;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.TreeCache;
import org.jboss.cache.TreeCacheMBean;
import org.jboss.cache.marshall.SelectedClassnameClassLoader;
import org.jboss.cache.xml.XmlHelper;
import org.w3c.dom.Element;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Abstract superclass of the StateTransfer tests.
*
* @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
* @version $Revision$
*/
public abstract class StateTransferTestBase extends TestCase
{
public static final Fqn A_B = Fqn.fromString("/a/b");
public static final Fqn A_C = Fqn.fromString("/a/c");
public static final Fqn A_D = Fqn.fromString("/a/d");
public static final String JOE = "JOE";
public static final String BOB = "BOB";
public static final String JANE = "JANE";
public static final Integer TWENTY = new Integer(20);
public static final Integer FORTY = new Integer(40);
protected Map caches;
private ClassLoader orig_TCL;
protected abstract String getReplicationVersion();
protected TreeCacheMBean createCache(String cacheID,
boolean sync,
boolean useMarshalling,
boolean useCacheLoader)
throws Exception
{
return createCache(cacheID, sync, useMarshalling, useCacheLoader, false, true);
}
protected TreeCacheMBean createCache(String cacheID,
boolean sync,
boolean useMarshalling,
boolean useCacheLoader,
boolean cacheLoaderAsync,
boolean startCache)
throws Exception
{
if (caches.get(cacheID) != null)
throw new IllegalStateException(cacheID + " already created");
TreeCacheMBean tree=new TreeCache();
PropertyConfigurator config=new PropertyConfigurator();
String configFile = sync ? "META-INF/replSync-service.xml"
: "META-INF/replAsync-service.xml";
config.configure(tree, configFile); // read in generic replAsync xml
tree.setClusterName("VersionedTestBase");
tree.setReplicationVersion(getReplicationVersion());
// Use a long timeout to facilitate setting debugger breakpoints
tree.setInitialStateRetrievalTimeout(60000);
if (useMarshalling) {
tree.setUseRegionBasedMarshalling(true);
tree.setInactiveOnStartup(true);
}
if (useCacheLoader) {
configureCacheLoader(tree, cacheID, useMarshalling, cacheLoaderAsync);
}
configureMultiplexer(tree);
// Put the cache in the map before starting, so if it fails in
// start it can still be destroyed later
caches.put(cacheID, tree);
if (startCache)
{
startCache(tree);
}
return tree;
}
/**
* Provides a hook for multiplexer integration. This default implementation
* is a no-op; subclasses that test mux integration would override
* to integrate the given cache with a multiplexer.
*
* param cache a cache that has been configured but not yet created.
*/
protected void configureMultiplexer(TreeCacheMBean cache) throws Exception
{
// default does nothing
}
/**
* Provides a hook to check that the cache's channel came from the
* multiplexer, or not, as expected. This default impl asserts that
* the channel did not come from the multiplexer.
*
* @param cache a cache that has already been started
*/
protected void validateMultiplexer(TreeCacheMBean cache)
{
assertFalse("Cache is not using multiplexer", cache.isUsingMultiplexer());
}
protected void startCache(TreeCacheMBean cache) throws Exception
{
cache.createService();
cache.startService();
validateMultiplexer(cache);
}
protected void configureCacheLoader(TreeCacheMBean cache,
String cacheID,
boolean useExtended,
boolean async)
throws Exception
{
String tmp_location = getTempLocation(cacheID);
// Do cleanup in case it failed before
File file = new File(tmp_location);
cleanFile(file);
file.mkdir();
tmp_location = escapeWindowsPath(tmp_location);
if (useExtended)
cache.setCacheLoaderConfiguration(getCacheLoaderConfig("org.jboss.cache.loader.FileExtendedCacheLoader", tmp_location, async));
else
cache.setCacheLoaderConfiguration(getCacheLoaderConfig("org.jboss.cache.loader.FileCacheLoader", tmp_location, async));
}
protected Element getCacheLoaderConfig(String cl, String loc, boolean async) throws Exception
{
String xml = " <config>\n" +
" \n" +
" <passivation>false</passivation>\n" +
" <preload></preload>\n" +
"\n" +
" <cacheloader>\n" +
" <class>" + cl + "</class>\n" +
" <properties>\n" +
" location=" + loc + "\n" +
" </properties>\n" +
" <async>" + async + "</async>\n" +
" <fetchPersistentState>true</fetchPersistentState>\n" +
" <ignoreModifications>false</ignoreModifications>\n" +
" </cacheloader>\n" +
" \n" +
" </config>";
return XmlHelper.stringToElement(xml);
}
protected String getTempLocation(String cacheID)
{
String tmp_location=System.getProperty("java.io.tmpdir", "c:\\tmp");
File file = new File(tmp_location);
file = new File(file, cacheID);
return file.getAbsolutePath();
}
protected String escapeWindowsPath(String path)
{
if ('/' == File.separatorChar)
return path;
char[] chars = path.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < chars.length; i++)
{
if (chars[i] == '\\')
sb.append('\\');
sb.append(chars[i]);
}
return sb.toString();
}
protected void setUp() throws Exception
{
super.setUp();
caches = new HashMap();
// Save the TCL in case a test changes it
orig_TCL = Thread.currentThread().getContextClassLoader();
}
protected void tearDown() throws Exception
{
super.tearDown();
// Restore the TCL in case a test changed it
Thread.currentThread().setContextClassLoader(orig_TCL);
Set keys = caches.keySet();
String[] cacheIDs = new String[keys.size()];
cacheIDs = (String[]) keys.toArray(cacheIDs);
for (int i = 0; i < cacheIDs.length; i++)
{
stopCache((TreeCache) caches.get(cacheIDs[i]));
File file = new File(getTempLocation(cacheIDs[i]));
cleanFile(file);
}
}
protected void stopCache(TreeCache cache)
{
if (cache != null)
{
try {
cache.stopService();
cache.destroyService();
}
catch (Exception e) {
System.out.println("Exception stopping cache " + e.getMessage());
e.printStackTrace(System.out);
}
}
}
protected void cleanFile(File file)
{
File[] children = file.listFiles();
if (children != null)
{
for (int i = 0; i < children.length; i++) {
cleanFile(children[i]);
}
}
if (file.exists())
file.delete();
if (file.exists())
file.deleteOnExit();
}
protected ClassLoader getClassLoader() throws Exception
{
String[] includesClasses = { "org.jboss.cache.marshall.Person",
"org.jboss.cache.marshall.Address" };
String [] excludesClasses = {};
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return new SelectedClassnameClassLoader(includesClasses, excludesClasses, cl);
}
protected ClassLoader getNotFoundClassLoader() throws Exception
{
String[] notFoundClasses = { "org.jboss.cache.marshall.Person",
"org.jboss.cache.marshall.Address" };
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return new SelectedClassnameClassLoader(null, null, notFoundClasses, cl);
}
}