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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.transaction.TransactionManager;

import junit.framework.TestCase;

import org.jboss.cache.DummyTransactionManagerLookup;
import org.jboss.cache.TreeCache;
import org.jboss.cache.aop.PojoCache;
import org.jboss.cache.lock.IsolationLevel;

/**
 * @author 
 * @version  
 */
public class PojoCollectionRollbackTest extends TestCase
{

    private static final String ID = "id";
    private static final String CONTAINER_FQN = "/objsIndex";
    
    
   public PojoCollectionRollbackTest(String s)
   {
      super(s);      
   }

   private PojoCache cache;

   protected void setUp() throws Exception
   {
      super.setUp();
   }

    private void startTest() throws Exception {
        cache = new PojoCache();
        cache.setCacheMode(TreeCache.LOCAL);
        cache.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
        cache.setTransactionManagerLookup(new DummyTransactionManagerLookup());
        cache.create();
        cache.start();
    }

   protected void tearDown() throws Exception
   {
      super.tearDown();
      cache.stop();
      cache.destroy();
   }

   public void testNestedMapAndIndexWithModifyRollback() throws Exception
   {
       System.out.println("testNestedMapAndIndexWithModifyRollback");
       startTest();
       
       // create cached data objects
       Map obj1 = new HashMap();
       obj1.put(ID, "1");
       cache.putObject("/objs/1", obj1);
       obj1 = (Map) cache.getObject("/objs/1");
       
       // create cached collection of data objects
       // initialize collection by adding a data object
       Map indexMap = null;
       final String KEY = "KEY";
       Object beforeModify;
       Object afterRollback;

       indexMap = new HashMap();
       cache.putObject(CONTAINER_FQN, indexMap);
       indexMap = (Map) cache.getObject(CONTAINER_FQN);
       indexMap.put(KEY, obj1);
       
       beforeModify = indexMap.get(KEY);
       Object idBeforeModify = ((Map)beforeModify).get(ID);
       
       System.out.println("beforeModify: " + beforeModify + ", data object id: " + ((Map)beforeModify).get(ID));

       // modify the collection by replacing the first data object with the second
       // and then roll-back the transaction
       TransactionManager tm = cache.getTransactionManager();
       tm.begin();

       obj1.put(ID, "newID");
       indexMap.remove(KEY);
       tm.rollback();
       
       indexMap = (Map) cache.getObject(CONTAINER_FQN);
       afterRollback = indexMap.get(KEY);
       System.out.println("afterRollback: " + afterRollback + ", data object id: " + ((Map)afterRollback).get(ID));

       // check if state of collection was restored
       assertEquals(beforeModify, afterRollback);
       assertTrue(beforeModify == afterRollback);
       assertEquals(1, indexMap.size());
       
       assertEquals("1", obj1.get(ID));
       Object idAfterRollback = ((Map)afterRollback).get(ID);
       System.out.println("idBeforeModify: " + idBeforeModify + " idAfterRollback: " + idAfterRollback);
       assertEquals(idBeforeModify, idAfterRollback);
   }

   public void testNestedMapWithModifyRollback() throws Exception
   {
       System.out.println("testNestedMapWithModifyRollback");
       startTest();
       
       // create cached data objects
       Map obj1 = new HashMap();
       obj1.put(ID, "1");
       cache.putObject("/objs/1", obj1);
       obj1 = (Map) cache.getObject("/objs/1");
       
       Map obj2 = new HashMap();
       obj2.put(ID, "2");
       cache.putObject("/objs/2", obj2);
       obj2 = (Map) cache.getObject("/objs/2");

       // create cached collection of data objects
       // initialize collection by adding a data object
       Map indexMap = null;
       final String KEY = "KEY";
       Object beforeModify;
       Object afterRollback;

       indexMap = new HashMap();
       cache.putObject(CONTAINER_FQN, indexMap);
       indexMap = (Map) cache.getObject(CONTAINER_FQN);
       indexMap.put(KEY, obj1);
       beforeModify = indexMap.get(KEY);
       
       System.out.println("beforeModify: " + beforeModify + ", data object id: " + ((Map)beforeModify).get(ID));
       
       // modify the collection by replacing the first data object with the second
       // and then roll-back the transaction
       TransactionManager tm = cache.getTransactionManager();
       tm.begin();
       Object removedByModify = indexMap.put(KEY, obj2);
       System.out.println("removedByModify: " + removedByModify + ", data object id: " + ((Map)removedByModify).get(ID));
       assertEquals(removedByModify, beforeModify);
       tm.rollback();
       
       indexMap = (Map) cache.getObject(CONTAINER_FQN);
       afterRollback = indexMap.get(KEY);
       System.out.println("afterRollback: " + afterRollback + ", data object id: " + ((Map)afterRollback).get(ID));
       
       // check if state of collection was restored
       assertEquals(beforeModify, afterRollback);
       assertEquals(1, indexMap.size());
       // check that map entry can now be modified
       indexMap.put(KEY, obj2);
       assertEquals(obj2, indexMap.get(KEY));
   }

