| /* |
| * 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.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.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( |
| "RefreshInterval can not be set directly. Use DistributedSystemConfig.refreshInterval."); |
| } |
| |
| // ------------------------------------------------------------------------- |
| // 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 |
| */ |
| @Override |
| 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( |
| "ManagedBean is null"); |
| } |
| |
| 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; |
| } |
| |
| @Override |
| 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; |
| |
| @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.STATISTIC_RESOURCE; |
| } |
| |
| @Override |
| 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(); |
| } |
| } |