package org.jboss.cache.jmx;

import org.jboss.cache.Cache;
import org.jboss.cache.CacheFactory;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.config.Configuration;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

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

/**
 * Tests the JMX wrapper class around the cache.
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
 * @author Brian Stansberry
 */
@Test(groups = "functional")
public abstract class CacheJmxWrapperTestBase
{
   public static final String CLUSTER_NAME = "CacheMBeanTest";

   protected Cache<String, String> cache;
   protected CacheJmxWrapperMBean<String, String> jmxWrapper;
   protected MBeanServer mBeanServer;
   protected ObjectName mBeanName;
   protected String mBeanNameStr;

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

      mBeanNameStr = JmxUtil.PREFIX + CLUSTER_NAME;
      mBeanName = new ObjectName(mBeanNameStr);
   }

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

   protected CacheJmxWrapperMBean<String, String> registerWrapper() throws Exception
   {
      if (cache == null)
         cache = createCache(createConfiguration());
      return registerWrapper(cache);
   }

   protected CacheJmxWrapperMBean<String, String> registerWrapper(Cache<String, String> toWrap) throws Exception
   {
      CacheJmxWrapper<String, String> wrapper = new CacheJmxWrapper<String, String>(toWrap);
      return registerWrapper(wrapper);
   }

   protected CacheJmxWrapperMBean<String, String> registerWrapper(Configuration config) throws Exception
   {
      CacheJmxWrapper<String, String> wrapper = new CacheJmxWrapper<String, String>();
      wrapper.setConfiguration(config);
      return registerWrapper(wrapper);
   }

   @SuppressWarnings("unchecked")
   protected CacheJmxWrapperMBean<String, String> registerWrapper(CacheJmxWrapperMBean<String, String> wrapper) throws Exception
   {
      JmxUtil.registerCacheMBean(mBeanServer, wrapper, mBeanNameStr);
      jmxWrapper = (CacheJmxWrapperMBean<String, String>) MBeanServerInvocationHandler.newProxyInstance(mBeanServer, mBeanName, CacheJmxWrapperMBean.class, false);
      return jmxWrapper;
   }

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

   protected CacheJmxWrapper<String, String> createWrapper(Configuration config)
   {
      CacheJmxWrapper<String, String> wrapper = new CacheJmxWrapper<String, String>();
      wrapper.setConfiguration(config);
      return wrapper;
   }

   protected Cache<String, String> createCache(Configuration config)
   {
      CacheFactory<String, String> factory = new DefaultCacheFactory();
      cache = factory.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(mBeanNameStr, 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));
      }
   }
}
