net.sf.ehcache.management.ManagementService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache-core Show documentation
Show all versions of ehcache-core Show documentation
Internal ehcache-core module. This artifact is not meant to be used directly
/**
* Copyright Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.ehcache.management;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Status;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.event.CacheManagerEventListener;
import net.sf.ehcache.hibernate.management.impl.EhcacheHibernateMbeanNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
/**
* Ehcache CacheManagers and Caches have lifecycles. Often normal use of a CacheManager
* will be to shut it down and create a new one from within a running JVM. For example,
* in Java EE environments, applications are often undeployed and then redeployed. A
* servlet listener avdailable in the web module, net.sf.ehcache.constructs.web.ShutdownListener
}
* enables this to be detected and the CacheManager shutdown.
*
* When a CacheManager is shut down we need to ensure there is no memory, resource or
* thread leakage. An MBeanServer, particularly a platform MBeanServer, can be expected
* to exist for the lifespan of the JVM. Accordingly, we need to deregister them when
* needed without creating a leakage.
*
* The second purpose of this class (and this package) is to keep management concerns away
* from the core ehcache packages. That way, JMX is not a required dependency, but rather
* an optional one.
*
* This class is constructable as of 1.5 to support injection via IoC containers.
*
* @author Greg Luck
* @version $Id: ManagementService.java 8506 2013-12-04 09:46:53Z ljacomet $
* @since 1.3
*/
public class ManagementService implements CacheManagerEventListener {
private static final Logger LOG = LoggerFactory.getLogger(ManagementService.class.getName());
private final MBeanServer mBeanServer;
private final net.sf.ehcache.CacheManager backingCacheManager;
private final boolean registerCacheManager;
private final boolean registerCaches;
private final boolean registerCacheConfigurations;
private final boolean registerCacheStatistics;
private final boolean registerCacheStores;
private Status status;
/**
* A constructor for a management service for a range of possible MBeans.
*
* The {@link #init()} method needs to be called after construction which causes
* the selected monitoring options to be be registered
* with the provided MBeanServer for caches in the given CacheManager.
*
* While registering the CacheManager enables traversal to all of the other
* items,
* this requires programmatic traversal. The other options allow entry points closer
* to an item of interest and are more accessible from JMX management tools like JConsole.
* Moreover CacheManager and Cache are not serializable, so remote monitoring is not possible
* for CacheManager or Cache, while CacheStatistics and CacheConfiguration are. Finally
* CacheManager and Cache enable management operations to be performed.
*
* Once monitoring is enabled caches will automatically added and removed from the MBeanServer
* as they are added and disposed of from the CacheManager. When the CacheManager itself
* shutsdown all registered MBeans will be unregistered.
*
* @param cacheManager the CacheManager to listen to
* @param mBeanServer the MBeanServer to register MBeans to
* @param registerCacheManager Whether to register the CacheManager MBean
* @param registerCaches Whether to register the Cache MBeans
* @param registerCacheConfigurations Whether to register the CacheConfiguration MBeans
* @param registerCacheStatistics Whether to register the CacheStatistics MBeans
* @throws net.sf.ehcache.CacheException if something goes wrong with init()
* @since 2.2
*/
public ManagementService(net.sf.ehcache.CacheManager cacheManager,
MBeanServer mBeanServer,
boolean registerCacheManager,
boolean registerCaches,
boolean registerCacheConfigurations,
boolean registerCacheStatistics,
boolean registerCacheStores) throws CacheException {
status = Status.STATUS_UNINITIALISED;
backingCacheManager = cacheManager;
this.mBeanServer = mBeanServer;
this.registerCacheManager = registerCacheManager;
this.registerCaches = registerCaches;
this.registerCacheConfigurations = registerCacheConfigurations;
this.registerCacheStatistics = registerCacheStatistics;
this.registerCacheStores = registerCacheStores;
}
/**
* A constructor for a management service for a range of possible MBeans.
*
* The {@link #init()} method needs to be called after construction which causes
* the selected monitoring options to be be registered
* with the provided MBeanServer for caches in the given CacheManager.
*
* While registering the CacheManager enables traversal to all of the other
* items,
* this requires programmatic traversal. The other options allow entry points closer
* to an item of interest and are more accessible from JMX management tools like JConsole.
* Moreover CacheManager and Cache are not serializable, so remote monitoring is not possible
* for CacheManager or Cache, while CacheStatistics and CacheConfiguration are. Finally
* CacheManager and Cache enable management operations to be performed.
*
* Once monitoring is enabled caches will automatically added and removed from the MBeanServer
* as they are added and disposed of from the CacheManager. When the CacheManager itself
* shutsdown all registered MBeans will be unregistered.
*
* @param cacheManager the CacheManager to listen to
* @param mBeanServer the MBeanServer to register MBeans to
* @param registerCacheManager Whether to register the CacheManager MBean
* @param registerCaches Whether to register the Cache MBeans
* @param registerCacheConfigurations Whether to register the CacheConfiguration MBeans
* @param registerCacheStatistics Whether to register the CacheStatistics MBeans
* @throws net.sf.ehcache.CacheException if something goes wrong with init()
*/
public ManagementService(net.sf.ehcache.CacheManager cacheManager,
MBeanServer mBeanServer,
boolean registerCacheManager,
boolean registerCaches,
boolean registerCacheConfigurations,
boolean registerCacheStatistics) throws CacheException {
this(cacheManager, mBeanServer, registerCacheManager, registerCaches,
registerCacheConfigurations, registerCacheStatistics, false);
}
/**
* A convenience static method which creates a ManagementService and initialises it with the
* supplied parameters.
*
* @param cacheManager the CacheManager to listen to
* @param mBeanServer the MBeanServer to register MBeans to
* @param registerCacheManager Whether to register the CacheManager MBean
* @param registerCaches Whether to register the Cache MBeans
* @param registerCacheConfigurations Whether to register the CacheConfiguration MBeans
* @param registerCacheStatistics Whether to register the CacheStatistics MBeans
* @see ManagementService#ManagementService(net.sf.ehcache.CacheManager, javax.management.MBeanServer, boolean, boolean, boolean, boolean, boolean)
* @since 2.2
*/
public static void registerMBeans(
net.sf.ehcache.CacheManager cacheManager,
MBeanServer mBeanServer,
boolean registerCacheManager,
boolean registerCaches,
boolean registerCacheConfigurations,
boolean registerCacheStatistics,
boolean registerCacheStores) throws CacheException {
ManagementService registry = new ManagementService(cacheManager,
mBeanServer,
registerCacheManager,
registerCaches,
registerCacheConfigurations,
registerCacheStatistics,
registerCacheStores);
registry.init();
}
/**
* A convenience static method which creates a ManagementService and initialises it with the
* supplied parameters.
*
* This one is provided for backward compatibility
*
* @param cacheManager the CacheManager to listen to
* @param mBeanServer the MBeanServer to register MBeans to
* @param registerCacheManager Whether to register the CacheManager MBean
* @param registerCaches Whether to register the Cache MBeans
* @param registerCacheConfigurations Whether to register the CacheConfiguration MBeans
* @param registerCacheStatistics Whether to register the CacheStatistics MBeans
* @see ManagementService#ManagementService(net.sf.ehcache.CacheManager, javax.management.MBeanServer, boolean, boolean, boolean, boolean)
*/
public static void registerMBeans(
net.sf.ehcache.CacheManager cacheManager,
MBeanServer mBeanServer,
boolean registerCacheManager,
boolean registerCaches,
boolean registerCacheConfigurations,
boolean registerCacheStatistics) throws CacheException {
registerMBeans(cacheManager, mBeanServer, registerCacheManager, registerCaches, registerCacheConfigurations,
registerCacheStatistics, false);
}
/**
* Call to register the mbeans in the mbean server and start the event listeners and do any other required initialisation.
* Once intialised, it registers itself as a CacheManageEvenListener with the backing CacheManager, so
* that it can participate in lifecycle and other events.
*
* @throws net.sf.ehcache.CacheException - all exceptions are wrapped in CacheException
*/
public void init() throws CacheException {
CacheManager cacheManager = new CacheManager(backingCacheManager);
try {
registerCacheManager(cacheManager);
registerPeerProviders();
List caches = cacheManager.getCaches();
for (int i = 0; i < caches.size(); i++) {
Cache cache = (Cache) caches.get(i);
registerCachesIfRequired(cache);
registerCacheStatisticsIfRequired(cache);
registerCacheConfigurationIfRequired(cache);
registerCacheStoreIfRequired(cache);
}
} catch (Exception e) {
throw new CacheException(e);
}
status = Status.STATUS_ALIVE;
backingCacheManager.getCacheManagerEventListenerRegistry().registerListener(this);
}
private void registerPeerProviders() {
final Map cacheManagerPeerProviders = this.backingCacheManager.getCacheManagerPeerProviders();
for (final CacheManagerPeerProvider cacheManagerPeerProvider : cacheManagerPeerProviders.values()) {
if (cacheManagerPeerProvider instanceof ManagedCacheManagerPeerProvider) {
((ManagedCacheManagerPeerProvider) cacheManagerPeerProvider).register(this.mBeanServer);
}
}
}
private void registerCacheManager(CacheManager cacheManager) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if (registerCacheManager) {
mBeanServer.registerMBean(cacheManager, cacheManager.getObjectName());
}
}
private void registerCacheConfigurationIfRequired(Cache cache) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if (registerCacheConfigurations) {
CacheConfiguration cacheConfiguration = cache.getCacheConfiguration();
mBeanServer.registerMBean(cacheConfiguration, cacheConfiguration.getObjectName());
}
}
private void registerCacheStatisticsIfRequired(Cache cache) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if (registerCacheStatistics) {
CacheStatistics cacheStatistics = cache.getStatistics();
mBeanServer.registerMBean(cacheStatistics, cacheStatistics.getObjectName());
}
}
private void registerCachesIfRequired(Cache cache) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if (registerCaches) {
mBeanServer.registerMBean(cache, cache.getObjectName());
}
}
private void registerCacheStoreIfRequired(Cache cache) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if (registerCacheStores) {
Store cacheStore = cache.getStore();
if (cacheStore != null) {
mBeanServer.registerMBean(cacheStore, cacheStore.getObjectName());
}
}
}
/**
* Returns the listener status.
*
* @return the status at the point in time the method is called
*/
public Status getStatus() {
return status;
}
/**
* Stop the listener and free any resources.
* Removes registered ObjectNames
*
* @throws net.sf.ehcache.CacheException - all exceptions are wrapped in CacheException
*/
public void dispose() throws CacheException {
Set registeredObjectNames = null;
try {
// CacheManager MBean
registeredObjectNames = mBeanServer.queryNames(CacheManager.createObjectName(backingCacheManager), null);
// Other MBeans for this CacheManager
registeredObjectNames.addAll(mBeanServer.queryNames(new ObjectName("net.sf.ehcache:*,CacheManager="
+ EhcacheHibernateMbeanNames.mbeanSafe(backingCacheManager.toString())), null));
} catch (MalformedObjectNameException e) {
// this should not happen
LOG.error("Error querying MBeanServer. Error was " + e.getMessage(), e);
}
for (Iterator iterator = registeredObjectNames.iterator(); iterator.hasNext();) {
ObjectName objectName = (ObjectName) iterator.next();
try {
mBeanServer.unregisterMBean(objectName);
} catch (Exception e) {
LOG.error("Error unregistering object instance " + objectName + " . Error was " + e.getMessage(), e);
}
}
status = Status.STATUS_SHUTDOWN;
}
/**
* Called immediately after a cache has been added and activated.
*
* Note that the CacheManager calls this method from a synchronized method. Any attempt to
* call a synchronized method on CacheManager from this method will cause a deadlock.
*
* Note that activation will also cause a CacheEventListener status change notification
* from {@link net.sf.ehcache.Status#STATUS_UNINITIALISED} to
* {@link net.sf.ehcache.Status#STATUS_ALIVE}. Care should be taken on processing that
* notification because:
*
* - the cache will not yet be accessible from the CacheManager.
*
- the addCaches methods which cause this notification are synchronized on the
* CacheManager. An attempt to call {@link net.sf.ehcache.CacheManager#getEhcache(String)}
* will cause a deadlock.
*
* The calling method will block until this method returns.
*
*
* @param cacheName the name of the Cache
the operation relates to
* @see net.sf.ehcache.event.CacheEventListener
*/
public void notifyCacheAdded(String cacheName) {
if (registerCaches || registerCacheStatistics || registerCacheConfigurations) {
Cache cache = new Cache(backingCacheManager.getEhcache(cacheName));
try {
registerCachesIfRequired(cache);
registerCacheStatisticsIfRequired(cache);
registerCacheConfigurationIfRequired(cache);
registerCacheStoreIfRequired(cache);
} catch (Exception e) {
LOG.error("Error registering cache for management for " + cache.getObjectName()
+ " . Error was " + e.getMessage(), e);
}
}
}
/**
* Called immediately after a cache has been disposed and removed. The calling method will
* block until this method returns.
*
* Note that the CacheManager calls this method from a synchronized method. Any attempt to
* call a synchronized method on CacheManager from this method will cause a deadlock.
*
* Note that a {@link net.sf.ehcache.event.CacheEventListener} status changed will also be triggered. Any
* attempt from that notification to access CacheManager will also result in a deadlock.
*
* @param cacheName the name of the Cache
the operation relates to
*/
public void notifyCacheRemoved(String cacheName) {
if (registerCaches) {
unregisterMBean(Cache.createObjectName(backingCacheManager.toString(), cacheName));
}
if (registerCacheConfigurations) {
unregisterMBean(CacheConfiguration.createObjectName(backingCacheManager.toString(), cacheName));
}
if (registerCacheStatistics) {
unregisterMBean(CacheStatistics.createObjectName(backingCacheManager.toString(), cacheName));
}
if (registerCacheStores) {
unregisterMBean(Store.createObjectName(backingCacheManager.toString(), cacheName));
}
}
private void unregisterMBean(ObjectName objectName) {
try {
if (mBeanServer.isRegistered(objectName)) {
mBeanServer.unregisterMBean(objectName);
}
} catch (Exception e) {
LOG.error("Error unregistering cache for management for " + objectName
+ " . Error was " + e.getMessage(), e);
}
}
}