blob: 6ed60ff0afc27ac4a8c9c232305a37584fd96139 [file] [log] [blame]
/*
* 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 org.apache.servicecomb.foundation.common.utils;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
public final class JvmUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(JvmUtils.class);
// available for oracle jdk/ open jdk, and maybe others
@VisibleForTesting
static final String SUN_JAVA_COMMAND = "sun.java.command";
private JvmUtils() {
}
/**
*
* @return main class or null, never throw exception.
* Note that this method does not ensure that the scbMainClass can be returned correctly in the some scene.
*/
public static Class<?> findMainClassByStackTrace() {
String mainClass = null;
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
if (stackTrace != null && stackTrace.length > 0) {
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
mainClass = stackTraceElement.getClassName();
break;
}
}
}
if (StringUtils.isEmpty(mainClass)) {
LOGGER.info("Can't found main class by stackTrace.");
return null;
}
try {
Class<?> cls = Class.forName(mainClass);
LOGGER.info("Found main class \"{}\" by stackTrace.", mainClass);
return cls;
} catch (Throwable e) {
LOGGER.warn("\"{}\" is not a valid class.", mainClass, e);
return null;
}
}
/**
*
* @return main class or null, never throw exception.
* Note that this method does not ensure that the scbMainClass can be returned correctly in the some scene,like "mvn spring-boot:run".
*/
public static Class<?> findMainClass() {
//Get the mainClass from the call stack
String mainClass = null;
// 1.run with java -cp ......
// command is main class and args
// 2.run with java -jar ......
// command is jar file name and args
String command = System.getProperty(SUN_JAVA_COMMAND);
if (StringUtils.isNotEmpty(command)) {
String mainClassOrJar = command.trim().split(" ")[0];
mainClass = readFromJar(mainClassOrJar);
}
if (StringUtils.isEmpty(mainClass)) {
LOGGER.info("Can't found main class by manifest.");
return null;
}
try {
Class<?> cls = Class.forName(mainClass);
LOGGER.info("Found main class \"{}\".", mainClass);
return cls;
} catch (Throwable e) {
LOGGER.warn("\"{}\" is not a valid class.", mainClass, e);
return null;
}
}
private static String readFromJar(String mainClassOrJar) {
if (!mainClassOrJar.endsWith(".jar")) {
return mainClassOrJar;
}
String manifestUri = "jar:file:" + new File(mainClassOrJar).getAbsolutePath() + "!/" + JarFile.MANIFEST_NAME;
try {
URL url = new URL(manifestUri);
try (InputStream inputStream = url.openStream()) {
Manifest manifest = new Manifest(inputStream);
String startClass = manifest.getMainAttributes().getValue("Start-Class");
if (StringUtils.isNotEmpty(startClass)) {
return startClass;
}
return manifest.getMainAttributes().getValue("Main-Class");
}
} catch (Throwable e) {
LOGGER.warn("Failed to read Main-Class from \"{}\".", manifestUri, e);
return null;
}
}
/**
* find a property class loader to avoid null
*/
public static ClassLoader correctClassLoader(ClassLoader classLoader) {
ClassLoader targetClassLoader = classLoader;
if (targetClassLoader == null) {
targetClassLoader = Thread.currentThread().getContextClassLoader();
}
if (targetClassLoader == null) {
targetClassLoader = JvmUtils.class.getClassLoader();
}
return targetClassLoader;
}
public static ClassLoader findClassLoader() {
return correctClassLoader(null);
}
}