/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.loader;

import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.xml.XmlHelper;
import org.w3c.dom.Element;

import java.util.List;
import java.util.Properties;

/**
 * Tests the construction of a cache laoder based on an XML element passed in.
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 */
public class CacheLoaderManagerTest extends AbstractCacheLoaderTestBase
{
    private CacheLoaderConfig createCacheLoaderCfg( boolean passivation )
    {
        CacheLoaderConfig cfg = new CacheLoaderConfig();
        cfg.setPassivation( passivation );
        return cfg;
    }

    private CacheLoaderConfig.IndividualCacheLoaderConfig createIndividualCacheLoaderConfig(CacheLoaderConfig parent, boolean async, String classname) throws Exception
    {
        CacheLoaderConfig.IndividualCacheLoaderConfig cfg = new CacheLoaderConfig.IndividualCacheLoaderConfig();
        cfg.setAsync( async );
        cfg.setClassName( classname );
        cfg.setFetchPersistentState( false );
        Properties p = new Properties();
        p.setProperty("location", getTempDir());
        p.setProperty("cache.jdbc.driver", "com.mysql.jdbc.Driver");
        p.setProperty("cache.jdbc.url", "jdbc:mysql://localhost/test");
        p.setProperty("cache.jdbc.user", "user");
        p.setProperty("cache.jdbc.password","pwd");
        cfg.setProperties(p);
        return cfg;
    }

    private String getTempDir()
    {
       return System.getProperty("java.io.tempdir", "/tmp");
    }

    private static Element strToElement(String s) throws Exception
    {
        return XmlHelper.stringToElement(s);
    }

