blob: df5b0b67a0ff017c0f109917ce455e0ff8d68be5 [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.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.ConfigurationParameterImpl;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.admin.ApplicationVM;
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.logging.internal.log4j.api.LogService;
/**
* Provides MBean support for managing a SystemMember application.
* <p>
* TODO: refactor to implement SystemMember and delegate to SystemMemberImpl. Wrap all delegate
* calls w/ e.printStackTrace() since the HttpAdaptor devours them
*
* @since GemFire 3.5
*
*/
@Deprecated
public class SystemMemberJmxImpl extends org.apache.geode.admin.internal.SystemMemberImpl
implements SystemMemberJmx, javax.management.NotificationListener,
org.apache.geode.admin.jmx.internal.ManagedResource {
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 JMX object name of this managed resource */
private ObjectName objectName;
/** 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 final Map<StatResource, StatisticResourceJmxImpl> managedStatisticsResourcesMap =
new HashMap<>();
// -------------------------------------------------------------------------
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Constructs an instance of SystemMemberJmxImpl.
*
* @param system the distributed system this SystemMember is a member of
* @param application the internal admin application to delegate actual work
*/
public SystemMemberJmxImpl(AdminDistributedSystemJmxImpl system, ApplicationVM application)
throws org.apache.geode.admin.AdminException {
super(system, application);
initializeMBean();
}
/**
* Constructs the instance of SystemMember using the corresponding InternalDistributedMember
* instance of a DS member for the given AdminDistributedSystem.
*
* @param system Current AdminDistributedSystem instance
* @param member InternalDistributedMember instance for which a SystemMember instance is to be
* constructed.
* @throws AdminException if construction of SystemMember fails
*
* @since GemFire 6.5
*/
protected SystemMemberJmxImpl(AdminDistributedSystemJmxImpl system,
InternalDistributedMember member) throws AdminException {
super(system, member);
initializeMBean();
}
/** Create and register the MBean to manage this resource */
private void initializeMBean() throws org.apache.geode.admin.AdminException {
mbeanName = "GemFire.Member:id="
+ MBeanUtils.makeCompliantMBeanNameProperty(getId()) + ",type="
+ MBeanUtils.makeCompliantMBeanNameProperty(getType().getName());
objectName =
MBeanUtils.createMBean(this, addDynamicAttributes(MBeanUtils.lookupManagedBean(this)));
// Refresh Interval
AdminDistributedSystemJmxImpl sysJmx = (AdminDistributedSystemJmxImpl) system;
if (sysJmx.getRefreshInterval() > 0) {
refreshInterval = sysJmx.getRefreshInterval();
}
}
// -------------------------------------------------------------------------
// MBean attributes - accessors/mutators
// -------------------------------------------------------------------------
/**
* Gets the interval in seconds between config refreshes
*
* @return the current refresh interval in seconds
*/
@Override
public int getRefreshInterval() {
return refreshInterval;
}
/**
* RefreshInterval is now set only through the AdminDistributedSystem property refreshInterval.
* Attempt to set refreshInterval on SystemMemberJmx 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.");
}
/**
* Sets interval in seconds between member 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 = MBeanUtils.isRefreshNotificationRegistered(this,
RefreshNotificationType.SYSTEM_MEMBER_CONFIG);
if (isRegistered && (getRefreshInterval() == refreshInterval)) {
return;
}
this.refreshInterval = Helper.setAndReturnRefreshInterval(this, 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 (refreshInterval > 0) {
_setRefreshInterval(refreshInterval);
}
super.refreshConfig();
}
/**
* Gets this member's cache.
*
* @return <code>ObjectName</code> for this member's cache
*
* @throws AdminException If this system member does not host a 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 SystemMember'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) 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 (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 AdminException {
return Helper.addDynamicAttributes(this, managed);
}
// -------------------------------------------------------------------------
// ManagedResource implementation
// -------------------------------------------------------------------------
/** 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;
@Override
public String getMBeanName() {
return mbeanName;
}
@Override
public ModelMBean getModelMBean() {
return modelMBean;
}
@Override
public void setModelMBean(ModelMBean modelMBean) {
this.modelMBean = modelMBean;
}
@Override
public ObjectName getObjectName() {
return objectName;
}
@Override
public ManagedResourceType getManagedResourceType() {
return ManagedResourceType.SYSTEM_MEMBER;
}
/**
* Un-registers all the statistics & cache managed resource created for this member. After
* un-registering the resource MBean instances, clears managedStatisticsResourcesMap collection.
*/
@Override
public void cleanupResource() {
synchronized (managedStatisticsResourcesMap) {
ConfigurationParameter[] names = getConfiguration();
if (names != null) {
for (ConfigurationParameter parm : names) {
((ConfigurationParameterImpl) parm).removeConfigurationParameterListener(this);
}
}
parms.clear();
Collection<StatisticResourceJmxImpl> statisticResources =
managedStatisticsResourcesMap.values();
for (StatisticResourceJmxImpl statisticResource : statisticResources) {
MBeanUtils.unregisterMBean(statisticResource);
}
managedStatisticsResourcesMap.clear();
}
MBeanUtils.unregisterMBean(managedSystemMemberCache);
}
/**
* 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<>();
String compatibleId = "id_" + MBeanUtils.makeCompliantMBeanNameProperty(clientId);
synchronized (managedStatisticsResourcesMap) {
Set<Entry<StatResource, StatisticResourceJmxImpl>> entrySet =
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) {
MBeanUtils.unregisterMBean(resource);
}
}
Helper.sendNotification(this, new Notification(notifType, 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, 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, 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, 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 = managedSystemMemberCache;
if (cacheResource != null) {
ManagedResource cleanedUp = cacheResource.cleanupRegionResources(event.getRegionPath());
if (cleanedUp != null) {
MBeanUtils.unregisterMBean(cleanedUp);
}
}
Notification notification = new Notification(NOTIF_REGION_LOST, modelMBean,
Helper.getNextNotificationSequenceNumber(), Helper.getRegionEventDetails(event));
notification.setUserData(event.getRegionPath());
Helper.sendNotification(this, notification);
}
}