| /* |
| * 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.concurrent.atomic.AtomicInteger; |
| |
| import javax.management.MBeanException; |
| import javax.management.MalformedObjectNameException; |
| import javax.management.Notification; |
| import javax.management.NotificationListener; |
| import javax.management.ObjectName; |
| import javax.management.RuntimeOperationsException; |
| import javax.naming.OperationNotSupportedException; |
| |
| import org.apache.commons.modeler.ManagedBean; |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.SystemFailure; |
| import org.apache.geode.admin.AdminException; |
| import org.apache.geode.admin.ConfigurationParameter; |
| import org.apache.geode.admin.OperationCancelledException; |
| import org.apache.geode.admin.StatisticResource; |
| import org.apache.geode.admin.SystemMember; |
| import org.apache.geode.admin.SystemMemberCache; |
| import org.apache.geode.admin.SystemMemberCacheEvent; |
| import org.apache.geode.admin.SystemMemberRegionEvent; |
| import org.apache.geode.annotations.internal.MakeNotStatic; |
| import org.apache.geode.cache.Operation; |
| import org.apache.geode.internal.admin.ClientMembershipMessage; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| import org.apache.geode.util.internal.GeodeGlossary; |
| |
| /** |
| * Defines methods that all <code>SystemMember</code> MBeans should implement. |
| * |
| * @since GemFire 4.0 |
| */ |
| @Deprecated |
| public interface SystemMemberJmx extends SystemMember, NotificationListener { |
| /** |
| * Notification type for indicating a cache got created on a member of this distributed system. |
| */ |
| String NOTIF_CACHE_CREATED = |
| GeodeGlossary.GEMFIRE_PREFIX + "distributedsystem.cache.created"; |
| /** |
| * Notification type for indicating a cache is closed on a member of this distributed system. |
| */ |
| String NOTIF_CACHE_CLOSED = GeodeGlossary.GEMFIRE_PREFIX + "distributedsystem.cache.closed"; |
| /** |
| * Notification type for indicating a region is created in a cache on a member of this distributed |
| * system. |
| */ |
| String NOTIF_REGION_CREATED = |
| GeodeGlossary.GEMFIRE_PREFIX + "distributedsystem.cache.region.created"; |
| /** |
| * Notification type for indicating a region was removed from a cache on a member of this |
| * distributed system. |
| */ |
| String NOTIF_REGION_LOST = |
| GeodeGlossary.GEMFIRE_PREFIX + "distributedsystem.cache.region.lost"; |
| |
| /** Notification type for indicating client joined */ |
| String NOTIF_CLIENT_JOINED = |
| GeodeGlossary.GEMFIRE_PREFIX + "distributedsystem.cache.client.joined"; |
| |
| /** Notification type for indicating client left */ |
| String NOTIF_CLIENT_LEFT = |
| GeodeGlossary.GEMFIRE_PREFIX + "distributedsystem.cache.client.left"; |
| |
| /** Notification type for indicating client crashed */ |
| String NOTIF_CLIENT_CRASHED = |
| GeodeGlossary.GEMFIRE_PREFIX + "distributedsystem.cache.client.crashed"; |
| |
| /** |
| * Gets the interval in seconds between config refreshes |
| * |
| * @return the current refresh interval in seconds |
| */ |
| 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 |
| 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. |
| */ |
| 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 |
| */ |
| ObjectName manageCache() throws AdminException, MalformedObjectNameException; |
| |
| /** |
| * Gets all active StatisticResources for this manager. |
| * |
| * @return array of ObjectName instances |
| */ |
| ObjectName[] manageStats() throws AdminException, MalformedObjectNameException; |
| |
| /** |
| * Gets the active StatisticResources for this manager, based on the typeName as the key |
| * |
| * @return ObjectName of StatisticResourceJMX instance |
| */ |
| 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 |
| */ |
| @Override |
| 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 |
| */ |
| 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 |
| */ |
| 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 |
| */ |
| 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 |
| */ |
| 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 |
| */ |
| 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} |
| */ |
| void handleClientMembership(String clientId, int eventType); |
| |
| ////////////////////// Inner Classess ////////////////////// |
| |
| /** |
| * A helper class that provides implementation of the <code>SystemMemberJmx</code> interface as |
| * static methods. |
| */ |
| class Helper { |
| private static final Logger logger = LogService.getLogger(); |
| |
| @MakeNotStatic |
| private static final AtomicInteger notificationSequenceNumber = new AtomicInteger(); |
| |
| public static int setAndReturnRefreshInterval(SystemMemberJmx member, int refreshInterval) { |
| int ret = refreshInterval; |
| |
| try { |
| MBeanUtils.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( |
| "This System Member does not have a Cache."); |
| } |
| 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( |
| "ManagedBean is null"); |
| } |
| |
| 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 (final ConfigurationParameter param : params) { |
| ConfigurationParameterJmxImpl parm = (ConfigurationParameterJmxImpl) param; |
| 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 (MBeanUtils.isRegistered(resource.getObjectName())) { |
| resource.getModelMBean().sendNotification(notif); |
| if (logger.isDebugEnabled()) { |
| logger.debug("Sent '{}' notification", notif.getType()); |
| } |
| } |
| } catch (RuntimeOperationsException e) { |
| logger |
| .info(String.format("Failed to send %s notification for %s", |
| "'" + notif.getType() + "'", "'" + notif.getMessage() + "'"), |
| e); |
| } catch (MBeanException e) { |
| logger |
| .info(String.format("Failed to send %s notification for %s", |
| "'" + notif.getType() + "'", "'" + notif.getMessage() + "'"), |
| e); |
| } |
| } |
| } |
| } |