package com.taobao.tddl.common.utils.mbean;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import com.taobao.tddl.common.utils.logger.Logger;
import com.taobao.tddl.common.utils.logger.LoggerFactory;
public class TddlMBeanServer {
private static final Logger log = LoggerFactory.getLogger(TddlMBeanServer.class);
private static final String LogPrefix = "[TddlMBeanServer]";
private MBeanServer mbs = null;
private ConcurrentHashMap<String, ConcurrentHashMap<String, AtomicLong>> idMap = new ConcurrentHashMap<String, ConcurrentHashMap<String, AtomicLong>>();
private ReentrantLock lock = new ReentrantLock();
private static ConcurrentHashMap<String, ObjectName> beanNameHolder = new ConcurrentHashMap<String, ObjectName>();
public static boolean shutDownMBean = true;
private static class Holder {
private static final TddlMBeanServer instance = new TddlMBeanServer();
}
private TddlMBeanServer(){
// 创建MBServer
String hostName = null;
try {
InetAddress addr = InetAddress.getLocalHost();
hostName = addr.getHostName();
} catch (IOException e) {
log.error(LogPrefix + "Get HostName Error", e);
hostName = "localhost";
}
String host = System.getProperty("hostName", hostName);
try {
boolean useJmx = Boolean.parseBoolean(System.getProperty("tddl.useJMX", "true"));
if (useJmx) {
mbs = ManagementFactory.getPlatformMBeanServer();
int port = Integer.parseInt(System.getProperty("tddl.rmi.port", "6679"));
String rmiName = System.getProperty("tddl.rmi.name", "tddlJmxServer");
Registry reg = null;
try {
reg = LocateRegistry.getRegistry(port);
reg.list();
} catch (Exception e) {
reg = null;
}
if (null == reg) {
reg = LocateRegistry.createRegistry(port);
}
reg.list();
String serverURL = "service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/" + rmiName;
JMXServiceURL url = new JMXServiceURL(serverURL);
final JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url,
null,
mbs);
connectorServer.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
System.err.println("JMXConnector stop");
connectorServer.stop();
} catch (IOException e) {
log.error(LogPrefix + e);
}
}
});
log.warn(LogPrefix + "jmx url: " + serverURL);
}
} catch (Exception e) {
log.error(LogPrefix + "create MBServer error", e);
}
}
public static void registerMBean(Object o, String name) {
if (!shutDownMBean) {
Holder.instance.registerMBean0(o, name);
}
}
public static void registerMBeanWithId(Object o, String id) {
if (!shutDownMBean) {
Holder.instance.registerMBeanWithId0(o, id);
}
}
public static void registerMBeanWithIdPrefix(Object o, String idPrefix) {
if (!shutDownMBean) {
Holder.instance.registerMBeanWithIdPrefix0(o, idPrefix);
}
}
private void registerMBean0(Object o, String name) {
// 注册MBean
if (beanServerExist()) {
String beanName = o.getClass().getPackage().getName() + ":type=" + o.getClass().getSimpleName()
+ (null == name ? (",id=" + o.hashCode()) : (",name=" + name + "-" + o.hashCode()));
realRegisterMBean(o, beanName);
}
}
private void registerMBeanWithId0(Object o, String id) {
// 注册MBean
if (null == id || id.length() == 0) {
throw new IllegalArgumentException("must set id");
}
if (beanServerExist()) {
String name = o.getClass().getPackage().getName() + ":type=" + o.getClass().getSimpleName() + ",id=" + id;
realRegisterMBean(o, name);
}
}
private String getId(String name, String idPrefix) {
ConcurrentHashMap<String, AtomicLong> subMap = idMap.get(name);
if (null == subMap) {
lock.lock();
try {
subMap = idMap.get(name);
if (null == subMap) {
subMap = new ConcurrentHashMap<String, AtomicLong>();
idMap.put(name, subMap);
}
} finally {
lock.unlock();
}
}
AtomicLong indexValue = subMap.get(idPrefix);
if (null == indexValue) {
lock.lock();
try {
indexValue = subMap.get(idPrefix);
if (null == indexValue) {
indexValue = new AtomicLong(0);
subMap.put(idPrefix, indexValue);
}
} finally {
lock.unlock();
}
}
long value = indexValue.incrementAndGet();
String result = idPrefix + "-" + value;
return result;
}
private void registerMBeanWithIdPrefix0(Object o, String idPrefix) {
// 注册MBean
if (beanServerExist()) {
if (null == idPrefix || idPrefix.length() == 0) {
idPrefix = "default";
}
idPrefix = idPrefix.replace(":", "-");
String id = this.getId(o.getClass().getName(), idPrefix);
String name = o.getClass().getPackage().getName() + ":type=" + o.getClass().getSimpleName() + ",id=" + id;
realRegisterMBean(o, name);
}
}
private void realRegisterMBean(Object o, String name) {
try {
ObjectName objectName = new ObjectName(name);
realRegisterMBean(o, objectName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private boolean beanServerExist() {
return mbs != null;
}
private synchronized void realRegisterMBean(Object o, ObjectName objectName) throws InstanceAlreadyExistsException,
MBeanRegistrationException,
NotCompliantMBeanException {
ObjectName old = beanNameHolder.putIfAbsent(objectName.getCanonicalName(), objectName);
if (old == null) {
mbs.registerMBean(o, objectName);
return;
}
log.error("same mbean try to register to BeanServer, reject! bean id is : " + objectName.getCanonicalName());
}
public void unRegisterAllSelfMBean() throws MBeanRegistrationException, InstanceNotFoundException {
for (ObjectName objectName : beanNameHolder.values()) {
if (beanServerExist()) mbs.unregisterMBean(objectName);
}
}
public static void removeAllMBean() throws MBeanRegistrationException, InstanceNotFoundException {
Holder.instance.unRegisterAllSelfMBean();
}
}