/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package test.compliance.server;

import java.util.ArrayList;

import javax.management.MBeanNotificationInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MBeanServerInvocationHandler;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;

import junit.framework.TestCase;
import test.compliance.server.support.BroadcasterInvocationHandlerTest;
import test.compliance.server.support.EmitterInvocationHandlerTest;
import test.compliance.server.support.InvocationHandlerTest;
import test.compliance.server.support.InvocationHandlerTestMBean;
import test.compliance.server.support.ObjectInvocationHandlerTest;

/**
 * Tests the MBeanServerInvocationHandler
 *
 * @author  <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
 */
public class MBeanServerInvocationHandlerTestCase
   extends TestCase
   implements NotificationListener
{
   // Attributes ----------------------------------------------------------------

   private ObjectName invocationHandlerTestName;

   private ArrayList messages = new ArrayList();

   // Constructor ---------------------------------------------------------------

   /**
    * Construct the test
    */
   public MBeanServerInvocationHandlerTestCase(String s)
   {
      super(s);

      try
      {
         invocationHandlerTestName = new ObjectName("MBeanServerInvocationHandlerTestCase:type=InvocationHandlerTest");
      }
      catch (Exception e)
      {
         throw new RuntimeException(e.toString());
      }
   }

   // Tests ---------------------------------------------------------------------

   public void testConstructor()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
   }

   public void testGetter()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);

      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);
      assertEquals("Attribute", proxy.getAttribute());
   }

   public void testSetter()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      proxy.setAttribute("Changed");
      assertEquals("Changed", test.getAttribute());
   }

   public void testGetterPrimitiveBoolean()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);

      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      assertEquals(false, test.isIsPrimitive());
      test.setIsPrimitive(true);

      assertEquals(true, proxy.isIsPrimitive());
   }

   public void testSetterPrimitiveBoolean()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      assertEquals(false, test.isIsPrimitive());
      proxy.setIsPrimitive(true);

      assertEquals(true, test.isIsPrimitive());
   }

   public void testGetterTypeBoolean()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);

      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      assertEquals(null, test.isIsType());
      test.setIsType(new Boolean(true));

      assertEquals(true, proxy.isIsType().booleanValue());
   }

   public void testSetterTypeBoolean()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      assertEquals(null, test.isIsType());
      proxy.setIsType(new Boolean(true));

      assertEquals(true, test.isIsType().booleanValue());
   }

   public void testInvokeNoArgsNoReturn()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      proxy.invokeNoArgsNoReturn();
      assertTrue(test.invokeNoArgsNoReturnInvoked);
   }

   public void testInvokeNoArgs()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      assertEquals("invokeNoArgs", proxy.invokeNoArgs());
   }

   public void testInvoke()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      assertEquals("parameter", proxy.invoke("parameter"));
   }

   public void testInvokeMixedParameters()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, false);

      Integer parameter = new Integer(20);
      assertEquals(parameter, proxy.invokeMixedParameters("parameter", 10, parameter));
   }

   public void testNotificationEmitterAdd()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      EmitterInvocationHandlerTest test = new EmitterInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      NotificationEmitter proxy = (NotificationEmitter) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      proxy.addNotificationListener(this, null, null);

      messages.clear();
      test.sendNotification();
      assertTrue(messages.size() == 1);
   }

   public void testNotificationEmitterRemove()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      EmitterInvocationHandlerTest test = new EmitterInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      NotificationEmitter proxy = (NotificationEmitter) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      proxy.addNotificationListener(this, null, null);

      messages.clear();
      test.sendNotification();
      assertTrue(messages.size() == 1);

      proxy.removeNotificationListener(this);

      messages.clear();
      test.sendNotification();
      assertTrue(messages.size() == 0);
   }

   public void testNotificationEmitterRemoveTriplet()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      EmitterInvocationHandlerTest test = new EmitterInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      NotificationEmitter proxy = (NotificationEmitter) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      NotificationFilterSupport filter = new NotificationFilterSupport();
      filter.enableType("test");
      Object handback = new Object();
      proxy.addNotificationListener(this, filter, handback);

      messages.clear();
      test.sendNotification();
      assertTrue(messages.size() == 1);

      proxy.removeNotificationListener(this, filter, handback);

      messages.clear();
      test.sendNotification();
      assertTrue(messages.size() == 0);
   }

   public void testNotificationEmitterRemoveTripletFailsOnBroadcaster()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      BroadcasterInvocationHandlerTest test = new BroadcasterInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      NotificationEmitter proxy = (NotificationEmitter) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      NotificationFilterSupport filter = new NotificationFilterSupport();
      filter.enableType("test");
      Object handback = new Object();
      proxy.addNotificationListener(this, filter, handback);

      messages.clear();
      test.sendNotification();
      assertTrue(messages.size() == 1);

      try
      {
         proxy.removeNotificationListener(this, filter, handback);
         fail("removeNotificationListener(NotificationListener, NotificationFilter, Object) " +
              "should not work for a broadcaster");
      }
      catch (Exception ignored)
      {
      }
   }

   public void testGetNotificationInfo()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      EmitterInvocationHandlerTest test = new EmitterInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      NotificationEmitter proxy = (NotificationEmitter) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      MBeanNotificationInfo[] info = proxy.getNotificationInfo();
      assertEquals("test", info[0].getNotifTypes()[0]);
   }

   public void testToString()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      ObjectInvocationHandlerTest test = new ObjectInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      assertEquals("TOSTRING", proxy.toString());
   }

   public void testToStringFailsWhenNotExposed()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      try
      {
         proxy.toString();
         fail("toString() should not work when it is not exposed for management");
      }
      catch (Exception ignored)
      {
      }
   }

   public void testEquals()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      ObjectInvocationHandlerTest test = new ObjectInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      assertTrue(proxy.equals(new Object()));
   }

   public void testEqualsFailsWhenNotExposed()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      try
      {
         proxy.equals(new Object());
         fail("equals(Object) should not work when it is not exposed for management");
      }
      catch (Exception ignored)
      {
      }
   }

   public void testHashCode()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      ObjectInvocationHandlerTest test = new ObjectInvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      assertEquals(1234, proxy.hashCode());
   }

   public void testHashCodeFailsWhenNotExposed()
      throws Exception
   {
      MBeanServer server = MBeanServerFactory.newMBeanServer();
      InvocationHandlerTest test = new InvocationHandlerTest();
      server.registerMBean(test, invocationHandlerTestName);
      InvocationHandlerTestMBean proxy = (InvocationHandlerTestMBean) MBeanServerInvocationHandler.newProxyInstance(
         server, invocationHandlerTestName, InvocationHandlerTestMBean.class, true);

      try
      {
         proxy.hashCode();
         fail("hashCode() should not work when it is not exposed for management");
      }
      catch (Exception ignored)
      {
      }
   }

   // Notification Listener -----------------------------------------------------

   public void handleNotification(Notification notification, Object handback)
   {
      messages.add(notification);
   }
}