blob: 046f5bdde04160a2032062683a64ba7608feb276 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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 org.apache.geode.admin.jmx.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBean;
import javax.naming.OperationNotSupportedException;
import org.apache.commons.modeler.ManagedBean;
import org.apache.logging.log4j.Logger;
import org.apache.geode.admin.AdminException;
import org.apache.geode.admin.CacheServerConfig;
import org.apache.geode.admin.CacheVmConfig;
import org.apache.geode.admin.ConfigurationParameter;
import org.apache.geode.admin.StatisticResource;
import org.apache.geode.admin.SystemMemberCache;
import org.apache.geode.admin.SystemMemberCacheEvent;
import org.apache.geode.admin.SystemMemberRegionEvent;
import org.apache.geode.admin.internal.CacheServerImpl;
import org.apache.geode.admin.internal.ConfigurationParameterImpl;
import org.apache.geode.internal.admin.ClientMembershipMessage;
import org.apache.geode.internal.admin.GemFireVM;
import org.apache.geode.internal.admin.StatResource;
import org.apache.geode.internal.logging.LogService;
/**
* MBean representation of a {@link org.apache.geode.admin.CacheVm}.
*
* @since GemFire 4.0
*/
public class CacheServerJmxImpl extends CacheServerImpl
implements ManagedResource, CacheVmConfig, CacheServerConfig, SystemMemberJmx {
private static final Logger logger = LogService.getLogger();
/**
* Interval in seconds between refreshes. Value less than one results in no refreshing
*/
private int refreshInterval = 0;
/** The object name of this managed resource */
private ObjectName objectName;
/** The name of the MBean that will manage this resource */
private String mbeanName;
/** The ModelMBean that is configured to manage this resource */
private ModelMBean modelMBean;
/** Reference to the cache MBean representing a Cache in the Cache VM Member */
private SystemMemberCacheJmxImpl managedSystemMemberCache;
/** collection to collect all the resources created for this member */
private Map<StatResource, StatisticResourceJmxImpl> managedStatisticsResourcesMap =
new HashMap<StatResource, StatisticResourceJmxImpl>();
////////////////////// Constructors //////////////////////
/**
* Creates a new <code>CacheServerJmxImpl</code> for an existing cache server.
*/
CacheServerJmxImpl(AdminDistributedSystemJmxImpl system, GemFireVM vm) throws AdminException {
super(system, vm);
initializeMBean();
}
/**
* Creates a new <code>CacheServerJmxImpl</code> for an newly-created cache server.
*/
CacheServerJmxImpl(AdminDistributedSystemJmxImpl system, CacheVmConfig config)
throws AdminException {
super(system, config);
initializeMBean();
}
////////////////////// Instance Methods //////////////////////
/**
* Creates and registers the MBean to manage this resource
*/
private void initializeMBean() throws AdminException {
this.mbeanName = new StringBuffer("GemFire.CacheVm:").append("id=")
.append(MBeanUtil.makeCompliantMBeanNameProperty(getId())).append(",type=")
.append(MBeanUtil.makeCompliantMBeanNameProperty(getType().getName())).toString();
this.objectName =
MBeanUtil.createMBean(this, addDynamicAttributes(MBeanUtil.lookupManagedBean(this)));
// Refresh Interval
AdminDistributedSystemJmxImpl sysJmx = (AdminDistributedSystemJmxImpl) system;
if (sysJmx.getRefreshInterval() > 0)
this.refreshInterval = sysJmx.getRefreshInterval();
}
@Override
public String getMBeanName() {
return this.mbeanName;
}
@Override
public ModelMBean getModelMBean() {
return this.modelMBean;
}
@Override
public void setModelMBean(ModelMBean modelMBean) {
this.modelMBean = modelMBean;
}
@Override
public ObjectName getObjectName() {
return this.objectName;
}
@Override
public ManagedResourceType getManagedResourceType() {
return ManagedResourceType.CACHE_VM;
}
/**
* Un-registers all the statistics & cache managed resource created for this member. After
* un-registering the resource MBean instances, clears managedStatisticsResourcesMap collection &
* sets managedSystemMemberCache to null.
*
* Creates ConfigurationParameterJmxImpl, StatisticResourceJmxImpl and SystemMemberCacheJmxImpl.
* But cleans up only StatisticResourceJmxImpl and SystemMemberCacheJmxImpl which are of type
* ManagedResource.
*/
@Override
public void cleanupResource() {
synchronized (this.managedStatisticsResourcesMap) {
ConfigurationParameter[] names = getConfiguration();
if (names != null) {
for (int i = 0; i < names.length; i++) {
ConfigurationParameter parm = names[i];
((ConfigurationParameterImpl) parm).removeConfigurationParameterListener(this);
}
}
this.parms.clear();
Collection<StatisticResourceJmxImpl> statisticResources =
managedStatisticsResourcesMap.values();
for (StatisticResourceJmxImpl statisticResource : statisticResources) {
MBeanUtil.unregisterMBean(statisticResource);
}
this.managedStatisticsResourcesMap.clear();
}
MBeanUtil.unregisterMBean(this.managedSystemMemberCache);
this.managedSystemMemberCache = null;
}
/////////////////////// Configuration ///////////////////////
@Override
public String getHost() {
return this.getConfig().getHost();
}
@Override
public void setHost(String host) {
this.getConfig().setHost(host);
}
@Override
public String getWorkingDirectory() {
return this.getConfig().getWorkingDirectory();
}
@Override
public void setWorkingDirectory(String dir) {
this.getConfig().setWorkingDirectory(dir);
}
@Override
public String getProductDirectory() {
return this.getConfig().getProductDirectory();
}
@Override
public void setProductDirectory(String dir) {
this.getConfig().setProductDirectory(dir);
}
@Override
public String getRemoteCommand() {
return this.getConfig().getRemoteCommand();
}
@Override
public void setRemoteCommand(String remoteCommand) {
this.getConfig().setRemoteCommand(remoteCommand);
}
@Override
public void validate() {
throw new UnsupportedOperationException("Should not be invoked");
}
@Override
public Object clone() throws CloneNotSupportedException {
throw new UnsupportedOperationException("Should not be invoked");
}
@Override
public String getCacheXMLFile() {
return this.getConfig().getCacheXMLFile();
}
@Override
public void setCacheXMLFile(String cacheXMLFile) {
this.getConfig().setCacheXMLFile(cacheXMLFile);
}
@Override
public String getClassPath() {
return this.getConfig().getClassPath();
}
@Override
public void setClassPath(String classpath) {
this.getConfig().setClassPath(classpath);
}
// -------------------------------------------------------------------------
// MBean attribute accessors/mutators
// -------------------------------------------------------------------------
/**
* Gets the interval in seconds between config refreshes
*
* @return the current refresh interval in seconds
*/
@Override
public int getRefreshInterval() {
return this.refreshInterval;
}
/**
* Sets interval in seconds between cache config refreshes; zero or less turns off auto
* refreshing. Manual refreshing has no effect on when the next scheduled refresh will occur.
*
* @param refreshInterval the new refresh interval in seconds
*/
@Override
public void _setRefreshInterval(int refreshInterval) {
boolean isRegistered = MBeanUtil.isRefreshNotificationRegistered(this,
RefreshNotificationType.SYSTEM_MEMBER_CONFIG);
if (isRegistered && (getRefreshInterval() == refreshInterval))
return;
this.refreshInterval = Helper.setAndReturnRefreshInterval(this, refreshInterval);
}
/**
* RefreshInterval is now set only through the AdminDistributedSystem property refreshInterval.
* Attempt to set refreshInterval on CacheServerJmx MBean would result in an
* OperationNotSupportedException Auto-refresh is enabled on demand when a call to refreshConfig
* is made
*
* @param refreshInterval the new refresh interval in seconds
* @deprecated since 6.0 use DistributedSystemConfig.refreshInterval instead
*/
@Override
@Deprecated
public void setRefreshInterval(int refreshInterval) throws OperationNotSupportedException {
throw new OperationNotSupportedException(
"RefreshInterval can not be set directly. Use DistributedSystemConfig.refreshInterval.");
}
// -------------------------------------------------------------------------
// MBean Operations
// -------------------------------------------------------------------------
@Override
public void refreshConfig() throws org.apache.geode.admin.AdminException {
// 1st call to refreshConfig would trigger
// the auto-refresh if an interval is set
if (this.refreshInterval > 0) {
this._setRefreshInterval(this.refreshInterval);
}
super.refreshConfig();
}
/**
* Gets this member's cache.
*
* @return array of ObjectName for this member's cache
*/
@Override
public ObjectName manageCache() throws AdminException, MalformedObjectNameException {
return Helper.manageCache(this);
}
/**
* Gets all active StatisticResources for this manager.
*
* @return array of ObjectName instances
*/
@Override
public ObjectName[] manageStats() throws AdminException, MalformedObjectNameException {
return Helper.manageStats(this);
}
/**
* Gets the active StatisticResources for this manager, based on the typeName as the key
*
* @return ObjectName of StatisticResourceJMX instance
*/
@Override
public ObjectName[] manageStat(String statisticsTypeName)
throws AdminException, MalformedObjectNameException {
return Helper.manageStat(this, statisticsTypeName);
}
// -------------------------------------------------------------------------
// JMX Notification listener
// -------------------------------------------------------------------------
/**
* Handles notification to refresh. Reacts by refreshing the values of this GemFireManager's
* ConfigurationParamaters. Any other notification is ignored. Given notification is handled only
* if there is any JMX client connected to the system.
*
* @param notification the JMX notification being received
* @param hb handback object is unused
*/
@Override
public void handleNotification(Notification notification, Object hb) {
AdminDistributedSystemJmxImpl systemJmx = (AdminDistributedSystemJmxImpl) this.system;
if (!systemJmx.isRmiClientCountZero()) {
Helper.handleNotification(this, notification, hb);
}
}
// -------------------------------------------------------------------------
// Template methods overriden from superclass...
// -------------------------------------------------------------------------
/**
* Template method for creating instance of ConfigurationParameter. Overridden to return
* ConfigurationParameterJmxImpl.
*/
@Override
protected ConfigurationParameter createConfigurationParameter(String name, String description,
Object value, Class type, boolean userModifiable) {
return new ConfigurationParameterJmxImpl(name, description, value, type, userModifiable);
}
/**
* Override createStatisticResource by instantiating StatisticResourceJmxImpl if it was not
* created earlier otherwise returns the same instance.
*
* @param stat StatResource reference for which this JMX resource is to be created
* @return StatisticResourceJmxImpl - JMX Implementation of StatisticResource
* @throws AdminException if constructing StatisticResourceJmxImpl instance fails
*/
@Override
protected StatisticResource createStatisticResource(StatResource stat)
throws org.apache.geode.admin.AdminException {
StatisticResourceJmxImpl managedStatisticResource = null;
synchronized (this.managedStatisticsResourcesMap) {
/*
* Ensuring that a single instance of Statistic Resource is created per StatResource.
*/
StatisticResourceJmxImpl statisticResourceJmxImpl = managedStatisticsResourcesMap.get(stat);
if (statisticResourceJmxImpl != null) {
managedStatisticResource = statisticResourceJmxImpl;
} else {
managedStatisticResource = new StatisticResourceJmxImpl(stat, this);
managedStatisticResource.getStatistics();// inits timer
managedStatisticsResourcesMap.put(stat, managedStatisticResource);
}
}
return managedStatisticResource;
}
/**
* Override createSystemMemberCache by instantiating SystemMemberCacheJmxImpl if it was not
* created earlier.
*
* @param vm GemFireVM reference for which this JMX resource is to be created
* @return SystemMemberCacheJmxImpl - JMX Implementation of SystemMemberCache
* @throws AdminException if constructing SystemMemberCacheJmxImpl instance fails
*/
@Override
protected SystemMemberCache createSystemMemberCache(GemFireVM vm)
throws org.apache.geode.admin.AdminException {
if (managedSystemMemberCache == null) {
managedSystemMemberCache = new SystemMemberCacheJmxImpl(vm);
}
return managedSystemMemberCache;
}
// -------------------------------------------------------------------------
// Create MBean attributes for each ConfigurationParameter
// -------------------------------------------------------------------------
/**
* Add MBean attribute definitions for each ConfigurationParameter.
*
* @param managed the mbean definition to add attributes to
* @return a new instance of ManagedBean copied from <code>managed</code> but with the new
* attributes added
*/
@Override
public ManagedBean addDynamicAttributes(ManagedBean managed)
throws org.apache.geode.admin.AdminException {
return Helper.addDynamicAttributes(this, managed);
}
/**
* Cleans up Managed Resources created for the client that was connected to the server represented
* by this class.
*
* @param clientId id of the client to be removed
* @return List of ManagedResources associated with the client of given client id
*/
/*
* This clean up is for the clients. The clients are started with a loner DM. Hence the clientId
* is not supposed to contain '/' as per InternalDistributedMember.toString().
*/
public List<ManagedResource> cleanupBridgeClientResources(String clientId) {
List<ManagedResource> returnedResources = new ArrayList<ManagedResource>();
String compatibleId = "id_" + MBeanUtil.makeCompliantMBeanNameProperty(clientId);
synchronized (this.managedStatisticsResourcesMap) {
Set<Entry<StatResource, StatisticResourceJmxImpl>> entrySet =
this.managedStatisticsResourcesMap.entrySet();
for (Iterator<Entry<StatResource, StatisticResourceJmxImpl>> it = entrySet.iterator(); it
.hasNext();) {
Entry<StatResource, StatisticResourceJmxImpl> entry = it.next();
StatisticResourceJmxImpl resource = entry.getValue();
if (resource.getMBeanName().contains(compatibleId)) {
it.remove(); // remove matching entry
returnedResources.add(resource);
}
}
}
return returnedResources;
}
/**
* Implementation handles client membership changes.
*
* @param clientId id of the client for whom membership change happened
* @param eventType membership change type; one of {@link ClientMembershipMessage#JOINED},
* {@link ClientMembershipMessage#LEFT}, {@link ClientMembershipMessage#CRASHED}
*/
@Override
public void handleClientMembership(String clientId, int eventType) {
String notifType = null;
List<ManagedResource> cleanedUp = null;
if (eventType == ClientMembershipMessage.LEFT) {
notifType = NOTIF_CLIENT_LEFT;
cleanedUp = cleanupBridgeClientResources(clientId);
} else if (eventType == ClientMembershipMessage.CRASHED) {
notifType = NOTIF_CLIENT_CRASHED;
cleanedUp = cleanupBridgeClientResources(clientId);
} else if (eventType == ClientMembershipMessage.JOINED) {
notifType = NOTIF_CLIENT_JOINED;
}
if (cleanedUp != null) {
for (ManagedResource resource : cleanedUp) {
MBeanUtil.unregisterMBean(resource);
}
}
Helper.sendNotification(this, new Notification(notifType, this.modelMBean,
Helper.getNextNotificationSequenceNumber(), clientId));
}
/**
* Implementation handles creation of cache by extracting the details from the given event object
* and sending the {@link SystemMemberJmx#NOTIF_CACHE_CREATED} notification to the connected JMX
* Clients.
*
* @param event event object corresponding to the creation of the cache
*/
@Override
public void handleCacheCreate(SystemMemberCacheEvent event) {
Helper.sendNotification(this, new Notification(NOTIF_CACHE_CREATED, this.modelMBean,
Helper.getNextNotificationSequenceNumber(), Helper.getCacheEventDetails(event)));
}
/**
* Implementation handles closure of cache by extracting the details from the given event object
* and sending the {@link SystemMemberJmx#NOTIF_CACHE_CLOSED} notification to the connected JMX
* Clients.
*
* @param event event object corresponding to the closure of the cache
*/
@Override
public void handleCacheClose(SystemMemberCacheEvent event) {
Helper.sendNotification(this, new Notification(NOTIF_CACHE_CLOSED, this.modelMBean,
Helper.getNextNotificationSequenceNumber(), Helper.getCacheEventDetails(event)));
}
/**
* Implementation handles creation of region by extracting the details from the given event object
* and sending the {@link SystemMemberJmx#NOTIF_REGION_CREATED} notification to the connected JMX
* Clients. Region Path is set as User Data in Notification.
*
* @param event event object corresponding to the creation of a region
*/
@Override
public void handleRegionCreate(SystemMemberRegionEvent event) {
Notification notification = new Notification(NOTIF_REGION_CREATED, this.modelMBean,
Helper.getNextNotificationSequenceNumber(), Helper.getRegionEventDetails(event));
notification.setUserData(event.getRegionPath());
Helper.sendNotification(this, notification);
}
/**
* Implementation should handle loss of region by extracting the details from the given event
* object and sending the {@link SystemMemberJmx#NOTIF_REGION_LOST} notification to the connected
* JMX Clients. Region Path is set as User Data in Notification. Additionally, it also clears the
* ManagedResources created for the region that is lost.
*
* @param event event object corresponding to the loss of a region
*/
@Override
public void handleRegionLoss(SystemMemberRegionEvent event) {
SystemMemberCacheJmxImpl cacheResource = this.managedSystemMemberCache;
if (cacheResource != null) {
ManagedResource cleanedUp = cacheResource.cleanupRegionResources(event.getRegionPath());
if (cleanedUp != null) {
MBeanUtil.unregisterMBean(cleanedUp);
}
}
Notification notification = new Notification(NOTIF_REGION_LOST, this.modelMBean,
Helper.getNextNotificationSequenceNumber(), Helper.getRegionEventDetails(event));
notification.setUserData(event.getRegionPath());
Helper.sendNotification(this, notification);
}
}