/* * 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 org.apache.geode.SystemFailure; import org.apache.geode.admin.*; import org.apache.geode.cache.Operation; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.admin.ClientMembershipMessage; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LocalizedMessage; import org.apache.commons.modeler.ManagedBean; import org.apache.logging.log4j.Logger; import javax.management.*; import javax.naming.OperationNotSupportedException; import java.util.concurrent.atomic.AtomicInteger; /** * Defines methods that all <code>SystemMember</code> MBeans should implement. * * @since GemFire 4.0 */ public interface SystemMemberJmx extends SystemMember, NotificationListener { /** * Notification type for indicating a cache got created on a member of this distributed system. */ public static final String NOTIF_CACHE_CREATED = DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.created"; /** * Notification type for indicating a cache is closed on a member of this distributed system. */ public static final String NOTIF_CACHE_CLOSED = DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.closed"; /** * Notification type for indicating a region is created in a cache on a member of this distributed * system. */ public static final String NOTIF_REGION_CREATED = DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.region.created"; /** * Notification type for indicating a region was removed from a cache on a member of this * distributed system. */ public static final String NOTIF_REGION_LOST = DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.region.lost"; /** Notification type for indicating client joined */ public static final String NOTIF_CLIENT_JOINED = DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.client.joined"; /** Notification type for indicating client left */ public static final String NOTIF_CLIENT_LEFT = DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.client.left"; /** Notification type for indicating client crashed */ public static final String NOTIF_CLIENT_CRASHED = DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.client.crashed"; /** * Gets the interval in seconds between config refreshes * * @return the current refresh interval in seconds */ public int getRefreshInterval(); /** * 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 */ @Deprecated public void setRefreshInterval(int refreshInterval) throws OperationNotSupportedException; /** * Sets the refresh interval field. Sets interval in seconds between config refreshes; zero or * less turns off auto refreshing. Manual refreshing has no effect on when the next scheduled * refresh will occur. */ public void _setRefreshInterval(int refreshInterval); /** * 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 */ public ObjectName manageCache() throws AdminException, MalformedObjectNameException; /** * Gets all active StatisticResources for this manager. * * @return array of ObjectName instances */ public ObjectName[] manageStats() throws AdminException, MalformedObjectNameException; /** * Gets the active StatisticResources for this manager, based on the typeName as the key * * @return ObjectName of StatisticResourceJMX instance */ public ObjectName[] manageStat(String statisticsTypeName) throws AdminException, MalformedObjectNameException; /** * Handles notification to refresh. Reacts by refreshing the values of this GemFireManager's * ConfigurationParamaters. Any other notification is ignored. * * @param notification the JMX notification being received * @param hb handback object is unused */ public void handleNotification(Notification notification, Object hb); /** * 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 */ public ManagedBean addDynamicAttributes(ManagedBean managed) throws AdminException; /** * Implementation should handle creation of cache by extracting the details from the given event * object. * * @param event event object corresponding to the creation of the cache */ public void handleCacheCreate(SystemMemberCacheEvent event); /** * Implementation should handle closure of cache by extracting the details from the given event * object. * * @param event event object corresponding to the closure of the cache */ public void handleCacheClose(SystemMemberCacheEvent event); /** * Implementation should handle creation of region by extracting the details from the given event * object. * * @param event event object corresponding to the creation of a region */ public void handleRegionCreate(SystemMemberRegionEvent event); /** * Implementation should handle loss of region by extracting the details from the given event * object. * * @param event event object corresponding to the loss of a region */ public void handleRegionLoss(SystemMemberRegionEvent event); /** * Implementation should handle 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} */ public void handleClientMembership(String clientId, int eventType); ////////////////////// Inner Classess ////////////////////// /** * A helper class that provides implementation of the <code>SystemMemberJmx</code> interface as * static methods. */ public static class Helper { private static final Logger logger = LogService.getLogger(); private static AtomicInteger notificationSequenceNumber = new AtomicInteger(); public static int setAndReturnRefreshInterval(SystemMemberJmx member, int refreshInterval) { int ret = refreshInterval; try { MBeanUtil.registerRefreshNotification(member, // NotificationListener ((ManagedResource) member).getMBeanName(), // User Data RefreshNotificationType.SYSTEM_MEMBER_CONFIG, refreshInterval); // int } catch (RuntimeException e) { logger.warn(e.getMessage(), e); // dead in water, print, and then ignore ret = 0; // zero out to avoid more exceptions } catch (VirtualMachineError err) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } catch (Error e) { // Whenever you catch Error or Throwable, you must also // catch VirtualMachineError (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); logger.error(e.getMessage(), e); // dead in water, print, and then ignore ret = 0; // zero out to avoid more exceptions } return ret; } public static ObjectName manageCache(SystemMemberJmx member) throws AdminException, MalformedObjectNameException { boolean IthrewIt = false; try { SystemMemberCache cache = member.getCache(); if (cache == null) { IthrewIt = true; throw new AdminException( LocalizedStrings.SystemMemberJmx_THIS_SYSTEM_MEMBER_DOES_NOT_HAVE_A_CACHE .toLocalizedString()); } // Assert.assertTrue(cache != null); (cannot be null) SystemMemberCacheJmxImpl cacheJmx = (SystemMemberCacheJmxImpl) cache; return ObjectName.getInstance(cacheJmx.getMBeanName()); } catch (AdminException e) { if (!IthrewIt) { logger.warn(e.getMessage(), e); } throw e; } catch (RuntimeException e) { logger.warn(e.getMessage(), e); throw e; } catch (VirtualMachineError err) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } catch (Error e) { // Whenever you catch Error or Throwable, you must also // catch VirtualMachineError (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); logger.error(e.getMessage(), e); throw e; } } public static ObjectName[] manageStats(SystemMemberJmx member) throws AdminException, MalformedObjectNameException { try { StatisticResource[] stats = member.getStats(); ObjectName[] onames = new ObjectName[stats.length]; for (int i = 0; i < stats.length; i++) { StatisticResourceJmxImpl stat = (StatisticResourceJmxImpl) stats[i]; onames[i] = ObjectName.getInstance(stat.getMBeanName()); } return onames; } catch (AdminException e) { logger.warn(e.getMessage(), e); throw e; } catch (RuntimeException e) { logger.warn(e.getMessage(), e); throw e; } catch (VirtualMachineError err) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } catch (Error e) { // Whenever you catch Error or Throwable, you must also // catch VirtualMachineError (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); logger.error(e.getMessage(), e); throw e; } } public static ObjectName[] manageStat(SystemMemberJmx member, String statisticsTypeName) throws AdminException, MalformedObjectNameException { try { StatisticResource[] stats = member.getStat(statisticsTypeName); if (stats == null) return null; else { ObjectName[] statNames = new ObjectName[stats.length]; for (int i = 0; i < stats.length; i++) { StatisticResourceJmxImpl statJMX = (StatisticResourceJmxImpl) stats[i]; statNames[i] = ObjectName.getInstance(statJMX.getMBeanName()); } return statNames; } } catch (AdminException e) { logger.warn(e.getMessage(), e); throw e; } catch (RuntimeException e) { logger.warn(e.getMessage(), e); throw e; } catch (Error e) { logger.error(e.getMessage(), e); throw e; } } public static void handleNotification(SystemMemberJmx member, Notification notification, Object hb) { if (RefreshNotificationType.SYSTEM_MEMBER_CONFIG.getType().equals(notification.getType()) && ((ManagedResource) member).getMBeanName().equals(notification.getUserData())) { try { member.refreshConfig(); } catch (org.apache.geode.admin.AdminException e) { logger.warn(e.getMessage(), e); } catch (OperationCancelledException e) { // underlying resource is no longer reachable by remote admin logger.warn(e.getMessage(), e); member._setRefreshInterval(0); } catch (java.lang.RuntimeException e) { logger.warn(e.getMessage(), e); // dead in water, print, and then ignore member._setRefreshInterval(0); // zero out to avoid more exceptions } catch (VirtualMachineError err) { SystemFailure.initiateFailure(err); // If this ever returns, rethrow the error. We're poisoned // now, so don't let this thread continue. throw err; } catch (java.lang.Error e) { // Whenever you catch Error or Throwable, you must also // catch VirtualMachineError (see above). However, there is // _still_ a possibility that you are dealing with a cascading // error condition, so you also need to check to see if the JVM // is still usable: SystemFailure.checkFailure(); logger.error(e.getMessage(), e); // dead in water, print, and then ignore member._setRefreshInterval(0); // zero out to avoid more exceptions } } } public static ManagedBean addDynamicAttributes(SystemMemberJmx member, ManagedBean managed) throws AdminException { if (managed == null) { throw new IllegalArgumentException( LocalizedStrings.SystemMemberJmx_MANAGEDBEAN_IS_NULL.toLocalizedString()); } member.refreshConfig(); // to get the config parms... // need to create a new instance of ManagedBean to clean the "slate"... ManagedBean newManagedBean = new DynamicManagedBean(managed); ConfigurationParameter[] params = member.getConfiguration(); for (int i = 0; i < params.length; i++) { ConfigurationParameterJmxImpl parm = (ConfigurationParameterJmxImpl) params[i]; ConfigAttributeInfo attrInfo = new ConfigAttributeInfo(parm); attrInfo.setName(parm.getName()); attrInfo.setDisplayName(parm.getName()); attrInfo.setDescription(parm.getDescription()); attrInfo.setType(parm.getJmxValueType().getName()); attrInfo.setIs(false); attrInfo.setReadable(true); attrInfo.setWriteable(parm.isModifiable()); newManagedBean.addAttribute(attrInfo); } return newManagedBean; } /** * Returns the next notification sequence number. * * @return the notificationSequenceNumber */ /* default */static int getNextNotificationSequenceNumber() { return notificationSequenceNumber.incrementAndGet(); } /** * Returns the cache event details extracted from the given SystemMemberCacheEvent * * @param event SystemMemberCacheEvent instance * @return the cache event details extracted from the given SystemMemberCacheEvent */ /* default */static String getCacheEventDetails(SystemMemberCacheEvent event) { String memberId = event.getMemberId(); Operation operation = event.getOperation(); return "CacheEvent[MemberId: " + memberId + ", operation: " + operation + "]"; } /** * Returns the region event details extracted from the given SystemMemberRegionEvent * * @param event SystemMemberRegionEvent instance * @return the cache event details extracted from the given SystemMemberRegionEvent */ /* default */static String getRegionEventDetails(SystemMemberRegionEvent event) { String memberId = event.getMemberId(); Operation operation = event.getOperation(); return "RegionEvent[MemberId: " + memberId + ", operation: " + operation + ", region:" + event.getRegionPath() + "]"; } /** * Sends the given notification. * * @param notif notification to send * * @throws NullPointerException if resource or ModelMBean for resource is null */ /* default */static void sendNotification(ManagedResource resource, Notification notif) { try { if (MBeanUtil.isRegistered(resource.getObjectName())) { resource.getModelMBean().sendNotification(notif); if (logger.isDebugEnabled()) { logger.debug("Sent '{}' notification", notif.getType()); } } } catch (RuntimeOperationsException e) { logger .info( LocalizedMessage.create( LocalizedStrings.SystemMemberJmx_FAILED_TO_SEND_0_NOTIFICATION_FOR_1, new Object[] {"'" + notif.getType() + "'", "'" + notif.getMessage() + "'"}), e); } catch (MBeanException e) { logger .info( LocalizedMessage.create( LocalizedStrings.SystemMemberJmx_FAILED_TO_SEND_0_NOTIFICATION_FOR_1, new Object[] {"'" + notif.getType() + "'", "'" + notif.getMessage() + "'"}), e); } } } }