This is an automated email from the ASF dual-hosted git repository.

wujimin pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new b00f4c7  [SCB-725] support get main class package when run with "java 
-jar xxx.jar"
b00f4c7 is described below

commit b00f4c748122460ba1484815ed9c98eadf9eba31
Author: wujimin <wuji...@huawei.com>
AuthorDate: Tue Jul 10 12:51:43 2018 +0800

    [SCB-725] support get main class package when run with "java -jar xxx.jar"
---
 .../foundation/common/utils/JvmUtils.java          | 41 ++++++++++++-
 .../foundation/common/utils/TestJvmUtils.java      | 68 +++++++++++++++++++++-
 2 files changed, 105 insertions(+), 4 deletions(-)

diff --git 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java
 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java
index 48a9baa..bb02d72 100644
--- 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java
+++ 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JvmUtils.java
@@ -16,6 +16,12 @@
  */
 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.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,21 +42,50 @@ public final class JvmUtils {
    * @return main class or null, never throw exception
    */
   public static Class<?> findMainClass() {
+    // 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 (command == null || command.isEmpty()) {
       return null;
     }
 
-    // command is main class and args
-    String mainClass = command.trim().split(" ")[0];
+    String mainClassOrJar = command.trim().split(" ")[0];
+    String mainClass = readFromJar(mainClassOrJar);
+    if (mainClass == null || mainClass.isEmpty()) {
+      return null;
+    }
+
     try {
-      return Class.forName(mainClass);
+      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);
+        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
    */
diff --git 
a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java
 
b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java
index d16792f..257c8f4 100644
--- 
a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java
+++ 
b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestJvmUtils.java
@@ -16,12 +16,24 @@
  */
 package org.apache.servicecomb.foundation.common.utils;
 
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.JarFile;
+
 import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({JvmUtils.class})
 public class TestJvmUtils {
   static String orgCmd = System.getProperty(JvmUtils.SUN_JAVA_COMMAND);
 
@@ -63,9 +75,63 @@ public class TestJvmUtils {
   }
 
   @Test
-  public void findMainClass_normal() {
+  public void findMainClass_class_normal() {
     System.setProperty(JvmUtils.SUN_JAVA_COMMAND, TestJvmUtils.class.getName() 
+ " arg");
 
     Assert.assertEquals(TestJvmUtils.class, JvmUtils.findMainClass());
   }
+
+  @Test
+  public void findMainClass_jar_normal() throws Exception {
+    String content = String.format("Manifest-Version: 1.0\nMain-Class: %s\n", 
TestJvmUtils.class.getName());
+    InputStream inputStream = new ByteArrayInputStream(content.getBytes());
+
+    URL url = PowerMockito.mock(URL.class);
+
+    String command = "a.jar";
+    String manifestUri = "jar:file:/" + new File(command).getAbsolutePath() + 
"!/" + JarFile.MANIFEST_NAME;
+
+    PowerMockito.whenNew(URL.class).withParameterTypes(String.class)
+        .withArguments(manifestUri).thenReturn(url);
+    PowerMockito.when(url.openStream()).thenReturn(inputStream);
+
+    System.setProperty(JvmUtils.SUN_JAVA_COMMAND, command + " arg");
+
+    Assert.assertEquals(TestJvmUtils.class, JvmUtils.findMainClass());
+  }
+
+  @Test
+  public void findMainClass_jar_null() throws Exception {
+    String content = "Manifest-Version: 1.0\n";
+    InputStream inputStream = new ByteArrayInputStream(content.getBytes());
+
+    URL url = PowerMockito.mock(URL.class);
+
+    String command = "a.jar";
+    String manifestUri = "jar:file:/" + new File(command).getAbsolutePath() + 
"!/" + JarFile.MANIFEST_NAME;
+
+    PowerMockito.whenNew(URL.class).withParameterTypes(String.class)
+        .withArguments(manifestUri).thenReturn(url);
+    PowerMockito.when(url.openStream()).thenReturn(inputStream);
+
+    System.setProperty(JvmUtils.SUN_JAVA_COMMAND, command + " arg");
+
+    Assert.assertNull(JvmUtils.findMainClass());
+  }
+
+  @Test
+  public void findMainClass_jar_readFailed() throws Exception {
+    URL url = PowerMockito.mock(URL.class);
+
+    String command = "a.jar";
+    String manifestUri = "jar:file:/" + new File(command).getAbsolutePath() + 
"!/" + JarFile.MANIFEST_NAME;
+
+    PowerMockito.whenNew(URL.class).withParameterTypes(String.class)
+        .withArguments(manifestUri).thenReturn(url);
+    PowerMockito.when(url.openStream()).thenThrow(new Error());
+
+    System.setProperty(JvmUtils.SUN_JAVA_COMMAND, command + " arg");
+
+    Assert.assertNull(JvmUtils.findMainClass());
+  }
 }

Reply via email to