/*
 *
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.replicated;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.TreeCache;
import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.transaction.DummyTransactionManager;

import javax.naming.Context;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.RollbackException;
import java.io.NotSerializableException;
import java.io.Serializable;

/**
 * Teting of replication exception for a Nonerislizable object
 *
 * @version $Revision: 1.3 $
 * @author Ben Wang
 */
public class ReplicationExceptionTest extends TestCase {
   TreeCache cache1, cache2;
   int caching_mode=TreeCache.REPL_SYNC;
   final String group_name="TreeCacheTestGroup";
   String props=
         "UDP(ip_mcast=true;ip_ttl=64;loopback=false;mcast_addr=228.1.2.3;" +
         "mcast_port=45566;mcast_recv_buf_size=80000;mcast_send_buf_size=150000;" +
         "ucast_recv_buf_size=80000;ucast_send_buf_size=150000):" +
         "PING(down_thread=true;num_initial_members=2;timeout=500;up_thread=true):" +
         "MERGE2(max_interval=20000;min_interval=10000):" +
         "FD(down_thread=true;shun=true;up_thread=true):" +
         "VERIFY_SUSPECT(down_thread=true;timeout=1500;up_thread=true):" +
         "pbcast.NAKACK(down_thread=true;gc_lag=50;retransmit_timeout=600,1200,2400,4800;" +
         "up_thread=true):" +
         "pbcast.STABLE(desired_avg_gossip=20000;down_thread=true;up_thread=true):" +
         "UNICAST(down_thread=true;min_threshold=10;timeout=600,1200,2400;window_size=100):" +
         "FRAG(down_thread=true;frag_size=8192;up_thread=true):" +
         "pbcast.GMS(join_retry_timeout=2000;join_timeout=5000;print_local_addr=true;shun=true):" +
         "pbcast.STATE_TRANSFER(down_thread=true;up_thread=true)";

   final static Log log_=LogFactory.getLog(ReplicationExceptionTest.class);
   String old_factory=null;
   final String FACTORY="org.jboss.cache.transaction.DummyContextFactory";
   DummyTransactionManager tx_mgr;
   Throwable t1_ex, t2_ex, ex=null;

   public ReplicationExceptionTest(String name) {
      super(name);
   }

   public void setUp() throws Exception {
      super.setUp();
      old_factory=System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
      System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
      tx_mgr=DummyTransactionManager.getInstance();
      t1_ex=t2_ex=ex=null;
   }

   public void tearDown() throws Exception {
      super.tearDown();
      DummyTransactionManager.destroy();
      destroyCaches();
      if(old_factory != null) {
         System.setProperty(Context.INITIAL_CONTEXT_FACTORY, old_factory);
         old_factory=null;
      }
   }

   Transaction beginTransaction() throws SystemException, NotSupportedException {
      DummyTransactionManager mgr=DummyTransactionManager.getInstance();
      mgr.begin();
      return mgr.getTransaction();
   }

   void initCaches(int caching_mode) throws Exception {
      this.caching_mode=caching_mode;
      cache1=new TreeCache();
      cache2=new TreeCache();
      cache1.setCacheMode(caching_mode);
      cache2.setCacheMode(caching_mode);
      cache1.setIsolationLevel(IsolationLevel.SERIALIZABLE);
      cache2.setIsolationLevel(IsolationLevel.SERIALIZABLE);

      cache1.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
      cache2.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
      /*
      cache1.setTransactionManagerLookupClass("org.jboss.cache.JBossTransactionManagerLookup");
      cache2.setTransactionManagerLookupClass("org.jboss.cache.JBossTransactionManagerLookup");
*/
      cache1.setLockAcquisitionTimeout(5000);
      cache2.setLockAcquisitionTimeout(5000);
      cache1.start();
      cache2.start();
   }

   void destroyCaches() throws Exception {
      if(cache1 != null)
         cache1.stop();
      if(cache2 != null)
         cache2.stop();
      cache1=null;
      cache2=null;
   }

   public void testNonSerializableRepl() throws Exception {
      try {
         initCaches(TreeCache.REPL_SYNC);

         cache1.put("/a/b/c", "test", new ContainerData());

         // We should not come here.
         assertNotNull("NonSerializableData should not be null on cache2", cache2.get("/a/b/c", "test"));
      }
      catch(RuntimeException runtime) {
         Throwable t=runtime.getCause();
         if(t instanceof NotSerializableException) {
            System.out.println("received NotSerializableException - as expected");
         }
         else {
            fail("should have received NotSerializableException, but received " + t.getClass());
         }
      }
      catch(Exception exc) {
         fail("failure - we should not get here: " + exc);
      }
   }

   public void testNonSerizlableReplWithTx() throws Exception {
      Transaction tx;

      try {
         initCaches(TreeCache.REPL_SYNC);

         tx=beginTransaction();
         cache1.put("/a/b/c", "test", new ContainerData());
         tx.commit();

         // We should not come here.
         assertNotNull("NonSerializableData should not be null on cache2", cache2.get("/a/b/c", "test"));
      }
      catch(RollbackException rollback) {
         System.out.println("received RollbackException - as expected");
      }
      catch(Exception e) {
         // We should also examine that it is indeed throwing a NonSerilaizable exception.
         fail(e.toString());
      }
   }

   public static Test suite() throws Exception {
      return new TestSuite(ReplicationExceptionTest.class);
   }


   static class NonSerializabeData
   {
      int i;
   }

   static class ContainerData implements Serializable {
      int i;
      NonSerializabeData non_serializable_data;
      private static final long serialVersionUID = -8322197791060897247L;

      public ContainerData() {
         i=99;
         non_serializable_data=new NonSerializabeData();
      }
   }
}
