From 86074d2d66a3bd5fea9a1aefc565828a6248d2e7 Mon Sep 17 00:00:00 2001
From: zaxar163 <zahar.vcherachny@yandex.ru>
Date: Mon, 22 Oct 2018 16:04:20 +0300
Subject: [PATCH] Add javaVerRelauncher.

---
 Launcher/build.gradle                         |  10 +-
 javaVerRelauncher/build.gradle                |   8 ++
 .../ru/gravit/launcher/relauncher/Helper.java | 127 ++++++++++++++++++
 .../launcher/relauncher/JavaVersionInfo.java  |  96 +++++++++++++
 .../launcher/relauncher/VerRelauncher.java    |  43 ++++++
 settings.gradle                               |   3 +-
 6 files changed, 285 insertions(+), 2 deletions(-)
 create mode 100644 javaVerRelauncher/build.gradle
 create mode 100644 javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/Helper.java
 create mode 100644 javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/JavaVersionInfo.java
 create mode 100644 javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/VerRelauncher.java

diff --git a/Launcher/build.gradle b/Launcher/build.gradle
index 0990074d..79da931f 100644
--- a/Launcher/build.gradle
+++ b/Launcher/build.gradle
@@ -1,6 +1,9 @@
-String mainClassName = "ru.gravit.launcher.LauncherEngine"
+String realMainClassName = "ru.gravit.launcher.LauncherEngine"
 String mainAgentName = "ru.gravit.launcher.LauncherAgent"
 
