[infinispan-commits] Infinispan SVN: r916 - in trunk/core/src: main/java/org/infinispan/jmx and 2 other directories.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Tue Oct 6 03:17:20 EDT 2009


Author: galder.zamarreno at jboss.com
Date: 2009-10-06 03:17:20 -0400 (Tue, 06 Oct 2009)
New Revision: 916

Added:
   trunk/core/src/main/java/org/infinispan/jmx/AbstractJmxRegistration.java
   trunk/core/src/test/java/org/infinispan/jmx/CacheMBeanTest.java
Modified:
   trunk/core/src/main/java/org/infinispan/CacheDelegate.java
   trunk/core/src/main/java/org/infinispan/jmx/CacheJmxRegistration.java
   trunk/core/src/main/java/org/infinispan/jmx/CacheManagerJmxRegistration.java
   trunk/core/src/main/java/org/infinispan/jmx/ComponentsJmxRegistration.java
   trunk/core/src/main/java/org/infinispan/manager/DefaultCacheManager.java
   trunk/core/src/test/java/org/infinispan/jmx/CacheManagerMBeanTest.java
   trunk/core/src/test/java/org/infinispan/jmx/JmxStatsFunctionalTest.java
Log:
[ISPN-118] (Expose CacheManager to be accessible as an MBean) Cache start/stop methods are now exposed as MBean methods as well as its status. CacheManager also exposed number of running caches. Cache MBean is only removed from JMX when CacheManager is stopped to enable cache restarts from JMX.

Modified: trunk/core/src/main/java/org/infinispan/CacheDelegate.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/CacheDelegate.java	2009-10-05 23:47:15 UTC (rev 915)
+++ trunk/core/src/main/java/org/infinispan/CacheDelegate.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -48,6 +48,9 @@
 import org.infinispan.factories.annotations.NonVolatile;
 import org.infinispan.interceptors.InterceptorChain;
 import org.infinispan.interceptors.base.CommandInterceptor;
+import org.infinispan.jmx.annotations.MBean;
+import org.infinispan.jmx.annotations.ManagedAttribute;
+import org.infinispan.jmx.annotations.ManagedOperation;
 import org.infinispan.lifecycle.ComponentStatus;
 import org.infinispan.manager.CacheManager;
 import org.infinispan.marshall.MarshalledValue;
@@ -79,7 +82,9 @@
  * @since 4.0
  */
 @NonVolatile
+ at MBean(objectName = CacheDelegate.OBJECT_NAME, description = "Component that acts as a manager, factory and container for caches in the system.")
 public class CacheDelegate<K, V> implements AdvancedCache<K, V> {
+   public static final String OBJECT_NAME = "Cache";
    protected InvocationContextContainer icc;
    protected CommandsFactory commandsFactory;
    protected InterceptorChain invoker;
@@ -245,12 +250,14 @@
       invoker.invoke(getInvocationContext(), command);
    }
 
+   @ManagedOperation(description = "Starts the cache.")
    public void start() {
       componentRegistry.start();
       defaultLifespan = config.getExpirationLifespan();
       defaultMaxIdleTime = config.getExpirationMaxIdle();
    }
 
+   @ManagedOperation(description = "Stops the cache.")
    public void stop() {
       componentRegistry.stop();
    }
@@ -485,6 +492,7 @@
       return (V) invoker.invoke(ctx, command);
    }
 
+   @ManagedAttribute(description = "Returns the cache status")
    public ComponentStatus getStatus() {
       return componentRegistry.getStatus();
    }

Added: trunk/core/src/main/java/org/infinispan/jmx/AbstractJmxRegistration.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/jmx/AbstractJmxRegistration.java	                        (rev 0)
+++ trunk/core/src/main/java/org/infinispan/jmx/AbstractJmxRegistration.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -0,0 +1,89 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.jmx;
+
+import java.util.Set;
+
+import javax.management.MBeanServer;
+
+import org.infinispan.CacheException;
+import org.infinispan.config.GlobalConfiguration;
+import org.infinispan.factories.AbstractComponentRegistry;
+import org.infinispan.util.Util;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * Parent class for top level JMX component registration.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public abstract class AbstractJmxRegistration {
+   private static final Log log = LogFactory.getLog(AbstractJmxRegistration.class);
+   String jmxDomain;
+   MBeanServer mBeanServer;
+   GlobalConfiguration globalConfig;
+   
+   protected abstract ComponentsJmxRegistration buildRegistrator(Set<AbstractComponentRegistry.Component> components);
+   
+   protected void registerMBeans(Set<AbstractComponentRegistry.Component> components, GlobalConfiguration globalConfig) {
+      mBeanServer = getMBeanServer(globalConfig);
+      ComponentsJmxRegistration registrator = buildRegistrator(components);
+      registrator.registerMBeans();
+   }
+   
+   protected void unregisterMBeans(Set<AbstractComponentRegistry.Component> components) {
+      ComponentsJmxRegistration registrator = buildRegistrator(components);
+      registrator.unregisterMBeans();
+   }
+   
+   protected MBeanServer getMBeanServer(GlobalConfiguration configuration) {
+      String serverLookup = configuration.getMBeanServerLookup();
+      try {
+         MBeanServerLookup lookup = (MBeanServerLookup) Util.getInstance(serverLookup);
+         return lookup.getMBeanServer();
+      } catch (Exception e) {
+         log.error("Could not instantiate MBeanServerLookup('" + serverLookup + "')", e);
+         throw new CacheException(e);
+      }
+   }
+   
+   protected String getJmxDomain(String jmxDomain, MBeanServer mBeanServer) {
+      String[] registeredDomains = mBeanServer.getDomains();
+      int index = 2;
+      String finalName = jmxDomain;
+      boolean done = false;
+      while (!done) {
+         done = true;
+         for (String domain : registeredDomains) {
+            if (domain.equals(finalName)) {
+               finalName = jmxDomain + index++;
+               done = false;
+               break;
+            }
+         }
+      }
+      return finalName;
+   }
+}

