/**
* 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 com.datastax.drivers.jdbc.pool.cassandra.service;
import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.drivers.jdbc.pool.cassandra.connection.CassandraClientMonitor;
import com.datastax.drivers.jdbc.pool.cassandra.connection.HConnectionManager;
/**
* A JMX monitor singlton.
*
* @author Ran Tavory (ran@outbain.com)
*
*/
public class JmxMonitor {
private final Logger log = LoggerFactory.getLogger(getClass());
private MBeanServer mbs;
private static JmxMonitor monitorInstance;
private Map<String,CassandraClientMonitor> monitors;
private JmxMonitor() {
mbs = ManagementFactory.getPlatformMBeanServer();
monitors = new HashMap<String, CassandraClientMonitor>();
}
public static JmxMonitor getInstance() {
if ( monitorInstance == null ) {
monitorInstance = new JmxMonitor();
}
return monitorInstance;
}
public void registerMonitor(String name, String monitorType, Object monitoringInterface)
throws MalformedObjectNameException, InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
String monitorName = generateMonitorName(name, monitorType);
log.info("Registering JMX {}", monitorName);
ObjectName oName = new ObjectName(monitorName);
// Check if the monitor is already registered
if (mbs.isRegistered(oName)) {
log.info("Monitor already registered: {}", oName);
return;
}
mbs.registerMBean(monitoringInterface, oName);
}
private String generateMonitorName(String className, String monitorType) {
StringBuilder sb = new StringBuilder();
sb.append(className);
sb.append(":ServiceType=");
// append the classloader name so we have unique names in web apps.
sb.append(getUniqueClassloaderIdentifier());
if (null != monitorType && monitorType.length() > 0) {
sb.append(",MonitorType=" + monitorType);
}
return sb.toString();
}
/**
* Generates a unique, but still nice and predictable name representing this classloader so that
* even apps operating under a web server such as tomcat with multiple classloaders would bee able
* to register each with its own unique mbean.
*/
private String getUniqueClassloaderIdentifier() {
String contextPath = getContextPath();
if (contextPath != null) {
return contextPath;
}
return "hector";
}
/**
* Tries to guess a context path for the running application.
* If this is a web application running under a tomcat server this will work.
* If unsuccessful, returns null.
* @return A string representing the current context path or null if it cannot be determined.
*/
private String getContextPath() {
URL url = getClass().getClassLoader().getResource("/");
if (url != null) {
String[] elements = url.toString().split("/");
for (int i = elements.length - 1; i > 0; --i) {
// URLs look like this: file:/.../ImageServer/WEB-INF/classes/
// And we want that part that's just before WEB-INF
if ("WEB-INF".equals(elements[i])) {
return elements[i - 1];
}
}
}
return null;
}
public CassandraClientMonitor getCassandraMonitor(HConnectionManager connectionManager) {
CassandraClientMonitor cassandraClientMonitor = monitors.get(connectionManager.getClusterName());
if ( cassandraClientMonitor == null ) {
try {
cassandraClientMonitor = new CassandraClientMonitor(connectionManager);
registerMonitor("me.prettyprint.cassandra.service_"+connectionManager.getClusterName(), "hector",
cassandraClientMonitor);
monitors.put(connectionManager.getClusterName(), cassandraClientMonitor);
} catch (MalformedObjectNameException e) {
log.error("Unable to register JMX monitor", e);
} catch (InstanceAlreadyExistsException e) {
log.error("Unable to register JMX monitor", e);
} catch (MBeanRegistrationException e) {
log.error("Unable to register JMX monitor", e);
} catch (NotCompliantMBeanException e) {
log.error("Unable to register JMX monitor", e);
}
}
return cassandraClientMonitor;
}
}