+String mainClassName = "ru.gravit.launcher.relauncher.VerRelauncher"
+String errMessage = "Please, download Java 8 or higher."
+String minVer = "52"
 
 repositories {
     maven {
@@ -14,6 +17,10 @@
 jar {
     from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
     manifest.attributes("Main-Class": mainClassName,
+		"MainRun-Class": realMainClassName,
+		"Graphic-Enabled": "true",
+		"ErrorMessage-String": errMessage,
+		"MinVesion-Integer": minVer,
 		"Premain-Class": mainAgentName,
 		"Can-Redefine-Classes": "true",
 		"Can-Retransform-Classes": "true",
@@ -22,6 +29,7 @@
 
 dependencies {
     compile project(':LauncherAPI')
+	compile project(':javaVerRelauncher')
     compile 'org.javassist:javassist:3.23.1-GA'
 }
 
diff --git a/javaVerRelauncher/build.gradle b/javaVerRelauncher/build.gradle
new file mode 100644
index 00000000..ba761cda
--- /dev/null
+++ b/javaVerRelauncher/build.gradle
@@ -0,0 +1,8 @@
+String mainClassName = "ru.gravit.launcher.relauncher.VerRelauncher"
+
+sourceCompatibility = '1.6'
+targetCompatibility = '1.6'
+	
+jar {
+    manifest.attributes("Main-Class": mainClassName)
+}
diff --git a/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/Helper.java b/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/Helper.java
new file mode 100644
index 00000000..a69deac1
--- /dev/null
+++ b/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/Helper.java
@@ -0,0 +1,127 @@
+package ru.gravit.launcher.relauncher;
+
+import java.io.File;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.URL;
+import java.util.Locale;
+import java.util.jar.Manifest;
+
+public final class Helper {
+	public static enum OS {
+		LINUX("linux"), MACOSX("macosx"), MUSTDIE("mustdie"), OTHER("other");
+		public static OS byName(final String name) {
+			if (name.startsWith("Windows"))
+				return MUSTDIE;
+			if (name.startsWith("Linux"))
+				return LINUX;
+			if (name.startsWith("Mac OS X"))
+				return MACOSX;
+			return OTHER;
+		}
+
+		public final String name;
+
+		private OS(final String name) {
+			this.name = name;
+		}
+	}
+
+	private static final String DEFERR = "Invalid java version.";
+
+	public static final ClassLoader LOADER = ClassLoader.getSystemClassLoader();
+	public static final OS os = OS.byName(ManagementFactory.getOperatingSystemMXBean().getName());
+	public static Manifest mf = null;
+	
+	public static final String getErrMessage() {
+		try {
+			return getErrMessage(getManifest());
+		} catch (final Throwable t) {
+			return DEFERR;
+		}
+	}
+
+	public static final String getErrMessage(final Manifest mf) {
+		String mess = DEFERR;
+		try {
+			mess = mf.getMainAttributes().getValue("ErrorMessage-String");
+		} catch (final Throwable t) {
+		}
+		return mess;
+	}
+
+	public static final String getMainClass() {
+		try {
+			return getMainClass(getManifest());
+		} catch (final Throwable t) {
+			return null;
+		}
+	}
+
+	public static final String getMainClass(final Manifest mf) {
+		String main = null;
+		try {
+			main = mf.getMainAttributes().getValue("MainRun-Class").trim();
+		} catch (final Throwable t) {
+		}
+		return main;
+	}
+
+	public static final Manifest getManifest() {
+		if (mf != null) return mf;
+		try {
+			InputStream in = VerRelauncher.class.getResourceAsStream("/META-INF/MANIFEST.MF");
+			Manifest mf = new Manifest(in);
+			in.close();
+			Helper.mf = mf;
+			return mf;
+		} catch (final Throwable t) {
+			return null;
+		}
+	}
+
+	public static final int getMinVer() {
+		try {
+			return getMinVer(getManifest());
+		} catch (final Throwable t) {
+			return JavaVersionInfo.JAVA_6;
+		}
+	}
+
+	public static final int getMinVer(final Manifest mf) {
+		int ver = JavaVersionInfo.JAVA_6;
+		try {
+			ver = Integer.parseInt(mf.getMainAttributes().getValue("MinVesion-Integer").trim());
+		} catch (final Throwable t) {
+		}
+		return ver;
+	}
+
+	public static final OS getOs() {
+		return os;
+	}
+
+	public static final boolean isGraphic() {
+		try {
+			return isGraphic(getManifest());
+		} catch (final Throwable t) {
+			return false;
+		}
+	}
+
+	public static final boolean isGraphic(final Manifest mf) {
+		boolean graph = false;
+		try {
+			graph = "TRUE".equalsIgnoreCase(mf.getMainAttributes().getValue("Graphic-Enabled").trim());
+		} catch (final Throwable t) {
+		}
+		return graph;
+	}
+
+	public static void verifySystemProperties(final Class<?> mainClass, final boolean requireSystem) {
+		Locale.setDefault(Locale.US);
+		// Verify ClassLoader
+		if (requireSystem && !mainClass.getClassLoader().equals(LOADER))
+			throw new SecurityException("ClassLoader should be system");
+	}
+}
diff --git a/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/JavaVersionInfo.java b/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/JavaVersionInfo.java
new file mode 100644
index 00000000..60d5d2a1
--- /dev/null
+++ b/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/JavaVersionInfo.java
@@ -0,0 +1,96 @@
+package ru.gravit.launcher.relauncher;
+
+public final class JavaVersionInfo {
+	/**
+	 * The major version number of class files for JDK 1.1.
+	 */
+	public static final int JAVA_1 = 45;
+
+	/**
+	 * The major version number of class files for JDK 10.
+	 */
+	public static final int JAVA_10 = 54;
+
+	/**
+	 * The major version number of class files for JDK 11.
+	 */
+	public static final int JAVA_11 = 55;
+
+	/**
+	 * The major version number of class files for JDK 1.2.
+	 */
+	public static final int JAVA_2 = 46;
+
+	/**
+	 * The major version number of class files for JDK 1.3.
+	 */
+	public static final int JAVA_3 = 47;
+
+	/**
+	 * The major version number of class files for JDK 1.4.
+	 */
+	public static final int JAVA_4 = 48;
+
+	/**
+	 * The major version number of class files for JDK 1.5.
+	 */
+	public static final int JAVA_5 = 49;
+
+	/**
+	 * The major version number of class files for JDK 1.6.
+	 */
+	public static final int JAVA_6 = 50;
+
+	/**
+	 * The major version number of class files for JDK 1.7.
+	 */
+	public static final int JAVA_7 = 51;
+
+	/**
+	 * The major version number of class files for JDK 1.8.
+	 */
+	public static final int JAVA_8 = 52;
+
+	/**
+	 * The major version number of class files for JDK 1.9.
+	 */
+	public static final int JAVA_9 = 53;
+
+	/**
+	 * The major version number of class files created from scratch. The default
+	 * value is 47 (JDK 1.3). It is 49 (JDK 1.5) if the JVM supports
+	 * <code>java.lang.StringBuilder</code>. It is 50 (JDK 1.6) if the JVM supports
+	 * <code>java.util.zip.DeflaterInputStream</code>. It is 51 (JDK 1.7) if the JVM
+	 * supports <code>java.lang.invoke.CallSite</code>. It is 52 (JDK 1.8) if the
+	 * JVM supports <code>java.util.function.Function</code>. It is 53 (JDK 1.9) if
+	 * the JVM supports <code>java.lang.reflect.Module</code>. It is 54 (JDK 10) if
+	 * the JVM supports <code>java.util.List.copyOf(Collection)</code>. It is 55
+	 * (JDK 11) if the JVM supports <code>java.util.Optional.isEmpty()</code>.
+	 */
+	public static final int MAJOR_VERSION;
+	static {
+		int ver = JAVA_3;
+		try {
+			Class.forName("java.lang.StringBuilder");
+			ver = JAVA_5;
+			Class.forName("java.util.zip.DeflaterInputStream");
+			ver = JAVA_6;
+			Class.forName("java.lang.invoke.CallSite", false, ClassLoader.getSystemClassLoader());
+			ver = JAVA_7;
+			Class.forName("java.util.function.Function");
+			ver = JAVA_8;
+			Class.forName("java.lang.Module");
+			ver = JAVA_9;
+			Class.forName("java.util.List").getMethod("copyOf", Class.forName("java.util.Collection"));
+			ver = JAVA_10;
+			Class.forName("java.util.Optional").getMethod("isEmpty");
+			ver = JAVA_11;
+		} catch (final Throwable t) {
+		}
+		MAJOR_VERSION = ver;
+	}
+
+	public static final int getVersion() {
+		return MAJOR_VERSION;
+	}
+}
diff --git a/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/VerRelauncher.java b/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/VerRelauncher.java
new file mode 100644
index 00000000..9e41527a
--- /dev/null
+++ b/javaVerRelauncher/src/main/java/ru/gravit/launcher/relauncher/VerRelauncher.java
@@ -0,0 +1,43 @@
+package ru.gravit.launcher.relauncher;
+
+import java.lang.reflect.Method;
+
+import javax.swing.JOptionPane;
+
+public final class VerRelauncher {
+	private static final void checkCompat() {
+		if (JavaVersionInfo.MAJOR_VERSION < Helper.getMinVer()) {
+			if (Helper.isGraphic())
+				runGraph(Helper.getErrMessage());
+			throw new AssertionError(Helper.getErrMessage());
+		}
+	}
+
+	public static void main(final String[] args) {
+		verifySystemProperties();
+		try {
+			checkCompat();
+			final Class<?> main = Class.forName(Helper.getMainClass(), true, ClassLoader.getSystemClassLoader());
+			Helper.verifySystemProperties(main, true);
+			final Method mainMethod = main.getMethod("main", String[].class);
+			mainMethod.setAccessible(true);
+			mainMethod.invoke(null, new Object[] { args });
+		} catch (final Throwable t) {
+			if (t instanceof AssertionError)
+				throw (AssertionError) t;
+			if (t instanceof InternalError)
+				throw (InternalError) t;
+			throw new InternalError(t);
+		}
+	}
+
+	private static void runGraph(final String errMessage) {
+		JOptionPane.showMessageDialog(null, errMessage);
+	}
+
+	private static void verifySystemProperties() {
+		Helper.verifySystemProperties(Helper.class, true);
+		Helper.verifySystemProperties(VerRelauncher.class, true);
+		Helper.verifySystemProperties(JavaVersionInfo.class, true);
+	}
+}
diff --git a/settings.gradle b/settings.gradle
index 5b0fea68..1e34055c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,9 +1,10 @@
 rootProject.name = 'Launcher'
 
-include 'Launcher'
 include 'libLauncher'
 include 'LauncherAPI'
+include 'javaVerRelauncher'
 include 'ServerWrapper'
+include 'Launcher'
 include 'LaunchServer'
 include 'modules'
 file('modules').eachDir { sub ->