/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. All Rights Reserved.
*
* Licensed 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 com.hazelcast.jmx;
import com.hazelcast.core.*;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Manager of data instances and collects general statistics.
*
* @author Marco Ferrante, DISI - University of Genova
*/
@JMXDescription("Cluster statistics")
public class DataMBean extends AbstractMBean<HazelcastInstance> implements InstanceListener {
private final static Logger logger = Logger.getLogger(DataMBean.class.getName());
private StatisticsCollector creationStats = null;
private StatisticsCollector destructionStats = null;
/**
* Return the instrumentation wrapper to a instance.
* See http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/best-practices.jsp
*
* @param instance
* @return dynamic mbean for the hazelcast instance
* @throws Exception
*/
private AbstractMBean buildMBean(Instance instance) throws Exception {
if (instance.getInstanceType().isTopic()) {
return new TopicMBean((ITopic) instance, managementService);
}
if (instance.getInstanceType().isQueue()) {
return new QueueMBean((IQueue) instance, managementService);
}
if (instance.getInstanceType().isList()) {
return new ListMBean((IList) instance, managementService);
}
if (instance.getInstanceType().isSet()) {
return new SetMBean((ISet) instance, managementService);
}
if (instance.getInstanceType().isMultiMap()) {
return new MultiMapMBean((MultiMap) instance, managementService);
}
if (instance.getInstanceType().isMap()) {
return new MapMBean((IMap) instance, managementService);
}
if (instance.getInstanceType().isLock()) {
return new LockMBean((ILock) instance, managementService);
}
if (instance.getInstanceType().isAtomicNumber()) {
return new AtomicNumberMBean((AtomicNumber) instance, managementService);
}
if (instance.getInstanceType().isCountDownLatch()) {
return new CountDownLatchMBean((ICountDownLatch) instance, managementService);
}
if (instance.getInstanceType().isSemaphore()) {
return new SemaphoreMBean((ISemaphore) instance, managementService);
}
return null;
}
protected DataMBean(ManagementService managementService) {
super(managementService.getInstance(), managementService);
}
@Override
public ObjectNameSpec getNameSpec() {
return getParentName().getNested("Statistics");
}
public void postRegister(Boolean registrationDone) {
if (registrationDone) {
creationStats = ManagementService.newStatisticsCollector();
destructionStats = ManagementService.newStatisticsCollector();
getManagedObject().addInstanceListener(this);
for (final Instance instance : getManagedObject().getInstances()) {
registerInstance(instance);
}
}
}
public void preDeregister() throws Exception {
getManagedObject().removeInstanceListener(this);
if (creationStats != null) {
creationStats.destroy();
creationStats = null;
}
if (destructionStats != null) {
destructionStats.destroy();
destructionStats = null;
}
}
public void postDeregister() {
// Required by MBeanRegistration interface
}
public void instanceCreated(InstanceEvent event) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Received created notification {0} {1}",
new String[]{event.getInstance().getInstanceType().toString(), event.getInstance().toString()});
}
if (creationStats != null) {
creationStats.addEvent();
}
registerInstance(event.getInstance());
}
public void instanceDestroyed(InstanceEvent event) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Received destroyed notification " + event.getInstance().toString());
}
if (destructionStats != null) {
destructionStats.addEvent();
}
unregisterInstance(event.getInstance());
}
public void registerInstance(Object instance) {
try {
AbstractMBean mbean = buildMBean((Instance) instance);
if (mbean == null) {
logger.log(Level.FINE, "Unsupported instance type " + instance.getClass().getName());
} else {
mbean.setParentName(getParentName());
ObjectName name = mbean.getObjectName();
logger.log(Level.FINEST, "Register MBean {0}", name);
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//noinspection SynchronizeOnThis
synchronized (this) {
if (!mbs.isRegistered(name)) {
mbs.registerMBean(mbean, name);
}
}
}
} catch (Exception e) {
logger.log(Level.FINE, "Unable to register MBean", e);
}
}
public void unregisterInstance(Object instance) {
try {
AbstractMBean mbean = buildMBean((Instance) instance);
if (mbean == null) {
logger.log(Level.FINE, "Unsupported instance type " + instance.getClass().getName());
} else {
mbean.setParentName(getParentName());
ObjectName name = mbean.getObjectName();
logger.log(Level.FINEST, "Unregister MBean {0}", name);
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//noinspection SynchronizeOnThis
synchronized (this) {
if (mbs.isRegistered(name)) {
mbs.unregisterMBean(name);
}
}
}
} catch (Exception e) {
logger.log(Level.FINE, "Unable to unregister MBean", e);
}
}
/**
* Resets statistics
*/
@JMXOperation("resetStats")
public void resetStats() {
if (creationStats != null)
creationStats.reset();
if (destructionStats != null)
destructionStats.reset();
}
@JMXAttribute("InstanceCount")
@JMXDescription("Total data structures registered")
public int getInstanceCount() {
Collection<Instance> instances = getManagedObject().getInstances();
return instances.size();
}
@JMXAttribute("InstancesCreated")
@JMXDescription("Total instances created since startup")
public long getInstancesCreated() {
return creationStats.getTotal();
}
@JMXAttribute("InstancesCreatedLast")
@JMXDescription("Instances created in the last second")
public double getInstancesCreatedAvg() {
return creationStats.getAverage();
}
@JMXAttribute("InstancesCreatedPeak")
@JMXDescription("Max instances created per second")
public double getInstancesCreatedMax() {
return creationStats.getMax();
}
@JMXAttribute("InstancesDestroyed")
@JMXDescription("Total instances destroyed since startup")
public long getInstancesDestroyed() {
return destructionStats.getTotal();
}
@JMXAttribute("InstancesDestroyedLast")
@JMXDescription("Instances destroyed in the last second")
public double getInstancesDestroyedAvg() {
return destructionStats.getAverage();
}
@JMXAttribute("InstancesDestroyedPeak")
@JMXDescription("Max instances destroyed per second")
public double getInstancesDestroyedMax() {
return destructionStats.getMax();
}
}