Modified: trunk/core/src/main/java/org/infinispan/jmx/CacheJmxRegistration.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/jmx/CacheJmxRegistration.java	2009-10-05 23:47:15 UTC (rev 915)
+++ trunk/core/src/main/java/org/infinispan/jmx/CacheJmxRegistration.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -22,20 +22,28 @@
 package org.infinispan.jmx;
 
 import org.infinispan.AdvancedCache;
+import org.infinispan.Cache;
+import org.infinispan.CacheDelegate;
 import org.infinispan.CacheException;
 import org.infinispan.config.Configuration;
 import org.infinispan.config.GlobalConfiguration;
 import org.infinispan.factories.AbstractComponentRegistry;
 import org.infinispan.factories.GlobalComponentRegistry;
+import org.infinispan.factories.AbstractComponentRegistry.Component;
 import org.infinispan.factories.annotations.Inject;
 import org.infinispan.factories.annotations.NonVolatile;
 import org.infinispan.factories.annotations.Start;
 import org.infinispan.factories.annotations.Stop;
-import org.infinispan.util.Util;
 import org.infinispan.util.logging.Log;
 import org.infinispan.util.logging.LogFactory;
 
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -43,31 +51,35 @@
  * ConfigurationRegistry to the MBean server.
  *
  * @author Mircea.Markus at jboss.com
+ * @author Galder Zamarreño
  * @see java.lang.management.ManagementFactory#getPlatformMBeanServer()
  * @since 4.0
  */
 @NonVolatile
