/* * Copyright 2015 NAVER Corp. * * 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. */ package com.navercorp.pinpoint.bootstrap.resolver.condition; import java.io.IOException; import java.util.jar.JarFile; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.common.util.JvmUtils; import com.navercorp.pinpoint.common.util.SimpleProperty; import com.navercorp.pinpoint.common.util.SystemProperty; import com.navercorp.pinpoint.common.util.SystemPropertyKey; /** * @author HyunGil Jeong * */ public class MainClassCondition implements Condition<String>, ConditionValue<String> { private static final String MANIFEST_MAIN_CLASS_KEY = "Main-Class"; private static final String NOT_FOUND = null; private final PLogger logger = PLoggerFactory.getLogger(this.getClass().getName()); private final String applicationMainClassName; public MainClassCondition() { this(SystemProperty.INSTANCE); } public MainClassCondition(SimpleProperty property) { if (property == null) { throw new IllegalArgumentException("properties should not be null"); } this.applicationMainClassName = getMainClassName(property); if (this.applicationMainClassName == NOT_FOUND) { logger.info("Main class could not be deduced, please set 'profiler.applicationservertype' in pinpoint.config."); logger.info("If you're running on 1.6.0_24 or prior version of Java, consider upgrading to 1.6.0_25+."); logger.info("If you're running Tomcat or Tomcat on Spring Boot, please set 'profiler.tomcat.conditional.transform' to false"); logger.info("If you're running Jboss, please set 'profiler.tomcat.conditional.transform' to false"); } } /** * Checks if the specified value matches the fully qualified class name of the application's main class. * If the main class cannot be resolved, the method return <tt>false</tt>. * * @param condition the value to check against the application's main class name * @return <tt>true</tt> if the specified value matches the name of the main class; * <tt>false</tt> if otherwise, or if the main class cannot be resolved */ @Override public boolean check(String condition) { if (this.applicationMainClassName == NOT_FOUND) { return false; } if (this.applicationMainClassName.equals(condition)) { logger.debug("Main class match - [{}]", this.applicationMainClassName, condition); return true; } else { logger.debug("Main class does not match - found : [{}], expected : [{}]", this.applicationMainClassName, condition); return false; } } /** * Returns the fully qualified class name of the application's main class. * * @return the fully qualified class name of the main class, or an empty string if the main class cannot be resolved */ @Override public String getValue() { if (this.applicationMainClassName == NOT_FOUND) { return ""; } return this.applicationMainClassName; } private String getMainClassName(SimpleProperty property) { String javaCommand = property.getProperty(SystemPropertyKey.SUN_JAVA_COMMAND.getKey(), "").split(" ")[0]; if (javaCommand.isEmpty()) { String jreVersion = property.getProperty(SystemPropertyKey.JAVA_RUNTIME_VERSION.getKey()); logger.warn("Error retrieving main class using '{}', jre : {}", SystemPropertyKey.SUN_JAVA_COMMAND.getKey(), jreVersion); return NOT_FOUND; } else { JarFile executableArchive = null; try { executableArchive = new JarFile(javaCommand); return extractMainClassFromArchive(executableArchive); } catch (IOException e) { // If it's not a valid java archive, VM shouldn't start in the first place. // Thus this would simply be a main class return javaCommand; } catch (Exception e) { // fail-safe, application shouldn't not start because of this logger.warn("Error retrieving main class", e); return NOT_FOUND; } finally { if (executableArchive != null) { try { executableArchive.close(); } catch (IOException e) { logger.warn("Error closing jarFile : [{}]", executableArchive.getName(), e); } } } } } private String extractMainClassFromArchive(JarFile bootstrapJar) throws IOException { String mainClassFromManifest = bootstrapJar.getManifest().getMainAttributes().getValue(MANIFEST_MAIN_CLASS_KEY); if (mainClassFromManifest == null) { return NOT_FOUND; } return mainClassFromManifest; } }