package org.jboss.cache.pojo.jmx;

import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.jboss.cache.config.Configuration;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
 * Tests the JMX wrapper class around a PojoCache.
 *
 * @author Brian Stansberry
 */
@Test(groups = {"functional"})
public class PojoCacheJmxWrapperTestBase 
{
   public static final String PC_PREFIX = JmxUtil.POJO_CACHE_DOMAIN + ":" +
                                          JmxUtil.SERVICE_KEY_NAME + "=PojoCacheJmxWrapperTest," +
                                          JmxUtil.CLUSTER_KEY + "=";
   public static final String CLUSTER_NAME = "PojoCacheMBeanTest";

   protected PojoCache cache;
   protected PojoCacheJmxWrapperMBean jmxWrapper;
   protected MBeanServer mBeanServer;
   protected ObjectName mBeanName;
   protected String mBeanNameStr;
   protected ObjectName plainCacheMBeanName;
   protected String plainCacheMBeanNameStr;

   @BeforeMethod(alwaysRun = true)
   protected void setUp() throws Exception
   {
      mBeanServer = MBeanServerFactory.createMBeanServer("PojoCacheMBeanTest");

      mBeanName = new ObjectName(PC_PREFIX + CLUSTER_NAME);
      mBeanNameStr = mBeanName.getCanonicalName();
      plainCacheMBeanName = JmxUtil.getPlainCacheObjectName(mBeanName);
      plainCacheMBeanNameStr = plainCacheMBeanName.getCanonicalName();
   }

   @AfterMethod(alwaysRun = true)
   protected void tearDown() throws Exception
   {
      try
      {
         cleanup();
      }
      finally
      {
         if (mBeanServer != null)
         {
            MBeanServerFactory.releaseMBeanServer(mBeanServer);
            mBeanServer = null;
         }
      }
   }

   protected PojoCacheJmxWrapperMBean registerWrapper() throws Exception
   {
      if (cache == null)
         cache = createCache(createConfiguration());
      return registerWrapper(cache);
   }

   protected PojoCacheJmxWrapperMBean registerWrapper(PojoCache toWrap) throws Exception
   {
      PojoCacheJmxWrapper wrapper = new PojoCacheJmxWrapper(toWrap);
      return registerWrapper(wrapper);
   }

   protected PojoCacheJmxWrapperMBean registerWrapper(Configuration config) throws Exception
   {
      PojoCacheJmxWrapper wrapper = new PojoCacheJmxWrapper();
      wrapper.setConfiguration(config);
      return registerWrapper(wrapper);
   }

   protected PojoCacheJmxWrapperMBean registerWrapper(PojoCacheJmxWrapperMBean wrapper) throws Exception
   {
      JmxUtil.registerPojoCache(mBeanServer, wrapper, mBeanNameStr);
      jmxWrapper = (PojoCacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(mBeanServer, mBeanName, PojoCacheJmxWrapperMBean.class, false);
      return jmxWrapper;
   }

   protected void unregisterWrapper() throws Exception
   {
      mBeanServer.unregisterMBean(mBeanName);
   }

   protected PojoCacheJmxWrapper createWrapper(Configuration config)
   {
      PojoCacheJmxWrapper wrapper = new PojoCacheJmxWrapper();
      wrapper.setConfiguration(config);
      return wrapper;
   }

   protected PojoCache createCache(Configuration config)
   {
      cache = PojoCacheFactory.createCache(config, false);
      return cache;
   }

   protected Configuration createConfiguration()
   {
      Configuration c = new Configuration();
      c.setClusterName(CLUSTER_NAME);
      c.setExposeManagementStatistics(true);
      c.setCacheMode(Configuration.CacheMode.LOCAL);
      return c;
   }

   private void cleanup() throws Exception
   {
      if (cache != null)
      {
         try
         {
            cache.stop();
         }
         catch (Exception ignored)
         {
         }

         cache = null;
      }
      if (jmxWrapper != null)
      {
         try
         {
            jmxWrapper.stop();
            jmxWrapper.destroy();
         }
         catch (Exception ignored)
         {
         }

         jmxWrapper = null;
      }

      if (mBeanServer != null && mBeanName != null && mBeanServer.isRegistered(mBeanName))
         mBeanServer.unregisterMBean(mBeanName);
   }

   protected void interceptorRegistrationTest(boolean expectMbeans) throws MalformedObjectNameException, NullPointerException
   {
      interceptorRegistrationTest(plainCacheMBeanNameStr, expectMbeans);
   }

   protected void interceptorRegistrationTest(String baseName, boolean expectMbeans) throws MalformedObjectNameException, NullPointerException
   {
      // should be 3 interceptor MBeans loaded:
      ObjectName[] interceptorMBeanNames = {
            new ObjectName(baseName + JmxUtil.INTERCEPTOR_KEY + "TxInterceptor"),
            new ObjectName(baseName + JmxUtil.INTERCEPTOR_KEY + "CacheMgmtInterceptor"),
            new ObjectName(baseName + JmxUtil.INTERCEPTOR_KEY + "InvocationContextInterceptor")
      };

      for (ObjectName n : interceptorMBeanNames)
      {
         if (expectMbeans)
            assertTrue(n + " should be registered", mBeanServer.isRegistered(n));
         else
            assertFalse(n + " should not be registered", mBeanServer.isRegistered(n));
      }
   }
}