   public void testNestedMapWithRemoveRollback() throws Exception
   {
       System.out.println("testNestedMapWithRemoveRollback");
       startTest();

       // create cached data objects
       Map obj1 = new HashMap();
       obj1.put(ID, "1");
       cache.putObject("/objs/1", obj1);
       obj1 = (Map) cache.getObject("/objs/1");
       
       Map obj2 = new HashMap();
       obj2.put(ID, "2");
       cache.putObject("/objs/2", obj2);
       obj2 = (Map) cache.getObject("/objs/2");

       // create cached collection of data objects
       Map indexMap = new HashMap();
       cache.putObject(CONTAINER_FQN, indexMap);
       indexMap = (Map) cache.getObject(CONTAINER_FQN);

       // initialize collection by adding a data object
       final String KEY = "KEY";
       indexMap.put(KEY, obj1);
       
       Object beforeModify = indexMap.get(KEY);
       System.out.println("beforeModify: " + beforeModify + ", data object id: " + ((Map)beforeModify).get(ID));

       // modify the collection by replacing the first data object with the second
       // and then roll-back the transaction
       TransactionManager tm = cache.getTransactionManager();
       tm.begin();
       Object removedByRemove = indexMap.remove(KEY);
       System.out.println("removedByRemove: " + removedByRemove + ", data object id: " + ((Map)removedByRemove).get(ID));
       assertEquals(beforeModify, removedByRemove);
       tm.rollback();
       
       Object afterRollback = indexMap.get(KEY);
       System.out.println("afterRollback: " + afterRollback + ", data object id: " + ((Map)afterRollback).get(ID));
       
       // check if state of collection was restored
       assertEquals(beforeModify, afterRollback);
       assertEquals(1, indexMap.size());

       // check that map entry can now be modified
       indexMap.put(KEY, obj2);
       assertEquals(obj2, indexMap.get(KEY));
   }

   public void testNestedListWithModifyAddRollback() throws Exception
   {
       System.out.println("testNestedListWithModifyAddRollback");
       startTest();

       // create cached data objects
       Map obj1 = new HashMap();
       obj1.put(ID, "1");
       cache.putObject("/objs/1", obj1);
       obj1 = (Map) cache.getObject("/objs/1");
       
       Map obj2 = new HashMap();
       obj2.put(ID, "2");
       cache.putObject("/objs/2", obj2);
       obj2 = (Map) cache.getObject("/objs/2");
       assertFalse(obj1.equals(obj2));

       // create cached collection of data objects
       List indexList = new ArrayList();
       cache.putObject(CONTAINER_FQN, indexList);
       indexList = (List) cache.getObject(CONTAINER_FQN);

       // initialize collection by adding a data object
       indexList.add(obj1);
       
       Object beforeModify = indexList.get(0);
       System.out.println("beforeModify: " + beforeModify + ", data object id: " + ((Map)beforeModify).get(ID));
       int objIndex1, objIndex2;

       // modify the collection by replacing the first data object with the second
       // and then roll-back the transaction
       TransactionManager tm = cache.getTransactionManager();
       tm.begin();
       indexList.add(obj2);
       objIndex1 = indexList.indexOf(obj1);
       objIndex2 = indexList.indexOf(obj2);
       tm.rollback();
       
       // before rollback - object set
       assertFalse(obj1.equals(obj2));
       assertEquals(0, objIndex1);
       assertEquals(1, objIndex2);
       
       Object afterRollback = indexList.get(0);
       System.out.println("afterRollback: " + afterRollback + ", data object id: " + ((Map)afterRollback).get(ID));
       
       // check if state of collection was restored
       assertEquals(beforeModify, afterRollback);
       assertEquals(1, indexList.size());

       // check that list entry can now be modified
       indexList.set(0, obj2);
       assertEquals(obj2, indexList.get(0));
   }