    public void testSingleCacheLoader() throws Exception
    {
        // without async
        CacheLoaderManager mgr = new CacheLoaderManager();
        CacheLoaderConfig cfg = createCacheLoaderCfg(false);
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, false, "org.jboss.cache.loader.FileCacheLoader"));

        mgr.setConfig(cfg, null);
        CacheLoader cl = mgr.getCacheLoader();

        Assert.assertEquals(FileCacheLoader.class, cl.getClass());

        // with async
        cfg = createCacheLoaderCfg(false);
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader"));

        mgr.setConfig(cfg, null);
        cl = mgr.getCacheLoader();

        Assert.assertEquals(AsyncExtendedCacheLoader.class, cl.getClass());
    }

    public void testSingleCacheLoaderPassivation() throws Exception
    {
        // without async
        CacheLoaderConfig cfg = createCacheLoaderCfg(true);
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, false, "org.jboss.cache.loader.FileCacheLoader"));
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, false, "org.jboss.cache.loader.bdbje.BdbjeCacheLoader"));
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, false, "org.jboss.cache.loader.JDBCCacheLoader"));

        CacheLoaderManager mgr = new CacheLoaderManager();
        mgr.setConfig(cfg, null);
        CacheLoader cl = mgr.getCacheLoader();

        Assert.assertEquals(FileCacheLoader.class, cl.getClass());

        // with async
        cfg = createCacheLoaderCfg(true);
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader"));
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.bdbje.BdbjeCacheLoader"));
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.JDBCCacheLoader"));

        mgr.setConfig(cfg, null);
        cl = mgr.getCacheLoader();

        Assert.assertEquals(AsyncExtendedCacheLoader.class, cl.getClass());
    }

    public void testSingleCacheLoaderFromXml() throws Exception
    {
        // without async
        Element confXml = getSingleCacheLoaderConfig("", "org.jboss.cache.loader.FileCacheLoader", "location="+getTempDir(), false, false, false);

        CacheLoaderManager mgr = new CacheLoaderManager();
        mgr.setConfig(confXml, null);
        CacheLoader cl = mgr.getCacheLoader();

        Assert.assertEquals(FileCacheLoader.class, cl.getClass());

        // with async
        confXml = getSingleCacheLoaderConfig("", "org.jboss.cache.loader.FileCacheLoader", "location=" + getTempDir(), true, false, false);

        mgr.setConfig(confXml, null);
        cl = mgr.getCacheLoader();
        Assert.assertEquals(AsyncExtendedCacheLoader.class, cl.getClass());
    }

    public void testSingleCacheLoaderPassivationFromXml() throws Exception
    {
        // without async
        String conf = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+
                "<config><passivation>true</passivation>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.FileCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.bdbje.BdbjeCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.JDBCCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader></config>";

        CacheLoaderManager mgr = new CacheLoaderManager();
        mgr.setConfig(strToElement(conf), null);
        CacheLoader cl = mgr.getCacheLoader();

        Assert.assertEquals(FileCacheLoader.class, cl.getClass());

        // with async
        conf = "<config><passivation>true</passivation>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.FileCacheLoader</class>" +
                "    <async>true</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.bdbje.BdbjeCacheLoader</class>" +
                "    <async>true</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.JDBCCacheLoader</class>" +
                "    <async>true</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader></config>";

        mgr.setConfig(strToElement(conf), null);
        cl = mgr.getCacheLoader();

        Assert.assertEquals(AsyncExtendedCacheLoader.class, cl.getClass());
    }

    public void testChainingCacheLoader() throws Exception
    {
        // async = false
        CacheLoaderConfig cfg = createCacheLoaderCfg(false);
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, false, "org.jboss.cache.loader.FileCacheLoader"));
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, false, "org.jboss.cache.loader.JDBCCacheLoader"));

        CacheLoaderManager mgr = new CacheLoaderManager();
        mgr.setConfig(cfg, null);
        CacheLoader cl = mgr.getCacheLoader();

        Assert.assertEquals(ChainingCacheLoader.class, cl.getClass());
        Assert.assertEquals(2, ((ChainingCacheLoader) cl).getSize());
        List loaders = ((ChainingCacheLoader) cl).getCacheLoaders();
        Assert.assertEquals(FileCacheLoader.class, loaders.get(0).getClass());
        Assert.assertEquals(JDBCCacheLoader.class, loaders.get(1).getClass());

        // async = true
        cfg = createCacheLoaderCfg(false);
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, false, "org.jboss.cache.loader.FileCacheLoader"));
        cfg.addIndividualCacheLoaderConfig(createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.JDBCCacheLoader"));

        mgr.setConfig(cfg, null);
        cl = mgr.getCacheLoader();

        Assert.assertEquals(ChainingCacheLoader.class, cl.getClass());
        Assert.assertEquals(2, ((ChainingCacheLoader) cl).getSize());
        loaders = ((ChainingCacheLoader) cl).getCacheLoaders();
        Assert.assertEquals(FileCacheLoader.class, loaders.get(0).getClass());
        Assert.assertEquals(AsyncCacheLoader.class, loaders.get(1).getClass());
    }

    public void testChainingCacheLoaderFromXml() throws Exception
    {
        // async = false
        String conf = "<config><passivation>false</passivation>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.FileCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.JDBCCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "cache.jdbc.driver=com.mysql.jdbc.Driver\ncache.jdbc.url=jdbc:mysql://localhost/test\ncache.jdbc.user=user\ncache.jdbc.password=pwd" +
                "    </properties>" +
                "</cacheloader></config>";

        CacheLoaderManager mgr = new CacheLoaderManager();
        mgr.setConfig(strToElement(conf), null);
        CacheLoader cl = mgr.getCacheLoader();


        Assert.assertEquals(ChainingCacheLoader.class, cl.getClass());
        Assert.assertEquals(2, ((ChainingCacheLoader) cl).getSize());
        List loaders = ((ChainingCacheLoader) cl).getCacheLoaders();
        Assert.assertEquals(FileCacheLoader.class, loaders.get(0).getClass());
        Assert.assertEquals(JDBCCacheLoader.class, loaders.get(1).getClass());

        // async = true
        conf = "<config>" +
                "<passivation>false</passivation>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.FileCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.JDBCCacheLoader</class>" +
                "    <async>true</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "cache.jdbc.driver=com.mysql.jdbc.Driver\ncache.jdbc.url=jdbc:mysql://localhost/test\ncache.jdbc.user=user\ncache.jdbc.password=pwd"+
                "    </properties>" +
                "</cacheloader></config>";

        mgr.setConfig(strToElement(conf), null);
        cl = mgr.getCacheLoader();

        Assert.assertEquals(ChainingCacheLoader.class, cl.getClass());
        Assert.assertEquals(2, ((ChainingCacheLoader) cl).getSize());
        loaders = ((ChainingCacheLoader) cl).getCacheLoaders();
        Assert.assertEquals(FileCacheLoader.class, loaders.get(0).getClass());
        Assert.assertEquals(AsyncCacheLoader.class, loaders.get(1).getClass());
    }

    public void testMoreThanOneFetchPersistentState() throws Exception
    {
        CacheLoaderManager mgr = new CacheLoaderManager();
        CacheLoaderConfig cfg = createCacheLoaderCfg(false);
        CacheLoaderConfig.IndividualCacheLoaderConfig i = createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader");
        i.setFetchPersistentState(true);
        CacheLoaderConfig.IndividualCacheLoaderConfig i2 = createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader");
        i2.setFetchPersistentState(true);

        cfg.addIndividualCacheLoaderConfig(i);
        cfg.addIndividualCacheLoaderConfig(i2);

        Assert.assertEquals(2, cfg.getIndividualCacheLoaderConfigs().size());

        try
        {
            mgr.setConfig(cfg, null);
            Assert.assertTrue("Should throw exception since we have > 1 cache loader with fetchPersistentState as true", false);
        }
        catch (Exception e)
        {
            Assert.assertTrue(true);
        }

        // control cases which should not throw exceptions
        mgr = new CacheLoaderManager();
        cfg = createCacheLoaderCfg(false);
        i = createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader");
        i.setFetchPersistentState(true);

        cfg.addIndividualCacheLoaderConfig(i);

        Assert.assertEquals(1, cfg.getIndividualCacheLoaderConfigs().size());
        mgr.setConfig(cfg, null);

        // control cases which should not throw exceptions
        mgr = new CacheLoaderManager();
        cfg = createCacheLoaderCfg(false);
        i = createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader");
        i.setFetchPersistentState(true);
        i2 = createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader");
        i2.setFetchPersistentState(false);

        cfg.addIndividualCacheLoaderConfig(i);
        cfg.addIndividualCacheLoaderConfig(i2);

        Assert.assertEquals(2, cfg.getIndividualCacheLoaderConfigs().size());
        mgr.setConfig(cfg, null);

        // control cases which should not throw exceptions
        mgr = new CacheLoaderManager();
        cfg = createCacheLoaderCfg(false);
        i = createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader");
        i.setFetchPersistentState(false);
        i2 = createIndividualCacheLoaderConfig(cfg, true, "org.jboss.cache.loader.FileCacheLoader");
        i2.setFetchPersistentState(false);

        cfg.addIndividualCacheLoaderConfig(i);
        cfg.addIndividualCacheLoaderConfig(i2);

        Assert.assertEquals(2, cfg.getIndividualCacheLoaderConfigs().size());
        mgr.setConfig(cfg, null);
    }

    public void testConfigurationParsing() throws Exception
    {

        String conf = "<config>" +
                "<passivation>false</passivation>" +
                "<preload>/, /blah, /blah2</preload>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.FileCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>true</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.JDBCCacheLoader</class>" +
                "    <async>true</async>" +
                "    <fetchPersistentState>true</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "cache.jdbc.driver=com.mysql.jdbc.Driver\ncache.jdbc.url=jdbc:mysql://localhost/test\ncache.jdbc.user=user\ncache.jdbc.password=pwd" +
                "    </properties>" +
                "</cacheloader></config>";

        CacheLoaderManager mgr = new CacheLoaderManager();
        mgr.setConfig(strToElement(conf), null);

        Assert.assertEquals(ChainingCacheLoader.class, mgr.getCacheLoader().getClass());
        Assert.assertTrue("Should be true", mgr.isFetchPersistentState());
        Assert.assertTrue("Passivation shuld be false", !mgr.isPassivation());
        CacheLoaderConfig c = mgr.getCacheLoaderConfig();
        Assert.assertTrue("Should be using a chaining cache loader", c.useChainingCacheLoader());
        Assert.assertEquals("/, /blah, /blah2", c.getPreload());
        Assert.assertEquals(2, c.getIndividualCacheLoaderConfigs().size());

        CacheLoaderConfig.IndividualCacheLoaderConfig icfg = (CacheLoaderConfig.IndividualCacheLoaderConfig) c.getIndividualCacheLoaderConfigs().get(0);
        Assert.assertEquals("org.jboss.cache.loader.FileCacheLoader", icfg.getClassName());
        Assert.assertTrue("Async shld be false", !icfg.isAsync());
        Assert.assertTrue("fetchPersistentState shld be false", !icfg.isFetchPersistentState());
        Assert.assertTrue("IgnoreMods should be true", icfg.isIgnoreModifications());
        Assert.assertEquals(1, icfg.getProperties().size());

        icfg = (CacheLoaderConfig.IndividualCacheLoaderConfig) c.getIndividualCacheLoaderConfigs().get(1);
        Assert.assertEquals("org.jboss.cache.loader.JDBCCacheLoader", icfg.getClassName());
        Assert.assertTrue("Async shld be true", icfg.isAsync());
        Assert.assertTrue("fetchPersistentState shld be true", icfg.isFetchPersistentState());
        Assert.assertTrue("IgnoreMods should be false", !icfg.isIgnoreModifications());
        Assert.assertEquals(4, icfg.getProperties().size());

        // fetch PersistentState shld be false now
        conf = "<config>" +
                "<passivation>false</passivation>" +
                "<preload>/, /blah, /blah2</preload>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.FileCacheLoader</class>" +
                "    <async>false</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>true</ignoreModifications>" +
                "    <properties>" +
                "        location=" + getTempDir() +
                "    </properties>" +
                "</cacheloader>" +
                "<cacheloader>" +
                "    <class>org.jboss.cache.loader.JDBCCacheLoader</class>" +
                "    <async>true</async>" +
                "    <fetchPersistentState>false</fetchPersistentState>" +
                "    <ignoreModifications>false</ignoreModifications>" +
                "    <properties>" +
                "cache.jdbc.driver=com.mysql.jdbc.Driver\ncache.jdbc.url=jdbc:mysql://localhost/test\ncache.jdbc.user=user\ncache.jdbc.password=pwd" +
                "    </properties>" +
                "</cacheloader></config>";

        mgr = new CacheLoaderManager();
        mgr.setConfig(strToElement(conf), null);

        Assert.assertTrue("Should be false", !mgr.isFetchPersistentState());


    }
    public static Test suite()
    {
        return new TestSuite(CacheLoaderManagerTest.class);
    }

    public static void main(String[] args)
    {
        junit.textui.TestRunner.run(suite());
    }
}
