/* * 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 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.CancelException; import org.apache.geode.LogWriter; import org.apache.geode.SystemFailure; import org.apache.geode.admin.AdminException; import org.apache.geode.admin.Statistic; import org.apache.geode.internal.admin.StatResource; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; /** * Provides MBean support for the monitoring of a statistic resource. * * @since GemFire 3.5 * */ public class StatisticResourceJmxImpl extends org.apache.geode.admin.internal.StatisticResourceImpl implements javax.management.NotificationListener, org.apache.geode.admin.jmx.internal.ManagedResource { private static final Logger logger = LogService.getLogger(); /** * Interval in seconds between refreshes. Values less than one results in no refreshing . */ private int refreshInterval = 0; /** The JMX object name of this managed resource */ private ObjectName objectName; /** A flag to indicate if time is inited. MBeanUtil lookup is costly */ private boolean timerInited = false; // ------------------------------------------------------------------------- // Constructor(s) // ------------------------------------------------------------------------- /** * Constructor for the StatisticResource object * * @param statResource the admin StatResource to manage/monitor * @param member the SystemMember owning this resource * @exception org.apache.geode.admin.AdminException if unable to create this StatisticResource for * administration */ public StatisticResourceJmxImpl(StatResource statResource, SystemMemberJmx member) throws org.apache.geode.admin.AdminException { super(statResource, member); initializeMBean(); } /** Create and register the MBean to manage this resource */ private void initializeMBean() throws org.apache.geode.admin.AdminException { this.mbeanName = new StringBuffer("GemFire.Statistic:").append("source=") .append(MBeanUtil.makeCompliantMBeanNameProperty(this.member.getId())).append(",type=") .append(MBeanUtil.makeCompliantMBeanNameProperty(getType())).append(",name=") .append(MBeanUtil.makeCompliantMBeanNameProperty(getName())).append(",uid=") .append(getUniqueId()).toString(); this.objectName = MBeanUtil.createMBean(this, addDynamicAttributes(MBeanUtil.lookupManagedBean(this))); // Refresh Interval AdminDistributedSystemJmxImpl sysJmx = (AdminDistributedSystemJmxImpl) this.member.getDistributedSystem(); if (sysJmx.getRefreshInterval() > 0) this.refreshInterval = sysJmx.getRefreshInterval(); } // ------------------------------------------------------------------------- // MBean attributes - accessors/mutators // ------------------------------------------------------------------------- /** * Gets the interval in seconds between statistics refreshes * * @return the current refresh interval in seconds */ public int getRefreshInterval() { return this.refreshInterval; } /** * Sets interval in seconds between statistic 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 */ private void _setRefreshInterval(int refreshInterval) { boolean isRegistered = MBeanUtil.isRefreshNotificationRegistered(this, RefreshNotificationType.STATISTIC_RESOURCE_STATISTICS); if (isRegistered && (getRefreshInterval() == refreshInterval)) return; try { MBeanUtil.registerRefreshNotification(this, // NotificationListener getMBeanName(), // User Data as MBean Name RefreshNotificationType.STATISTIC_RESOURCE_STATISTICS, refreshInterval); // int this.refreshInterval = refreshInterval; timerInited = true; } catch (RuntimeException e) { logger.warn(e.getMessage(), e); // dead in water, print, and then ignore this.refreshInterval = 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 this.refreshInterval = 0; // zero out to avoid more exceptions } } /** * RefreshInterval is now set only through the AdminDistributedSystem property refreshInterval. * Attempt to set refreshInterval on StatisticResourceJmx MBean would result in an * OperationNotSupportedException Auto-refresh is enabled on demand when a call to getStatistics * 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 { throw new OperationNotSupportedException( LocalizedStrings.MANAGED_RESOURCE_REFRESH_INTERVAL_CANT_BE_SET_DIRECTLY .toLocalizedString()); } // ------------------------------------------------------------------------- // 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. * <p> * TODO: investigate use of NotificationFilter instead of explicit check... * * @param notification the JMX notification being received * @param hb handback object is unused */ public void handleNotification(Notification notification, Object hb) { AdminDistributedSystemJmxImpl adminDSJmx = (AdminDistributedSystemJmxImpl) this.member.getDistributedSystem(); String typeStatResourceStats = RefreshNotificationType.STATISTIC_RESOURCE_STATISTICS.getType(); if (typeStatResourceStats.equals(notification.getType()) && getMBeanName().equals(notification.getUserData()) && !adminDSJmx.isRmiClientCountZero()) { try { refresh(); } catch (org.apache.geode.admin.AdminException e) { logger.warn(e.getMessage(), e); } catch (org.apache.geode.admin.OperationCancelledException e) { // underlying resource is no longer reachable by remote admin logger.warn(e.getMessage(), e); _setRefreshInterval(0); } catch (CancelException e) { // shutting down - okay to ignore } catch (java.lang.RuntimeException e) { logger.debug(e.getMessage(), e); // dead in water, print, and then ignore _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 this.refreshInterval = 0; // zero out to avoid more exceptions } } } // ------------------------------------------------------------------------- // Create MBean attributes for each Statistic // ------------------------------------------------------------------------- /** * Add MBean attribute definitions for each Statistic. * * @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 org.apache.geode.admin.AdminException { if (managed == null) { throw new IllegalArgumentException( LocalizedStrings.StatisticResourceJmxImpl_MANAGEDBEAN_IS_NULL.toLocalizedString()); } refresh(); // to get the stats... // need to create a new instance of ManagedBean to clean the "slate"... ManagedBean newManagedBean = new DynamicManagedBean(managed); for (int i = 0; i < this.statistics.length; i++) { StatisticAttributeInfo attrInfo = new StatisticAttributeInfo(); attrInfo.setName(this.statistics[i].getName()); attrInfo.setDisplayName(this.statistics[i].getName()); attrInfo.setDescription(this.statistics[i].getDescription()); attrInfo.setType("java.lang.Number"); attrInfo.setIs(false); attrInfo.setReadable(true); attrInfo.setWriteable(false); attrInfo.setStat(this.statistics[i]); newManagedBean.addAttribute(attrInfo); } return newManagedBean; } public Statistic[] getStatistics() { if (!timerInited) { // 1st call to getStatistics would trigger // the auto-refresh if an interval is set if (this.refreshInterval > 0) { this._setRefreshInterval(this.refreshInterval); } } if (this.statistics == null) { try { this.refresh(); } catch (AdminException e) { this.statistics = new Statistic[0]; } } return this.statistics; } // ------------------------------------------------------------------------- // 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; public String getMBeanName() { return this.mbeanName; } public ModelMBean getModelMBean() { return this.modelMBean; } public void setModelMBean(ModelMBean modelMBean) { this.modelMBean = modelMBean; } public ObjectName getObjectName() { return this.objectName; } public ManagedResourceType getManagedResourceType() { return ManagedResourceType.STATISTIC_RESOURCE; } public void cleanupResource() { this.modelMBean = null; this.member = null; this.statistics = null; this.statResource = null; } /** * Checks equality of the given object with <code>this</code> based on the type (Class) and the * MBean Name returned by <code>getMBeanName()</code> methods. * * @param obj object to check equality with * @return true if the given object is if the same type and its MBean Name is same as * <code>this</code> object's MBean Name, false otherwise */ @Override public boolean equals(Object obj) { if (!(obj instanceof StatisticResourceJmxImpl)) { return false; } StatisticResourceJmxImpl other = (StatisticResourceJmxImpl) obj; return this.getMBeanName().equals(other.getMBeanName()); } /** * Returns hash code for <code>this</code> object which is based on the MBean Name generated. * * @return hash code for <code>this</code> object */ @Override public int hashCode() { return this.getMBeanName().hashCode(); } }