   public void testNestedListWithModifySetRollback() throws Exception
   {
       System.out.println("testNestedListWithModifySetRollback");
       startTest();

       // create cached data objects
       Map obj1 = new HashMap();
       obj1.put(ID, "1");
       cache.putObject("/objs/1", obj1);
       obj1 = (Map) cache.getObject("/objs/1");
       
       Map obj2 = new HashMap();
       obj2.put(ID, "2");
       cache.putObject("/objs/2", obj2);
       obj2 = (Map) cache.getObject("/objs/2");

       // create cached collection of data objects
       List indexList = new ArrayList();
       cache.putObject(CONTAINER_FQN, indexList);
       indexList = (List) cache.getObject(CONTAINER_FQN);

       // initialize collection by adding a data object
       indexList.add(obj1);
       
       Object beforeModify = indexList.get(0);
       System.out.println("beforeModify: " + beforeModify + ", data object id: " + ((Map)beforeModify).get(ID));
       int objIndex;

       // modify the collection by replacing the first data object with the second
       // and then roll-back the transaction
       TransactionManager tm = cache.getTransactionManager();
       tm.begin();
       Object removedBySet = indexList.set(0, obj2);
       System.out.println("removedBySet: " +removedBySet + ", data object id: " + ((Map)removedBySet).get(ID));
       assertEquals(beforeModify, removedBySet);
       objIndex = indexList.indexOf(obj2);
       tm.rollback();
       
       // before rollback - object set
       assertEquals(0, objIndex);
       
       Object afterRollback = indexList.get(0);
       System.out.println("afterRollback: " + afterRollback + ", data object id: " + ((Map)afterRollback).get(ID));
       
       // check if state of collection was restored
       assertEquals(beforeModify, afterRollback);
       assertEquals(1, indexList.size());

       // check that list entry can now be modified
       indexList.set(0, obj2);
       assertEquals(obj2, indexList.get(0));
   }

   public void testNestedListWithRemoveRollback() throws Exception
   {
       System.out.println("testNestedListWithRemoveRollback");
       startTest();

       // create cached data objects
       Map obj1 = new HashMap();
       obj1.put(ID, "1");
       cache.putObject("/objs/1", obj1);
       obj1 = (Map) cache.getObject("/objs/1");
       
       Map obj2 = new HashMap();
       obj2.put(ID, "2");
       cache.putObject("/objs/2", obj2);
       obj2 = (Map) cache.getObject("/objs/2");

       // create cached collection of data objects
       List indexList = new ArrayList();
       cache.putObject(CONTAINER_FQN, indexList);
       indexList = (List) cache.getObject(CONTAINER_FQN);

       // initialize collection by adding a data object
       indexList.add(obj1);
       
       Object beforeModify = indexList.get(0);
       System.out.println("beforeModify: " + beforeModify + ", data object id: " + ((Map)beforeModify).get(ID));
       int objIndex;
       
       // modify the collection by replacing the first data object with the second
       // and then roll-back the transaction
       TransactionManager tm = cache.getTransactionManager();
       tm.begin();
       indexList.remove(obj1);
       objIndex = indexList.indexOf(obj1);
       tm.rollback();
       
       // before rollback - object removed
       assertEquals(-1, objIndex);
       
       Object afterRollback = indexList.get(0);
       System.out.println("afterRollback: " + afterRollback + ", data object id: " + ((Map)afterRollback).get(ID));
       
       // check if state of collection was restored
       assertEquals(beforeModify, afterRollback);
       assertEquals(1, indexList.size());

       // check that list entry can now be modified
       indexList.set(0, obj2);
       assertEquals(obj2, indexList.get(0));
   }


}
