/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.cache.passivation;

import org.jboss.cache.CacheFactory;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.factories.XmlConfigurationParser;
import org.jboss.cache.loader.DummyInMemoryCacheLoader;
import org.jboss.cache.util.TestingUtil;
import org.jboss.cache.notifications.annotation.CacheListener;
import org.jboss.cache.notifications.annotation.NodeActivated;
import org.jboss.cache.notifications.annotation.NodePassivated;
import org.jboss.cache.notifications.event.Event;
import org.jboss.cache.notifications.event.NodeEvent;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
 * @author Ben Wang
 * @version $Revision: 5906 $
 */
@Test(groups = {"functional"})
public class BasicPassivationTest
{
   CacheSPI cache;
   int wakeupIntervalMillis_ = 0;
   final String ROOT_STR = "/test";
   Throwable t1_ex, t2_ex;
   final long DURATION = 10000;
   boolean isTrue;
   final String FQNSTR = "/org/jboss/3";
   int activationCount = 0;
   int passivationCount = 0;

   @BeforeMethod(alwaysRun = true)
   public void setUp() throws Exception
   {
      initCaches();
      wakeupIntervalMillis_ = cache.getConfiguration().getEvictionConfig().getWakeupIntervalSeconds() * 1000;
      log("wakeupInterval is " + wakeupIntervalMillis_);
      if (wakeupIntervalMillis_ < 0)
      {
         fail("testEviction(): eviction thread wake up interval is illegal " + wakeupIntervalMillis_);
      }

      t1_ex = t2_ex = null;
      isTrue = true;
   }

   private void initCaches()
   {
      CacheFactory<String, String> instance = new DefaultCacheFactory<String, String>();
      cache = (CacheSPI) instance.createCache(new XmlConfigurationParser().parseFile("META-INF/conf-test/local-passivation-service.xml"), false);
      cache.getConfiguration().setTransactionManagerLookupClass("org.jboss.cache.transaction.DummyTransactionManagerLookup");
      Object listener = new TestCacheListener();
      cache.getConfiguration().getCacheLoaderConfig().getFirstCacheLoaderConfig().setClassName(DummyInMemoryCacheLoader.class.getName());
      cache.start();
      cache.getNotifier().addCacheListener(listener);
   }

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

   public void testBasic()
   {
      activationCount = 0;
      passivationCount = 0;

      cache.put(FQNSTR, FQNSTR, FQNSTR);

      System.out.println(cache.toString());
      TestingUtil.sleepThread(2100);
      System.out.println(cache.toString());

      assert !(cache.exists(FQNSTR) && cache.getNode(FQNSTR).getKeys().contains(FQNSTR)) : "Should have been evicted!!";
      Object val = cache.get(FQNSTR, FQNSTR);
      assertNotNull("DataNode should not be empty ", val);

      assertEquals("activation count:", 1, activationCount);
      assertEquals("passivation count:", 1, passivationCount);
   }

   public void testDualPassivation() throws Exception
   {
      Fqn fqn = Fqn.fromString(FQNSTR);
      cache.put(fqn, "key", "value");
      cache.evict(fqn);
      cache.evict(fqn);
      assertEquals("Proper value after 2 passivations", "value", cache.get(fqn, "key"));
   }

   public void testIntermingledPassivation() throws Exception
   {
      Fqn fqn = Fqn.fromString(FQNSTR);
      cache.put(fqn, "key1", "value");
      cache.evict(fqn);
      cache.put(fqn, "key2", "value");
      cache.evict(fqn);
      assertEquals("Proper value after 2 passivations", "value", cache.get(fqn, "key1"));

   }

   private void log(String msg)
   {
      System.out.println("-- " + msg);
   }

   @CacheListener
   public class TestCacheListener
   {
      @SuppressWarnings("unchecked")
      @NodeActivated
      @NodePassivated
      public void callback(NodeEvent ne)
      {
         if (ne.isPre())
            return;// we are not interested in postActivate event
         if (!ne.getFqn().isChildOrEquals(Fqn.fromString(FQNSTR)))
            return;// don't care about fqn that doesn't belong to me.

         log("got event " + ne);
         if (ne.getType() == Event.Type.NODE_ACTIVATED)
            activationCount++;
         else if (ne.getType() == Event.Type.NODE_PASSIVATED)
            passivationCount++;
      }
   }
}
