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

package org.jboss.cache.pojo.notification;

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;

import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheFactory;
import org.jboss.cache.pojo.notification.event.AttachedEvent;
import org.jboss.cache.pojo.notification.event.DetachedEvent;
import org.jboss.cache.pojo.notification.event.Event;
import org.jboss.cache.pojo.notification.event.FieldModifiedEvent;
import org.jboss.cache.pojo.test.Address;
import org.jboss.cache.pojo.test.Person;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

// $Id: ObjectTest.java 4699 2007-10-26 18:31:15Z jason.greene@jboss.com $

/**
 * Tests attach, detach, and field modify notifications
 *
 * @author Jason T. Greene
 */
@Test(groups = {"functional"})
public class ObjectTest
{
   protected PojoCache cache;
   protected Listener listener;


   @BeforeMethod(alwaysRun = true)
   protected void setUp() throws Exception
   {
      String configFile = "META-INF/local-service.xml";
      boolean toStart = false;
      cache = PojoCacheFactory.createCache(configFile, toStart);
      cache.start();

      listener = new Listener();
      cache.addListener(listener);
   }

   private <T extends Event> T takeNotification(Class<T> clazz)
   {
      T notification = listener.take(clazz);
      verifyNotification(notification);

      return notification;
   }

   protected void verifyNotification(Event notification)
   {
      assertSame(cache, notification.getContext().getPojoCache());
      assertEquals(true, notification.isLocal());
   }



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

   public void testAttachNotification() throws Exception
   {
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      cache.attach("/a", test);
      AttachedEvent attach = takeNotification(AttachedEvent.class);
      assertEquals(test, attach.getSource());
   }

   public void testAttachNotification2() throws Exception
   {
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      Address addr = new Address();
      test.setAddress(addr);
      cache.attach("/a", test);

      // Address Attach
      AttachedEvent attach = takeNotification(AttachedEvent.class);
      assertEquals(addr, attach.getSource());

      // Person Attach
      attach = takeNotification(AttachedEvent.class);
      assertEquals(test, attach.getSource());
   }

   public void testDetachNotification() throws Exception
   {
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      cache.attach("/a", test);

      // Person Attach
      AttachedEvent attach = takeNotification(AttachedEvent.class);
      Object attached = attach.getSource();
      assertEquals(test, attached);

      cache.detach("/a");

      // Person Detach
      DetachedEvent detach = takeNotification(DetachedEvent.class);
      assertSame(attached, detach.getSource());
   }

   public void testFieldNotification() throws Exception
   {
      Person test = new Person();
      test.setName("Ben");
      test.setAge(10);
      cache.attach("/a", test);

      // Person Attach
      AttachedEvent attach = takeNotification(AttachedEvent.class);
      assertEquals(test, attach.getSource());

      // Field modification
      test.setAge(20);
      FieldModifiedEvent modify = takeNotification(FieldModifiedEvent.class);
      assertEquals(test, modify.getSource());
      assertEquals(test.getClass().getDeclaredField("age"), modify.getField());
      assertEquals(20, modify.getValue());

      // Object Field Modification
      Address addr = new Address();
      addr.setCity("Madison");
      addr.setStreet("State St.");
      addr.setZip(53703);
      test.setAddress(addr);

      // First Attach
      attach = takeNotification(AttachedEvent.class);
      assertEquals(addr, attach.getSource());

      // Then Modify
      modify = takeNotification(FieldModifiedEvent.class);
      assertEquals(test, modify.getSource());
      assertEquals(test.getClass().getDeclaredField("address"), modify.getField());
      assertEquals(addr, modify.getValue());
   }
}