-public class CacheJmxRegistration {
+public class CacheJmxRegistration extends AbstractJmxRegistration {
    private static final Log log = LogFactory.getLog(CacheJmxRegistration.class);
 
    private AdvancedCache cache;
+   private Set<Component> nonCacheComponents;
 
    @Inject
-   public void initialize(AdvancedCache cache) {
+   public void initialize(AdvancedCache cache, GlobalConfiguration globalConfig) {
       this.cache = cache;
+      this.globalConfig = globalConfig;
    }
 
    /**
     * Here is where the registration is being performed.
     */
    @Start(priority = 14)
-   public void registerToMBeanServer() {
+   public void start() {
       if (cache == null)
          throw new IllegalStateException("The cache should had been injected before a call to this method");
       Configuration config = cache.getConfiguration();
       if (config.isExposeJmxStatistics()) {
-         ComponentsJmxRegistration registrator = buildRegistrator();
-         registrator.registerMBeans();
+         Set<Component> components = cache.getComponentRegistry().getRegisteredComponents();
+         nonCacheComponents = getNonCacheComponents(components);
+         registerMBeans(components, cache.getConfiguration().getGlobalConfiguration());
          log.info("MBeans were successfully registered to the platform mbean server.");
       }
    }
@@ -76,76 +88,89 @@
     * Unregister when the cache is being stoped.
     */
    @Stop
-   public void unregisterMBeans() {
-      //this method might get called several times.
+   public void stop() {
+      // This method might get called several times.
       // After the first call the cache will become null, so we guard this
       if (cache == null) return;
       Configuration config = cache.getConfiguration();
       if (config.isExposeJmxStatistics()) {
-         ComponentsJmxRegistration componentsJmxRegistration = buildRegistrator();
-         componentsJmxRegistration.unregisterMBeans();
+         // Only unregister the non cache MBean so that it can be restarted
+         unregisterMBeans(nonCacheComponents);
          log.trace("MBeans were successfully unregistered from the mbean server.");
       }
       cache = null;
    }
+   
+   public void unregisterCacheMBean() {
+      String pattern = jmxDomain + ":" + ComponentsJmxRegistration.JMX_RESOURCE_KEY + "=" + CacheDelegate.OBJECT_NAME + ",*";
+      try {
+         Set<ObjectName> names = mBeanServer.queryNames(new ObjectName(pattern), null);
+         for (ObjectName name : names) {
+            mBeanServer.unregisterMBean(name);
+         }
+      } catch (MBeanRegistrationException e) {
+         String message = "Unable to unregister Cache MBeans with pattern " + pattern;
+         log.warn(message, e);
+      } catch (InstanceNotFoundException e) {
+         // Ignore if Cache MBeans not present
+      } catch (MalformedObjectNameException e) {
+         String message = "Malformed pattern " + pattern;
+         log.error(message, e);
+         throw new CacheException(message, e);
+      }
+   }
 
-   private ComponentsJmxRegistration buildRegistrator() {
-      Set<AbstractComponentRegistry.Component> components = cache.getComponentRegistry().getRegisteredComponents();
-      GlobalConfiguration configuration = cache.getConfiguration().getGlobalConfiguration();
-      MBeanServer beanServer = getMBeanServer(configuration);
-      ComponentsJmxRegistration registrator = new ComponentsJmxRegistration(beanServer, components, getGroupName());
-      updateDomain(registrator, cache.getAdvancedCache().getComponentRegistry().getGlobalComponentRegistry(), beanServer);
+
+   @Override
+   protected ComponentsJmxRegistration buildRegistrator(Set<AbstractComponentRegistry.Component> components) {
+      ComponentsJmxRegistration registrator = new ComponentsJmxRegistration(mBeanServer, components, getGroupName());
+      updateDomain(registrator, cache.getComponentRegistry().getGlobalComponentRegistry(), mBeanServer);
       return registrator;
    }
-
-   static void updateDomain(ComponentsJmxRegistration registrator, GlobalComponentRegistry componentRegistry, MBeanServer mBeanServer) {
+   
+   protected void updateDomain(ComponentsJmxRegistration registrator, GlobalComponentRegistry componentRegistry, MBeanServer mBeanServer) {
       GlobalConfiguration gc = componentRegistry.getComponent(GlobalConfiguration.class);
-      String componentName = CacheJmxRegistration.class.getName() + "_jmxDomain";
-      String jmxDomain = componentRegistry.getComponent(String.class, componentName);
-      if (jmxDomain == null) {
-         jmxDomain = getJmxDomain(gc.getJmxDomain(), mBeanServer);
-         if (!jmxDomain.equals(gc.getJmxDomain()) && !gc.isAllowDuplicateDomains()) {
-            String message = "There's already an cache manager instance registered under '" + gc.getJmxDomain() +
-                  "' JMX domain. If you want to allow multiple instances configured with same JMX domain enable " +
-                  "'allowDuplicateDomains' attribute in 'globalJmxStatistics' config element";
-            if (log.isErrorEnabled()) log.error(message);
-            throw new JmxDomainConflictException(message);
+      CacheManagerJmxRegistration managerJmxReg = componentRegistry.getComponent(CacheManagerJmxRegistration.class);
+      if (!gc.isExposeGlobalJmxStatistics() && jmxDomain == null) {
+         String tmpJmxDomain = getJmxDomain(gc.getJmxDomain(), mBeanServer);
+         synchronized (managerJmxReg) {
+            if (managerJmxReg.jmxDomain == null) {
+               if (!tmpJmxDomain.equals(gc.getJmxDomain()) && !gc.isAllowDuplicateDomains()) {
+                  String message = "There's already an cache manager instance registered under '" + gc.getJmxDomain() +
+                        "' JMX domain. If you want to allow multiple instances configured with same JMX domain enable " +
+                        "'allowDuplicateDomains' attribute in 'globalJmxStatistics' config element";
+                  if (log.isErrorEnabled()) log.error(message);
+                  throw new JmxDomainConflictException(message);
+               }
+               // Set manager component's jmx domain so that other caches under same manager 
+               // can see it, particularly important when jmx is only enabled at the cache level
+               managerJmxReg.jmxDomain = tmpJmxDomain;
+            }
+            // So that all caches share the same domain, regardless of whether dups are 
+            // allowed or not, simply assign the manager's calculated jmxDomain
+            jmxDomain = managerJmxReg.jmxDomain;
          }
-         componentRegistry.registerComponent(jmxDomain, componentName);
+      } else {
+         // If global stats were enabled, manager's jmxDomain would have been populated 
+         // when cache manager was started, so no need for synchronization here.
+         jmxDomain = managerJmxReg.jmxDomain == null ? gc.getJmxDomain() : managerJmxReg.jmxDomain;
       }
       registrator.setJmxDomain(jmxDomain);
    }
 
-   private static String getJmxDomain(String jmxDomain, MBeanServer mBeanServer) {
-      String[] registeredDomains = mBeanServer.getDomains();
-      int index = 2;
-      String finalName = jmxDomain;
-      boolean done = false;
-      while (!done) {
-         done = true;
-         for (String domain : registeredDomains) {
-            if (domain.equals(finalName)) {
-               finalName = jmxDomain + index++;
-               done = false;
-               break;
-            }
+   protected Set<Component> getNonCacheComponents(Set<Component> components) {
+      Set<Component> componentsExceptCache = new HashSet<AbstractComponentRegistry.Component>();
+      for (AbstractComponentRegistry.Component component : components) {
+         String name = component.getName();
+         if (!name.equals(Cache.class.getName()) && !name.equals(AdvancedCache.class.getName())) {
+            componentsExceptCache.add(component);
          }
       }
-      return finalName;
+      return componentsExceptCache;
    }
 
-   static MBeanServer getMBeanServer(GlobalConfiguration configuration) {
-      String serverLookup = configuration.getMBeanServerLookup();
-      try {
-         MBeanServerLookup lookup = (MBeanServerLookup) Util.getInstance(serverLookup);
-         return lookup.getMBeanServer();
-      } catch (Exception e) {
-         log.error("Could not instantiate MBeanServerLookup('" + serverLookup + "')", e);
-         throw new CacheException(e);
-      }
-   }
-
    private String getGroupName() {
       return cache.getName() + "(" + cache.getConfiguration().getCacheModeString().toLowerCase() + ")";
    }
+
 }

Modified: trunk/core/src/main/java/org/infinispan/jmx/CacheManagerJmxRegistration.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/jmx/CacheManagerJmxRegistration.java	2009-10-05 23:47:15 UTC (rev 915)
+++ trunk/core/src/main/java/org/infinispan/jmx/CacheManagerJmxRegistration.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -5,67 +5,74 @@
 import org.infinispan.factories.GlobalComponentRegistry;
 import org.infinispan.factories.annotations.Inject;
 import org.infinispan.factories.annotations.NonVolatile;
-import org.infinispan.factories.annotations.Start;
-import org.infinispan.factories.annotations.Stop;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 import javax.management.MBeanServer;
+
 import java.util.Set;
 
 /**
  * Registers all the components from global component registry to the mbean server.
  *
  * @author Mircea.Markus at jboss.com
+ * @author Galder Zamarreño
  * @since 4.0
  */
 @NonVolatile
-public class CacheManagerJmxRegistration {
-
+public class CacheManagerJmxRegistration extends AbstractJmxRegistration {
+   private static final Log log = LogFactory.getLog(CacheManagerJmxRegistration.class);
    public static final String GLOBAL_JMX_GROUP = "[global]";
-   private GlobalComponentRegistry registry;
-   private GlobalConfiguration globalConfiguration;
-   private MBeanServer mBeanServer;
+   private GlobalComponentRegistry globalReg;
 
    @Inject
    public void init(GlobalComponentRegistry registry, GlobalConfiguration configuration) {
-      this.registry = registry;
-      this.globalConfiguration = configuration;
+      this.globalReg = registry;
+      this.globalConfig = configuration;
    }
 
    /**
     * On start, the mbeans are registered.
     */
-   @Start(priority = 20)
    public void start() {
-      if (globalConfiguration.isExposeGlobalJmxStatistics()) {
-         ComponentsJmxRegistration registrator = buildRegistrator();
-         registrator.registerMBeans();
+      if (globalConfig.isExposeGlobalJmxStatistics()) {
+         registerMBeans(globalReg.getRegisteredComponents(), globalConfig);
       }
    }
 
-   public void setMBeanServer(MBeanServer mBeanServer) {
-      this.mBeanServer = mBeanServer;
-   }
-
    /**
     * On stop, the mbeans are unregistered.
     */
-   @Stop
    public void stop() {
-      //this method might get called several times.
+      // This method might get called several times.
       // After the first call the cache will become null, so we guard this
-      if (registry == null) return;
-      if (globalConfiguration.isExposeGlobalJmxStatistics()) {
-         ComponentsJmxRegistration componentsJmxRegistration = buildRegistrator();
-         componentsJmxRegistration.unregisterMBeans();
+      if (globalReg == null) return;
+      if (globalConfig.isExposeGlobalJmxStatistics()) {
+         unregisterMBeans(globalReg.getRegisteredComponents());
       }
-      registry = null;
+      globalReg = null;
    }
 
-   private ComponentsJmxRegistration buildRegistrator() {
-      Set<AbstractComponentRegistry.Component> components = registry.getRegisteredComponents();
-      mBeanServer = CacheJmxRegistration.getMBeanServer(globalConfiguration);
+   @Override
+   protected ComponentsJmxRegistration buildRegistrator(Set<AbstractComponentRegistry.Component> components) {
       ComponentsJmxRegistration registrator = new ComponentsJmxRegistration(mBeanServer, components, GLOBAL_JMX_GROUP);
-      CacheJmxRegistration.updateDomain(registrator, registry, mBeanServer);
+      updateDomain(registrator, globalReg, mBeanServer);
       return registrator;
    }
+
+   protected void updateDomain(ComponentsJmxRegistration registrator, GlobalComponentRegistry componentRegistry, MBeanServer mBeanServer) {
+      if (jmxDomain == null) {
+         jmxDomain = getJmxDomain(globalConfig.getJmxDomain(), mBeanServer);
+         String configJmxDomain = globalConfig.getJmxDomain();
+         if (!jmxDomain.equals(configJmxDomain) && !globalConfig.isAllowDuplicateDomains()) {
+            String message = "There's already an cache manager instance registered under '" + configJmxDomain +
+                  "' JMX domain. If you want to allow multiple instances configured with same JMX domain enable " +
+                  "'allowDuplicateDomains' attribute in 'globalJmxStatistics' config element";
+            if (log.isErrorEnabled()) log.error(message);
+            throw new JmxDomainConflictException(message);
+         }
+      }
+      registrator.setJmxDomain(jmxDomain);
+   }
+
 }

Modified: trunk/core/src/main/java/org/infinispan/jmx/ComponentsJmxRegistration.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/jmx/ComponentsJmxRegistration.java	2009-10-05 23:47:15 UTC (rev 915)
+++ trunk/core/src/main/java/org/infinispan/jmx/ComponentsJmxRegistration.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -80,12 +80,14 @@
    public void registerMBeans() throws CacheException {
       try {
          List<ResourceDMBean> resourceDMBeans = getResourceDMBeansFromComponents();
+         boolean trace = log.isTraceEnabled();
          for (ResourceDMBean resource : resourceDMBeans) {
             String resourceName = resource.getObjectName();
             ObjectName objectName = new ObjectName(getObjectName(resourceName));
             if (!mBeanServer.isRegistered(objectName)) {
                try {
                   mBeanServer.registerMBean(resource, objectName);
+                  if (trace) log.trace("Registered " + resource + " under " + objectName);
                } catch (InstanceAlreadyExistsException e) {
                   //this might happen if multiple instances are trying to concurrently register same objectName
                   log.info("Could not register object with name:" + objectName + "(" + e.getMessage() + ")");
@@ -108,11 +110,13 @@
       log.trace("Unregistering jmx resources..");
       try {
          List<ResourceDMBean> resourceDMBeans = getResourceDMBeansFromComponents();
+         boolean trace = log.isTraceEnabled();
          for (ResourceDMBean resource : resourceDMBeans) {
             String resourceName = resource.getObjectName();
             ObjectName objectName = new ObjectName(getObjectName(resourceName));
             if (mBeanServer.isRegistered(objectName)) {
                mBeanServer.unregisterMBean(objectName);
+               if (trace) log.trace("Unregistered " + objectName);
             }
          }
       }

Modified: trunk/core/src/main/java/org/infinispan/manager/DefaultCacheManager.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/manager/DefaultCacheManager.java	2009-10-05 23:47:15 UTC (rev 915)
+++ trunk/core/src/main/java/org/infinispan/manager/DefaultCacheManager.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -34,8 +34,11 @@
 import org.infinispan.factories.annotations.NonVolatile;
 import org.infinispan.factories.scopes.Scope;
 import org.infinispan.factories.scopes.Scopes;
+import org.infinispan.jmx.CacheJmxRegistration;
+import org.infinispan.jmx.CacheManagerJmxRegistration;
 import org.infinispan.jmx.annotations.MBean;
 import org.infinispan.jmx.annotations.ManagedAttribute;
+import org.infinispan.jmx.annotations.ManagedOperation;
 import org.infinispan.lifecycle.ComponentStatus;
 import org.infinispan.lifecycle.Lifecycle;
 import org.infinispan.notifications.cachemanagerlistener.CacheManagerNotifier;
@@ -93,9 +96,10 @@
  */
 @Scope(Scopes.GLOBAL)
 @NonVolatile
- at MBean(objectName = "CacheManager", description = "Component that acts as a manager, factory and container for caches in the system.")
+ at MBean(objectName = DefaultCacheManager.OBJECT_NAME, description = "Component that acts as a manager, factory and container for caches in the system.")
 public class DefaultCacheManager implements CacheManager {
    public static final String DEFAULT_CACHE_NAME = "org.infinispan.manager.DefaultCacheManager.DEFAULT_CACHE_NAME";
+   public static final String OBJECT_NAME = "CacheManager";
    protected GlobalConfiguration globalConfiguration;
    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
    private final ConcurrentMap<String, Configuration> configurationOverrides = new ConcurrentHashMap<String, Configuration>();
@@ -313,6 +317,7 @@
     *
     * @return the default cache.
     */
+   @ManagedOperation(description = "Starts the default cache.")
    public <K, V> Cache<K, V> getCache() {
       return getCache(DEFAULT_CACHE_NAME);
    }
@@ -330,6 +335,7 @@
     * @return a cache instance identified by cacheName
     */
    @SuppressWarnings("unchecked")
+   @ManagedOperation(description = "Starts a cache with the given name.")
    public <K, V> Cache<K, V> getCache(String cacheName) {
       if (cacheName == null)
          throw new NullPointerException("Null arguments not allowed");
@@ -381,7 +387,7 @@
    }
 
    public void start() {
-      // nothing to do
+      globalComponentRegistry.getComponent(CacheManagerJmxRegistration.class).start();
    }
 
    public void stop() {
@@ -391,14 +397,25 @@
          if (entry.getKey().equals(DEFAULT_CACHE_NAME)) {
             defaultCache = entry.getValue();
          } else {
+            unregisterCacheMBean(entry.getValue());
             entry.getValue().stop();
          }
       }
 
-      if (defaultCache != null) defaultCache.stop();
+      if (defaultCache != null) {
+         unregisterCacheMBean(defaultCache);
+         defaultCache.stop();
+      }
+      globalComponentRegistry.getComponent(CacheManagerJmxRegistration.class).stop();
       globalComponentRegistry.stop();
    }
 
+   private void unregisterCacheMBean(Cache cache) {
+      if (cache.getConfiguration().isExposeJmxStatistics()) {
+         cache.getAdvancedCache().getComponentRegistry().getComponent(CacheJmxRegistration.class).unregisterCacheMBean();
+      }
+   }
+   
    public void addListener(Object listener) {
       CacheManagerNotifier notifier = globalComponentRegistry.getComponent(CacheManagerNotifier.class);
       notifier.addListener(listener);
@@ -447,11 +464,20 @@
       return String.valueOf(this.configurationOverrides.keySet().size());
    }
 
-   @ManagedAttribute(description = "The total number of running caches, including the default cache.")
+   @ManagedAttribute(description = "The total number of created caches, including the default cache.")
    public String getCreatedCacheCount() {
       return String.valueOf(this.caches.keySet().size());
    }
 
+   @ManagedAttribute(description = "The total number of running caches, including the default cache.")
+   public String getRunningCacheCount() {
+      int running = 0;
+      for (Cache cache : caches.values()) {
+         if (cache.getStatus() == ComponentStatus.RUNNING) running++;
+      }
+      return String.valueOf(running);
+   }
+
    @ManagedAttribute(description = "Infinispan version")
    public String getVersion() {
       return Version.printVersion();

Added: trunk/core/src/test/java/org/infinispan/jmx/CacheMBeanTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/jmx/CacheMBeanTest.java	                        (rev 0)
+++ trunk/core/src/test/java/org/infinispan/jmx/CacheMBeanTest.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -0,0 +1,141 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or its affiliates, and
+ * individual contributors as indicated by the @author tags. See the
+ * copyright.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.jmx;
+
+import java.lang.reflect.Method;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.infinispan.CacheException;
+import org.infinispan.config.Configuration;
+import org.infinispan.config.GlobalConfiguration;
+import org.infinispan.lifecycle.ComponentStatus;
+import org.infinispan.manager.CacheManager;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.test.SingleCacheManagerTest;
+import org.infinispan.test.fwk.TestCacheManagerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+import org.testng.annotations.Test;
+
+ at Test(groups = "functional", testName = "jmx.CacheMBeanTest")
+public class CacheMBeanTest extends SingleCacheManagerTest {
+   private static final Log log = LogFactory.getLog(CacheMBeanTest.class);
+   public static final String JMX_DOMAIN = CacheMBeanTest.class.getSimpleName();
+   private MBeanServer server;
+
+   @Override
+   protected CacheManager createCacheManager() throws Exception {
+      GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault();
+      globalConfiguration.setJmxDomain(JMX_DOMAIN);
+      globalConfiguration.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
+      globalConfiguration.setExposeGlobalJmxStatistics(true);
+      Configuration configuration = new Configuration();
+      configuration.setExposeJmxStatistics(true);
+      cacheManager = TestCacheManagerFactory.createCacheManager(globalConfiguration, configuration);
+      server = PerThreadMBeanServerLookup.getThreadMBeanServer();
+      return cacheManager;
+   }
+   
+   public void testStartStopManagedOperations() throws Exception {
+      ObjectName defaultOn = new ObjectName(JMX_DOMAIN + ":cache-name=" + DefaultCacheManager.DEFAULT_CACHE_NAME + "(local),jmx-resource=Cache");
+      ObjectName managerON = new ObjectName(JMX_DOMAIN + ":cache-name=[global],jmx-resource=CacheManager");
+      server.invoke(managerON, "getCache", new Object[]{}, new String[]{});
+      assert ComponentStatus.RUNNING == server.getAttribute(defaultOn, "Status");
+      assert server.getAttribute(managerON, "CreatedCacheCount").equals("1");
+      assert server.getAttribute(managerON, "RunningCacheCount").equals("1");
+      server.invoke(defaultOn, "stop", new Object[]{}, new String[]{});
+      assert ComponentStatus.TERMINATED == server.getAttribute(defaultOn, "Status");
+      assert server.getAttribute(managerON, "CreatedCacheCount").equals("1");
+      assert server.getAttribute(managerON, "RunningCacheCount").equals("0");
+      server.invoke(defaultOn, "start", new Object[]{}, new String[]{});
+      assert ComponentStatus.RUNNING == server.getAttribute(defaultOn, "Status");
+      assert server.getAttribute(managerON, "CreatedCacheCount").equals("1");
+      assert server.getAttribute(managerON, "RunningCacheCount").equals("1");
+      server.invoke(defaultOn, "stop", new Object[]{}, new String[]{});
+      assert server.getAttribute(managerON, "CreatedCacheCount").equals("1");
+      assert server.getAttribute(managerON, "RunningCacheCount").equals("0");
+      assert ComponentStatus.TERMINATED == server.getAttribute(defaultOn, "Status");
+      server.invoke(defaultOn, "start", new Object[]{}, new String[]{});
+      assert server.getAttribute(managerON, "CreatedCacheCount").equals("1");
+      assert server.getAttribute(managerON, "RunningCacheCount").equals("1");
+      assert ComponentStatus.RUNNING == server.getAttribute(defaultOn, "Status");
+      server.invoke(defaultOn, "stop", new Object[]{}, new String[]{});
+      assert server.getAttribute(managerON, "CreatedCacheCount").equals("1");
+      assert server.getAttribute(managerON, "RunningCacheCount").equals("0");
+      assert ComponentStatus.TERMINATED == server.getAttribute(defaultOn, "Status");
+   }
+   
+   public void testManagerStopRemovesCacheMBean(Method method) throws Exception {
+      GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault();
+      final String otherJmxDomain = JMX_DOMAIN + '.' + method.getName();
+      globalConfiguration.setJmxDomain(otherJmxDomain);
+      globalConfiguration.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
+      globalConfiguration.setExposeGlobalJmxStatistics(true);
+      Configuration configuration = new Configuration();
+      configuration.setExposeJmxStatistics(true);
+      ObjectName defaultOn = new ObjectName(otherJmxDomain + ":cache-name=" + DefaultCacheManager.DEFAULT_CACHE_NAME + "(local),jmx-resource=Cache");
+      ObjectName galderOn = new ObjectName(otherJmxDomain + ":cache-name=galder(local),jmx-resource=Cache");
+      ObjectName managerON = new ObjectName(otherJmxDomain + ":cache-name=[global],jmx-resource=CacheManager");
+      CacheManager otherManager = TestCacheManagerFactory.createCacheManager(globalConfiguration, configuration);
+      server.invoke(managerON, "getCache", new Object[]{}, new String[]{});
+      server.invoke(managerON, "getCache", new Object[]{"galder"}, new String[]{String.class.getName()});
+      assert ComponentStatus.RUNNING == server.getAttribute(defaultOn, "Status");
+      assert ComponentStatus.RUNNING == server.getAttribute(galderOn, "Status");
+      otherManager.stop();
+      try {
+         log.info(server.getMBeanInfo(managerON));
+         assert false : "Failure expected, " + managerON + " shouldn't be registered in mbean server";
+      } catch (InstanceNotFoundException e) {
+      }
+      try {
+         log.info(server.getMBeanInfo(defaultOn));
+         assert false : "Failure expected, " + defaultOn + " shouldn't be registered in mbean server";
+      } catch (InstanceNotFoundException e) {
+      }
+      try {
+         log.info(server.getMBeanInfo(galderOn));
+         assert false : "Failure expected, " + galderOn + " shouldn't be registered in mbean server";
+      } catch (InstanceNotFoundException e) {
+      }
+   }
+
+
+   public void testDuplicateJmxDomainOnlyCacheExposesJmxStatistics() throws Exception {
+      GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault();
+      final String otherJmxDomain = JMX_DOMAIN;
+      globalConfiguration.setJmxDomain(otherJmxDomain);
+      globalConfiguration.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
+      Configuration configuration = new Configuration();
+      configuration.setExposeJmxStatistics(true);
+      CacheManager otherManager = TestCacheManagerFactory.createCacheManager(globalConfiguration, configuration);
+      try {
+         otherManager.getCache();
+         assert false : "Failure expected, " + otherJmxDomain + " is a duplicate!";
+      } catch (CacheException e) {
+         assert e.getCause().getCause() instanceof JmxDomainConflictException;
+      }
+   }
+}

Modified: trunk/core/src/test/java/org/infinispan/jmx/CacheManagerMBeanTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/jmx/CacheManagerMBeanTest.java	2009-10-05 23:47:15 UTC (rev 915)
+++ trunk/core/src/test/java/org/infinispan/jmx/CacheManagerMBeanTest.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -1,5 +1,7 @@
 package org.infinispan.jmx;
 
+import java.lang.reflect.Method;
+
 import org.infinispan.config.Configuration;
 import org.infinispan.config.GlobalConfiguration;
 import org.infinispan.manager.CacheManager;
@@ -7,6 +9,7 @@
 import org.infinispan.test.fwk.TestCacheManagerFactory;
 import org.testng.annotations.Test;
 
+import javax.management.InstanceNotFoundException;
 import javax.management.MBeanException;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
@@ -32,10 +35,9 @@
       globalConfiguration.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
       globalConfiguration.setExposeGlobalJmxStatistics(true);
       cacheManager = TestCacheManagerFactory.createCacheManager(globalConfiguration);
-      cacheManager.start();
-      cacheManager.getCache();
-      name = new ObjectName("CacheManagerMBeanTest:cache-name=[global],jmx-resource=CacheManager");
+      name = new ObjectName(JMX_DOMAIN + ":cache-name=[global],jmx-resource=CacheManager");
       server = PerThreadMBeanServerLookup.getThreadMBeanServer();
+      server.invoke(name, "getCache", new Object[]{}, new String[]{});
       return cacheManager;
    }
 
@@ -43,6 +45,7 @@
       assert server.getAttribute(name, "CreatedCacheCount").equals("1");
       assert server.getAttribute(name, "DefinedCacheCount").equals("0") : "Was " + server.getAttribute(name, "DefinedCacheCount");
       assert server.getAttribute(name, "DefinedCacheNames").equals("[]");
+      assert server.getAttribute(name, "RunningCacheCount").equals("1");
 
       //now define some new caches
       cacheManager.defineConfiguration("a", new Configuration());
@@ -50,16 +53,18 @@
       cacheManager.defineConfiguration("c", new Configuration());
       assert server.getAttribute(name, "CreatedCacheCount").equals("1");
       assert server.getAttribute(name, "DefinedCacheCount").equals("3");
+      assert server.getAttribute(name, "RunningCacheCount").equals("1");
       String attribute = (String) server.getAttribute(name, "DefinedCacheNames");
       assert attribute.contains("a(");
       assert attribute.contains("b(");
       assert attribute.contains("c(");
 
       //now start some caches
-      cacheManager.getCache("a");
-      cacheManager.getCache("b");
+      server.invoke(name, "getCache", new Object[]{"a"}, new String[]{String.class.getName()});
+      server.invoke(name, "getCache", new Object[]{"b"}, new String[]{String.class.getName()});
       assert server.getAttribute(name, "CreatedCacheCount").equals("3");
       assert server.getAttribute(name, "DefinedCacheCount").equals("3");
+      assert server.getAttribute(name, "RunningCacheCount").equals("3");
       attribute = (String) server.getAttribute(name, "DefinedCacheNames");
       assert attribute.contains("a(");
       assert attribute.contains("b(");
@@ -75,4 +80,25 @@
       }
       
    }
+   
+   public void testJmxRegistrationAtStartupAndStop(Method method) throws Exception {
+      GlobalConfiguration globalConfiguration = GlobalConfiguration.getNonClusteredDefault();
+      final String otherJmxDomain = JMX_DOMAIN + '.' + method.getName();
+      globalConfiguration.setJmxDomain(otherJmxDomain);
+      globalConfiguration.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
+      globalConfiguration.setExposeGlobalJmxStatistics(true);
+      CacheManager otherManager = TestCacheManagerFactory.createCacheManager(globalConfiguration);
+      ObjectName otherName = new ObjectName(otherJmxDomain + ":cache-name=[global],jmx-resource=CacheManager");
+      try {
+         assert server.getAttribute(otherName, "CreatedCacheCount").equals("0");
+      } finally {
+         otherManager.stop();
+      }
+      
+      try {
+         server.getAttribute(otherName, "CreatedCacheCount").equals("0");
+         assert false : "Failure expected, " + otherName + " shouldn't be registered in mbean server";
+      } catch (InstanceNotFoundException e) {
+      }
+   }
 }

Modified: trunk/core/src/test/java/org/infinispan/jmx/JmxStatsFunctionalTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/jmx/JmxStatsFunctionalTest.java	2009-10-05 23:47:15 UTC (rev 915)
+++ trunk/core/src/test/java/org/infinispan/jmx/JmxStatsFunctionalTest.java	2009-10-06 07:17:20 UTC (rev 916)
@@ -1,6 +1,5 @@
 package org.infinispan.jmx;
 
-import org.infinispan.CacheException;
 import org.infinispan.config.Configuration;
 import org.infinispan.config.GlobalConfiguration;
 import org.infinispan.manager.CacheManager;
@@ -12,6 +11,8 @@
 import javax.management.MBeanServer;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
+
+import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
@@ -25,6 +26,8 @@
 @Test(groups = "functional", testName = "jmx.JmxStatsFunctionalTest")
 public class JmxStatsFunctionalTest {
 
+   public static final String JMX_DOMAIN = JmxStatsFunctionalTest.class.getSimpleName();
+   private MBeanServer server;
    private CacheManager cm, cm2, cm3;
 
 
@@ -134,31 +137,40 @@
       assert existsObject("infinispan:cache-name=remote1(repl_sync),jmx-resource=Statistics");
    }
 
-   public void testMultipleManagersOnSameServerFails() {
+   public void testMultipleManagersOnSameServerFails(Method method) throws Exception {
       assert !existsDomains("infinispan");
+      final String jmxDomain = JMX_DOMAIN + '.' + method.getName();
       GlobalConfiguration globalConfiguration = GlobalConfiguration.getClusteredDefault();
+      globalConfiguration.setJmxDomain(jmxDomain);
       globalConfiguration.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
       cm = TestCacheManagerFactory.createCacheManager(globalConfiguration);
       Configuration localCache = config();//local by default
       localCache.setExposeJmxStatistics(true);
       cm.defineConfiguration("local_cache", localCache);
       cm.getCache("local_cache");
-      assert existsObject("infinispan:cache-name=local_cache(local),jmx-resource=Statistics");
+      assert existsObject(jmxDomain + ":cache-name=local_cache(local),jmx-resource=Statistics");
 
       GlobalConfiguration globalConfiguration2 = GlobalConfiguration.getClusteredDefault();
+      globalConfiguration2.setJmxDomain(jmxDomain);
       globalConfiguration2.setExposeGlobalJmxStatistics(true);
       globalConfiguration2.setAllowDuplicateDomains(false);
       globalConfiguration2.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
-      cm2 = TestCacheManagerFactory.createCacheManager(globalConfiguration2);
-      Configuration localCache2 = config();//local by default
-      localCache2.setExposeJmxStatistics(true);
-      cm2.defineConfiguration("local_cache", localCache);
       try {
-         cm2.getCache("local_cache");
-         assert false : "exception expected";
-      } catch (CacheException e) {
-         //expected
+         TestCacheManagerFactory.createCacheManager(globalConfiguration2);
+         assert false : "Failure expected, '" + jmxDomain + "' duplicate!";
+      } catch (JmxDomainConflictException e) {
       }
+      
+      server = PerThreadMBeanServerLookup.getThreadMBeanServer();
+      globalConfiguration2.setAllowDuplicateDomains(true);
+      CacheManager duplicateAllowedManager = TestCacheManagerFactory.createCacheManager(globalConfiguration2);
+      try {
+         final String duplicateName = jmxDomain + "2";
+         ObjectName duplicateObjectName = new ObjectName(duplicateName + ":cache-name=[global],jmx-resource=CacheManager");
+         server.getAttribute(duplicateObjectName, "CreatedCacheCount").equals("0");
+      } finally {
+         duplicateAllowedManager.stop();
+      }
    }
    
    public void testMultipleManagersOnSameServerWithCloneFails() {
@@ -176,15 +188,10 @@
       globalConfigurationClone.setExposeGlobalJmxStatistics(true);
       globalConfigurationClone.setAllowDuplicateDomains(false);
       globalConfigurationClone.setMBeanServerLookup(PerThreadMBeanServerLookup.class.getName());
-      cm2 = TestCacheManagerFactory.createCacheManager(globalConfigurationClone);
-      Configuration localCache2 = config();//local by default
-      localCache2.setExposeJmxStatistics(true);
-      cm2.defineConfiguration("local_cache", localCache);
       try {
-         cm2.getCache("local_cache");
-         assert false : "exception expected";
-      } catch (CacheException e) {
-         //expected
+         TestCacheManagerFactory.createCacheManager(globalConfigurationClone);
+         assert false : "Failure expected, 'infinispan' duplicate!";
+      } catch (JmxDomainConflictException e) {
       }
    }
 
@@ -251,6 +258,7 @@
       cm.defineConfiguration("local_cache", localCache);
       cm.getCache("local_cache");
       assert existsObject("infinispan:cache-name=local_cache(local),jmx-resource=Statistics");
+      assert existsObject("infinispan:cache-name=local_cache(local),jmx-resource=Cache");
 
       //now register a global one
       GlobalConfiguration globalConfiguration2 = GlobalConfiguration.getClusteredDefault();
@@ -263,10 +271,12 @@
       remoteCache.setCacheMode(Configuration.CacheMode.REPL_SYNC);
       cm2.defineConfiguration("remote_cache", remoteCache);
       cm2.getCache("remote_cache");
+      assert existsObject("infinispan2:cache-name=remote_cache(repl_sync),jmx-resource=Cache");
       assert existsObject("infinispan2:cache-name=remote_cache(repl_sync),jmx-resource=Statistics");
 
       cm2.stop();
       assert existsObject("infinispan:cache-name=local_cache(local),jmx-resource=Statistics");
+      assert !existsObject("infinispan2:cache-name=remote_cache(repl_sync),jmx-resource=Cache");
       assert !existsObject("infinispan2:cache-name=remote_cache(repl_sync),jmx-resource=Statistics");
 
       cm.stop();



More information about the infinispan-commits mailing list