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; } }