blob: 1445448a80240d47501aac8bd8b515fd4330d68b [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 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.logging.internal.log4j.api.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();
}
}