package org.jboss.cache.loader;

import org.jboss.cache.Cache;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.util.TestingUtil;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
import org.jboss.cache.factories.XmlConfigurationParser;
import org.jboss.cache.jmx.CacheJmxWrapper;
import org.jboss.cache.loader.tcp.TcpCacheServer;
import org.jboss.cache.xml.XmlHelper;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
import org.w3c.dom.Element;

import java.net.UnknownHostException;

/**
 * Tests various ways of setting up the TcpCacheServer
 *
 * @author Brian Stansberry
 * @version $Id: TcpCacheServerTest.java 5906 2008-05-29 07:24:18Z mircea.markus $
 */
@Test(groups = {"functional"})
public class TcpCacheServerTest
{
   static TcpCacheServer cache_server = null;

   private CacheSPI<Object, Object> cache;
   private CacheLoader loader;

   static
   {
      Runtime.getRuntime().addShutdownHook(new Thread()
      {
         public void run()
         {
            if (cache_server != null)
            {
               System.out.println("Stopping TcpCacheServer");
               cache_server.stop();
            }
         }
      });
   }

   private void createCacheAndLoader() throws Exception
   {
      Configuration c = new Configuration();
      c.setCacheMode(Configuration.CacheMode.LOCAL);
      c.setTransactionManagerLookupClass("org.jboss.cache.transaction.DummyTransactionManagerLookup");
      c.setCacheLoaderConfig(getCacheLoaderConfig());
      cache = (CacheSPI<Object, Object>) new DefaultCacheFactory().createCache(c);

      cache.start();
      loader = cache.getCacheLoaderManager().getCacheLoader();
   }

   protected CacheLoaderConfig getCacheLoaderConfig() throws Exception
   {
      String xml = "<config>\n" +
            "<passivation>false</passivation>\n" +
            "<preload></preload>\n" +
            "<cacheloader>\n" +
            "<class>org.jboss.cache.loader.TcpDelegatingCacheLoader</class>\n" +
            "<properties>host=127.0.0.1\nport=12121</properties>\n" +
            "<async>false</async>\n" +
            "<shared>true</shared>\n" +
            "<fetchPersistentState>true</fetchPersistentState>\n" +
            "<purgeOnStartup>false</purgeOnStartup>\n" +
            "</cacheloader>\n" +
            "</config>";
      Element element = XmlHelper.stringToElement(xml);
      return XmlConfigurationParser.parseCacheLoaderConfig(element);
   }

   @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
      if (cache != null)
      {
         cache.stop();
         cache.destroy();
         cache = null;
      }

      if (cache_server != null)
      {
         System.out.println("Stopping TcpCacheServer");
         cache_server.stop();
         cache_server = null;
      }
   }


   private static void createTcpCacheServer() throws UnknownHostException
   {
      cache_server = new TcpCacheServer();
      cache_server.setBindAddress("127.0.0.1");
      cache_server.setPort(12121);
   }

   private void startTcpCacheServer()
   {
      Thread runner = new Thread()
      {
         public void run()
         {
            try
            {
               System.out.println("Starting TcpCacheServer");
               cache_server.create();
               cache_server.start();
            }
            catch (Exception ex)
            {
               ex.printStackTrace();
            }
         }
      };

      runner.setDaemon(true);
      runner.start();

      // give the tcp cache server time to start up
      TestingUtil.sleepThread(2000);
   }

   public void testInjectConfigFilePath() throws Exception
   {
      createTcpCacheServer();
      Configuration conf = UnitTestCacheConfigurationFactory.createConfiguration(Configuration.CacheMode.LOCAL, true);
      CacheSPI cacheSPI = (CacheSPI) new DefaultCacheFactory().createCache(conf);
      cache_server.setCache(cacheSPI);
      startTcpCacheServer();
      createCacheAndLoader();
      cacheCheck();
      usabilityCheck();
   }

   public void testInjectCache() throws Exception
   {
      createTcpCacheServer();
      Configuration conf = UnitTestCacheConfigurationFactory.createConfiguration(Configuration.CacheMode.LOCAL, true);
      CacheSPI cacheSPI = (CacheSPI) new DefaultCacheFactory().createCache(conf);
      cache_server.setCache(cacheSPI);
      startTcpCacheServer();
      createCacheAndLoader();
      cacheCheck();
      usabilityCheck();
   }

   public void testInjectCacheJmxWrapper() throws Exception
   {
      createTcpCacheServer();
      Configuration conf = UnitTestCacheConfigurationFactory.createConfiguration(Configuration.CacheMode.LOCAL, true);
      CacheSPI cacheSPI = (CacheSPI) new DefaultCacheFactory().createCache(conf);
      CacheJmxWrapper wrapper = new CacheJmxWrapper<Object, Object>(cacheSPI);
      wrapper.start();
      cache_server.setCacheJmxWrapper(wrapper);
      startTcpCacheServer();
      createCacheAndLoader();
      cacheCheck();
      usabilityCheck();
   }

   private void cacheCheck()
   {
      Cache c = cache_server.getCache();
      assertNotNull("Cache exists", c);
      Configuration config = c.getConfiguration();
      // check a couple properties
      assertEquals("Correct mode", Configuration.CacheMode.LOCAL, config.getCacheMode());
      assertEquals("Correct cluster name", "JBossCache-Cluster", config.getClusterName());
   }

   private void usabilityCheck() throws Exception
   {
      Fqn<String> fqn = Fqn.fromString("/key");
      assertFalse("Fqn does not exist in loader", loader.exists(fqn));

      /* put(Fqn,Object,Object) and get(Fqn,Object) */
      Object oldVal;
      oldVal = loader.put(fqn, "one", "two");
      assertNull("oldVal is null", oldVal);

      assertEquals("Got value from cache", "two", cache.get(fqn, "one"));
   }

}