package org.jolokia.detector;
/*
* Copyright 2009-2013 Roland Huss
*
* 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.
*/
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.HashSet;
import java.util.Set;
import javax.management.*;
import org.jolokia.backend.executor.MBeanServerExecutor;
/**
* Base class for server detectors
*
* @author roland
* @since 05.11.10
*/
public abstract class AbstractServerDetector implements ServerDetector {
/**
* Check for the existence of a certain MBean. All known MBeanServers are queried
*
* @param pMBeanServerExecutor mbean servers to query for
* @param pMbeanPattern MBean name pattern for MBeans to check for
* @return set of {@link ObjectName}s if the pattern matches, or an empty set if not mbean has been found
*/
protected Set<ObjectName> searchMBeans(MBeanServerExecutor pMBeanServerExecutor, String pMbeanPattern) {
try {
ObjectName oName = new ObjectName(pMbeanPattern);
return pMBeanServerExecutor.queryNames(oName);
} catch (MalformedObjectNameException e) {
return new HashSet<ObjectName>();
} catch (IOException e) {
return new HashSet<ObjectName>();
}
}
/**
* Check whether a certain MBean exists
*
* @param pMBeanServerManger set of MBeanServers to query for
* @param pObjectName the objectname to check. Can be a pattern in which case this method
* return true if one or more MBeans of all MBeanServers match this pattern
* @return true if at least one MBean of the given name (or pattern) exists
*/
protected boolean mBeanExists(MBeanServerExecutor pMBeanServerManger,String pObjectName) {
return searchMBeans(pMBeanServerManger,pObjectName).size() > 0;
}
/**
* Get the string representation of an attribute
*
* @param pMBeanServerExecutor set of MBeanServers to query. The first one wins.
* @param pMBean object name of MBean to lookup
* @param pAttribute attribute to lookup
* @return string value of attribute or <code>null</code> if the attribute could not be fetched
*/
protected String getAttributeValue(MBeanServerExecutor pMBeanServerExecutor,String pMBean,String pAttribute) {
try {
ObjectName oName = new ObjectName(pMBean);
return getAttributeValue(pMBeanServerExecutor,oName,pAttribute);
} catch (MalformedObjectNameException e) {
return null;
}
}
/**
* Get the string representation of an attribute
*
*
*
* @param pMBeanServerExecutor set of MBeanServers to query. The first one wins.
* @param pMBean name of MBean to lookup
* @param pAttribute attribute to lookup
* @return string value of attribute or <code>null</code> if the attribute could not be fetched
*/
protected String getAttributeValue(MBeanServerExecutor pMBeanServerExecutor, final ObjectName pMBean, final String pAttribute) {
try {
return pMBeanServerExecutor.call(pMBean, GET_ATTRIBUTE_HANDLER, pAttribute);
} catch (IOException e) {
return null;
} catch (ReflectionException e) {
return null;
} catch (JMException e) {
return null;
}
}
// Handler for fetching an attribute
private static final MBeanServerExecutor.MBeanAction<String> GET_ATTRIBUTE_HANDLER = new MBeanServerExecutor.MBeanAction<String>() {
/** {@inheritDoc} */
public String execute(MBeanServerConnection pConn, ObjectName pName, Object... extraArgs) throws ReflectionException, InstanceNotFoundException, IOException, MBeanException, AttributeNotFoundException {
Object attr = pConn.getAttribute(pName, (String) extraArgs[0]);
return attr != null ? attr.toString() : null;
}
};
/**
* Get a single attribute for a given MBeanName pattern.
*
* @param pMBeanServerExecutor MBeanServer manager to query
* @param pMBeanName a MBean name or pattern. If multiple MBeans are found, each is queried for the attribute
* @param pAttribute the attribute to lookup
* @return the string value of the attribute or null if either no MBeans could be found, or 0 or more than 1 attribute
* are found on those mbeans
*/
protected String getSingleStringAttribute(MBeanServerExecutor pMBeanServerExecutor, String pMBeanName, String pAttribute) {
Set<ObjectName> serverMBeanNames = searchMBeans(pMBeanServerExecutor, pMBeanName);
if (serverMBeanNames.size() == 0) {
return null;
}
Set<String> attributeValues = new HashSet<String>();
for (ObjectName oName : serverMBeanNames) {
String val = getAttributeValue(pMBeanServerExecutor, oName, pAttribute);
if (val != null) {
attributeValues.add(val);
}
}
if (attributeValues.size() == 0 || attributeValues.size() > 1) {
return null;
}
return attributeValues.iterator().next();
}
/**
* Get the version number from a JSR-77 compliant server
*
*
* @param pMbeanServers servers to query
* @return version number or null if not found.
*/
protected String getVersionFromJsr77(MBeanServerExecutor pMbeanServers) {
Set<ObjectName> names = searchMBeans(pMbeanServers, "*:j2eeType=J2EEServer,*");
// Take the first one
if (names.size() > 0) {
return getAttributeValue(pMbeanServers, names.iterator().next(), "serverVersion");
}
return null;
}
/**
* Do nothing by default, leaving the implementation
* optional for each specific detector
*
* @param pServers servers to add
*/
public void addMBeanServers(Set<MBeanServerConnection> pServers) {
}
/**
* By default do nothing during JVM agent startup
*/
public void jvmAgentStartup(Instrumentation instrumentation) {
}
/**
* Tests if the given class name has been loaded by the JVM. Don't use this method
* in case you have access to the class loader which will be loading the class
* because the used approach is not very efficient.
* @param className the name of the class to check
* @param instrumentation
* @return true if the class has been loaded by the JVM
* @throws IllegalArgumentException in case instrumentation or the provided class is null
*/
protected boolean isClassLoaded(String className, Instrumentation instrumentation) {
if (instrumentation == null || className == null) {
throw new IllegalArgumentException("instrumentation and className must not be null");
}
Class<?>[] classes = instrumentation.getAllLoadedClasses();
for (Class<?> c : classes) {
if (className.equals(c.getName())) {
return true;
}
}
return false;
}
}