| /* |
| * 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); |
| } |
| } |