package org.jolokia.detector; import java.lang.instrument.Instrumentation; import java.lang.reflect.*; import java.util.Map; import java.util.Set; import javax.management.MBeanServer; import javax.management.MBeanServerConnection; import org.jolokia.backend.executor.MBeanServerExecutor; import org.jolokia.util.ClassUtil; /** * Detector for JBoss * * @author roland * @since 06.11.10 */ public class JBossDetector extends AbstractServerDetector { public static final String JBOSS_AS_MANAGEMENT_ROOT_SERVER = "jboss.as:management-root=server"; /** {@inheritDoc} */ public ServerHandle detect(MBeanServerExecutor pMBeanServerExecutor) { ServerHandle handle = checkFromJSR77(pMBeanServerExecutor); if (handle == null) { handle = checkFor5viaJMX(pMBeanServerExecutor); if (handle == null) { handle = checkForManagementRootServerViaJMX(pMBeanServerExecutor); } if (handle == null) { handle = checkForWildflySwarm(); } if (handle == null) { handle = fallbackForVersion7Check(pMBeanServerExecutor); } } return handle; } private ServerHandle checkForWildflySwarm() { if (isJBossModulesBasedContainer(this.getClass().getClassLoader())) { if (System.getProperties().containsKey("swarm.app.artifact")) { String version = System.getProperty("swarm.version"); return new JBossServerHandle(version != null ? version : "unknown", "Wildfly Swarm", null); } } return null; } /** * Attempts to detect a JBoss modules based application server. Because getting * access to the main arguments is not possible, it returns true in case the system property * {@code jboss.modules.system.pkgs} is set and the {@code org/jboss/modules/Main.class} resource can be found * using the class loader of this class. * * If so, it awaits the early initialization of a JBoss modules based application server by polling the system property * {@code java.util.logging.manager} and waiting until the specified class specified by this property has been * loaded by the JVM. */ @Override public void jvmAgentStartup(Instrumentation instrumentation) { jvmAgentStartup(instrumentation, this.getClass().getClassLoader()); } void jvmAgentStartup(Instrumentation instrumentation, ClassLoader classLoader) { if (isJBossModulesBasedContainer(classLoader)) { awaitServerInitializationForJBossModulesBasedContainer(instrumentation); } } protected boolean isJBossModulesBasedContainer(ClassLoader classLoader) { return hasWildflyProperties() && // Contained in any JBoss modules app: classLoader.getResource("org/jboss/modules/Main.class") != null; } private boolean hasWildflyProperties() { // For Wildfly AS: if (System.getProperty("jboss.modules.system.pkgs") != null) { return true; } // For Wildfly Swarm: String bootModuleLoader = System.getProperty("boot.module.loader"); if (bootModuleLoader != null) { return bootModuleLoader.contains("wildfly"); } return false; } // Wait a max 5 Minutes public static final int LOGGING_DETECT_TIMEOUT = 5 * 60 * 1000; public static final int LOGGING_DETECT_INTERVAL = 200; private void awaitServerInitializationForJBossModulesBasedContainer(Instrumentation instrumentation) { int count = 0; while (count * LOGGING_DETECT_INTERVAL < LOGGING_DETECT_TIMEOUT) { String loggingManagerClassName = System.getProperty("java.util.logging.manager"); if (loggingManagerClassName != null) { if (isClassLoaded(loggingManagerClassName, instrumentation)) { // Assuming that the logging manager (most likely org.jboss.logmanager.LogManager) // is loaded by the static initializer of java.util.logging.LogManager (and not by // other code), we know now that either the java.util.logging.LogManager singleton // is or will be initialized. // Here is the trigger for loading the class: // https://github.com/jboss-modules/jboss-modules/blob/1.5.1.Final/src/main/java/org/jboss/modules/Main.java#L482 // Therefore the steps 3-6 of the proposal for option 2 don't need to be performed, // see https://github.com/rhuss/jolokia/issues/258 for details. return; } } try { Thread.sleep(LOGGING_DETECT_INTERVAL); count++; } catch (InterruptedException e) { throw new RuntimeException(e); } } throw new IllegalStateException(String.format("Detected JBoss Module loader, but property java.util.logging.manager is not set after %d seconds", LOGGING_DETECT_TIMEOUT / 1000)); } private ServerHandle checkFromJSR77(MBeanServerExecutor pMBeanServerExecutor) { if (ClassUtil.checkForClass("org.jboss.mx.util.MBeanServerLocator")) { // Get Version number from JSR77 call String version = getVersionFromJsr77(pMBeanServerExecutor); if (version != null) { int idx = version.indexOf(' '); if (idx >= 0) { // Strip off boilerplate version = version.substring(0, idx); } return new JBossServerHandle(version, null); } } return null; } private ServerHandle checkFor5viaJMX(MBeanServerExecutor pMBeanServerExecutor) { if (mBeanExists(pMBeanServerExecutor, "jboss.system:type=Server")) { String versionFull = getAttributeValue(pMBeanServerExecutor, "jboss.system:type=Server", "Version"); String version = null; if (versionFull != null) { version = versionFull.replaceAll("\\(.*", "").trim(); } return new JBossServerHandle(version, null); } return null; } private ServerHandle checkForManagementRootServerViaJMX(MBeanServerExecutor pMBeanServerExecutor) { // Bug (or not ?) in Wildfly 8.0: Search for jboss.as:management-root=server return null but accessing this // MBean works. So we are looking, whether the JMX domain jboss.as exists and fetch the version directly. if (searchMBeans(pMBeanServerExecutor,"jboss.as:*").size() != 0) { String version = getAttributeValue(pMBeanServerExecutor, JBOSS_AS_MANAGEMENT_ROOT_SERVER, "productVersion"); if (version == null) { version = getAttributeValue(pMBeanServerExecutor, JBOSS_AS_MANAGEMENT_ROOT_SERVER, "releaseVersion"); } if (version != null) { String product = getAttributeValue(pMBeanServerExecutor, JBOSS_AS_MANAGEMENT_ROOT_SERVER, "productName"); return new JBossServerHandle(version, product != null ? product : "jboss", null); } } return null; } private ServerHandle fallbackForVersion7Check(MBeanServerExecutor pMBeanServerExecutor) { if (mBeanExists(pMBeanServerExecutor, "jboss.modules:*")) { // It's a JBoss 7, probably a 7.0.x one ... return new JBossServerHandle("7", null); } return null; } // Special handling for JBoss @Override /** {@inheritDoc} */ public void addMBeanServers(Set<MBeanServerConnection> servers) { try { Class locatorClass = Class.forName("org.jboss.mx.util.MBeanServerLocator"); Method method = locatorClass.getMethod("locateJBoss"); servers.add((MBeanServer) method.invoke(null)); } catch (ClassNotFoundException e) { /* Ok, its *not* JBoss 4,5 or 6, continue with search ... */ } catch (NoSuchMethodException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } } // ======================================================================== private static class JBossServerHandle extends ServerHandle { /** * JBoss server handle, with custom name * * @param version JBoss version * @param name Product name to use * @param extraInfo extra info to return */ JBossServerHandle(String version, String name, Map<String, String> extraInfo) { super("RedHat", name, version, extraInfo); } /** * JBoss server handle, using "jboss" as product name * * @param version JBoss version * @param extraInfo extra info to return */ JBossServerHandle(String version, Map<String, String> extraInfo) { this(version, "jboss", extraInfo); } } } /* * 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. */ /* jboss.web:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//localhost/jolokia --> path jboss.web:name=HttpRequest1,type=RequestProcessor,worker=http-bhut%2F172.16.239.130-8080 --> remoteAddr, serverPort, protocol */