Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/launcher/LauncherHelper.java
38829 views
/*1* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.launcher;2627/*28*29* <p><b>This is NOT part of any API supported by Sun Microsystems.30* If you write code that depends on this, you do so at your own31* risk. This code and its internal interfaces are subject to change32* or deletion without notice.</b>33*34*/3536/**37* A utility package for the java(1), javaw(1) launchers.38* The following are helper methods that the native launcher uses39* to perform checks etc. using JNI, see src/share/bin/java.c40*/41import java.io.File;42import java.io.IOException;43import java.io.PrintStream;44import java.io.UnsupportedEncodingException;45import java.lang.reflect.Method;46import java.lang.reflect.Modifier;47import java.math.BigDecimal;48import java.math.RoundingMode;49import java.nio.charset.Charset;50import java.nio.file.DirectoryStream;51import java.nio.file.Files;52import java.nio.file.Path;53import java.text.Normalizer;54import java.util.ResourceBundle;55import java.text.MessageFormat;56import java.util.ArrayList;57import java.util.Collections;58import java.util.Iterator;59import java.util.List;60import java.util.Locale;61import java.util.Locale.Category;62import java.util.Properties;63import java.util.Set;64import java.util.TreeSet;65import java.util.jar.Attributes;66import java.util.jar.JarFile;67import java.util.jar.Manifest;68import jdk.internal.platform.Container;69import jdk.internal.platform.Metrics;7071public enum LauncherHelper {72INSTANCE;73private static final String MAIN_CLASS = "Main-Class";7475private static StringBuilder outBuf = new StringBuilder();7677private static final String INDENT = " ";78private static final String VM_SETTINGS = "VM settings:";79private static final String PROP_SETTINGS = "Property settings:";80private static final String LOCALE_SETTINGS = "Locale settings:";8182// sync with java.c and sun.misc.VM83private static final String diagprop = "sun.java.launcher.diag";84final static boolean trace = sun.misc.VM.getSavedProperty(diagprop) != null;8586private static final String defaultBundleName =87"sun.launcher.resources.launcher";88private static class ResourceBundleHolder {89private static final ResourceBundle RB =90ResourceBundle.getBundle(defaultBundleName);91}92private static PrintStream ostream;93private static final ClassLoader scloader = ClassLoader.getSystemClassLoader();94private static Class<?> appClass; // application class, for GUI/reporting purposes9596/*97* A method called by the launcher to print out the standard settings,98* by default -XshowSettings is equivalent to -XshowSettings:all,99* Specific information may be gotten by using suboptions with possible100* values vm, properties and locale.101*102* printToStderr: choose between stdout and stderr103*104* optionFlag: specifies which options to print default is all other105* possible values are vm, properties, locale.106*107* initialHeapSize: in bytes, as set by the launcher, a zero-value indicates108* this code should determine this value, using a suitable method or109* the line could be omitted.110*111* maxHeapSize: in bytes, as set by the launcher, a zero-value indicates112* this code should determine this value, using a suitable method.113*114* stackSize: in bytes, as set by the launcher, a zero-value indicates115* this code determine this value, using a suitable method or omit the116* line entirely.117*/118@SuppressWarnings("fallthrough")119static void showSettings(boolean printToStderr, String optionFlag,120long initialHeapSize, long maxHeapSize, long stackSize,121boolean isServer) {122123initOutput(printToStderr);124String opts[] = optionFlag.split(":");125String optStr = (opts.length > 1 && opts[1] != null)126? opts[1].trim()127: "all";128switch (optStr) {129case "vm":130printVmSettings(initialHeapSize, maxHeapSize,131stackSize, isServer);132break;133case "properties":134printProperties();135break;136case "locale":137printLocale();138break;139case "system":140if (System.getProperty("os.name").contains("Linux")) {141printSystemMetrics();142break;143}144default:145printVmSettings(initialHeapSize, maxHeapSize, stackSize,146isServer);147printProperties();148printLocale();149if (System.getProperty("os.name").contains("Linux")) {150printSystemMetrics();151}152break;153}154}155156/*157* prints the main vm settings subopt/section158*/159private static void printVmSettings(160long initialHeapSize, long maxHeapSize,161long stackSize, boolean isServer) {162163ostream.println(VM_SETTINGS);164if (stackSize != 0L) {165ostream.println(INDENT + "Stack Size: " +166SizePrefix.scaleValue(stackSize));167}168if (initialHeapSize != 0L) {169ostream.println(INDENT + "Min. Heap Size: " +170SizePrefix.scaleValue(initialHeapSize));171}172if (maxHeapSize != 0L) {173ostream.println(INDENT + "Max. Heap Size: " +174SizePrefix.scaleValue(maxHeapSize));175} else {176ostream.println(INDENT + "Max. Heap Size (Estimated): "177+ SizePrefix.scaleValue(Runtime.getRuntime().maxMemory()));178}179ostream.println(INDENT + "Ergonomics Machine Class: "180+ ((isServer) ? "server" : "client"));181ostream.println(INDENT + "Using VM: "182+ System.getProperty("java.vm.name"));183ostream.println();184}185186/*187* prints the properties subopt/section188*/189private static void printProperties() {190Properties p = System.getProperties();191ostream.println(PROP_SETTINGS);192List<String> sortedPropertyKeys = new ArrayList<>();193sortedPropertyKeys.addAll(p.stringPropertyNames());194Collections.sort(sortedPropertyKeys);195for (String x : sortedPropertyKeys) {196printPropertyValue(x, p.getProperty(x));197}198ostream.println();199}200201private static boolean isPath(String key) {202return key.endsWith(".dirs") || key.endsWith(".path");203}204205private static void printPropertyValue(String key, String value) {206ostream.print(INDENT + key + " = ");207if (key.equals("line.separator")) {208for (byte b : value.getBytes()) {209switch (b) {210case 0xd:211ostream.print("\\r ");212break;213case 0xa:214ostream.print("\\n ");215break;216default:217// print any bizzare line separators in hex, but really218// shouldn't happen.219ostream.printf("0x%02X", b & 0xff);220break;221}222}223ostream.println();224return;225}226if (!isPath(key)) {227ostream.println(value);228return;229}230String[] values = value.split(System.getProperty("path.separator"));231boolean first = true;232for (String s : values) {233if (first) { // first line treated specially234ostream.println(s);235first = false;236} else { // following lines prefix with indents237ostream.println(INDENT + INDENT + s);238}239}240}241242/*243* prints the locale subopt/section244*/245private static void printLocale() {246Locale locale = Locale.getDefault();247ostream.println(LOCALE_SETTINGS);248ostream.println(INDENT + "default locale = " +249locale.getDisplayLanguage());250ostream.println(INDENT + "default display locale = " +251Locale.getDefault(Category.DISPLAY).getDisplayName());252ostream.println(INDENT + "default format locale = " +253Locale.getDefault(Category.FORMAT).getDisplayName());254printLocales();255ostream.println();256}257258private static void printLocales() {259Locale[] tlocales = Locale.getAvailableLocales();260final int len = tlocales == null ? 0 : tlocales.length;261if (len < 1 ) {262return;263}264// Locale does not implement Comparable so we convert it to String265// and sort it for pretty printing.266Set<String> sortedSet = new TreeSet<>();267for (Locale l : tlocales) {268sortedSet.add(l.toString());269}270271ostream.print(INDENT + "available locales = ");272Iterator<String> iter = sortedSet.iterator();273final int last = len - 1;274for (int i = 0 ; iter.hasNext() ; i++) {275String s = iter.next();276ostream.print(s);277if (i != last) {278ostream.print(", ");279}280// print columns of 8281if ((i + 1) % 8 == 0) {282ostream.println();283ostream.print(INDENT + INDENT);284}285}286}287288public static void printSystemMetrics() {289Metrics c = Container.metrics();290291ostream.println("Operating System Metrics:");292293if (c == null) {294ostream.println(INDENT + "No metrics available for this platform");295return;296}297298ostream.println(INDENT + "Provider: " + c.getProvider());299ostream.println(INDENT + "Effective CPU Count: " + c.getEffectiveCpuCount());300ostream.println(INDENT + "CPU Period: " + c.getCpuPeriod() +301(c.getCpuPeriod() == -1 ? "" : "us"));302ostream.println(INDENT + "CPU Quota: " + c.getCpuQuota() +303(c.getCpuQuota() == -1 ? "" : "us"));304ostream.println(INDENT + "CPU Shares: " + c.getCpuShares());305306int cpus[] = c.getCpuSetCpus();307ostream.println(INDENT + "List of Processors, "308+ cpus.length + " total: ");309310ostream.print(INDENT);311for (int i = 0; i < cpus.length; i++) {312ostream.print(cpus[i] + " ");313}314if (cpus.length > 0) {315ostream.println("");316}317318cpus = c.getEffectiveCpuSetCpus();319ostream.println(INDENT + "List of Effective Processors, "320+ cpus.length + " total: ");321322ostream.print(INDENT);323for (int i = 0; i < cpus.length; i++) {324ostream.print(cpus[i] + " ");325}326if (cpus.length > 0) {327ostream.println("");328}329330int mems[] = c.getCpuSetMems();331ostream.println(INDENT + "List of Memory Nodes, "332+ mems.length + " total: ");333334ostream.print(INDENT);335for (int i = 0; i < mems.length; i++) {336ostream.print(mems[i] + " ");337}338if (mems.length > 0) {339ostream.println("");340}341342mems = c.getEffectiveCpuSetMems();343ostream.println(INDENT + "List of Available Memory Nodes, "344+ mems.length + " total: ");345346ostream.print(INDENT);347for (int i = 0; i < mems.length; i++) {348ostream.print(mems[i] + " ");349}350if (mems.length > 0) {351ostream.println("");352}353354ostream.println(INDENT + "CPUSet Memory Pressure Enabled: "355+ c.isCpuSetMemoryPressureEnabled());356357long limit = c.getMemoryLimit();358ostream.println(INDENT + "Memory Limit: " +359((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));360361limit = c.getMemorySoftLimit();362ostream.println(INDENT + "Memory Soft Limit: " +363((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));364365limit = c.getMemoryAndSwapLimit();366ostream.println(INDENT + "Memory & Swap Limit: " +367((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));368369limit = c.getKernelMemoryLimit();370ostream.println(INDENT + "Kernel Memory Limit: " +371((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));372373limit = c.getTcpMemoryLimit();374ostream.println(INDENT + "TCP Memory Limit: " +375((limit >= 0) ? SizePrefix.scaleValue(limit) : "Unlimited"));376377ostream.println(INDENT + "Out Of Memory Killer Enabled: "378+ c.isMemoryOOMKillEnabled());379380ostream.println("");381}382383private enum SizePrefix {384385KILO(1024, "K"),386MEGA(1024 * 1024, "M"),387GIGA(1024 * 1024 * 1024, "G"),388TERA(1024L * 1024L * 1024L * 1024L, "T");389long size;390String abbrev;391392SizePrefix(long size, String abbrev) {393this.size = size;394this.abbrev = abbrev;395}396397private static String scale(long v, SizePrefix prefix) {398return BigDecimal.valueOf(v).divide(BigDecimal.valueOf(prefix.size),3992, RoundingMode.HALF_EVEN).toPlainString() + prefix.abbrev;400}401/*402* scale the incoming values to a human readable form, represented as403* K, M, G and T, see java.c parse_size for the scaled values and404* suffixes. The lowest possible scaled value is Kilo.405*/406static String scaleValue(long v) {407if (v < MEGA.size) {408return scale(v, KILO);409} else if (v < GIGA.size) {410return scale(v, MEGA);411} else if (v < TERA.size) {412return scale(v, GIGA);413} else {414return scale(v, TERA);415}416}417}418419/**420* A private helper method to get a localized message and also421* apply any arguments that we might pass.422*/423private static String getLocalizedMessage(String key, Object... args) {424String msg = ResourceBundleHolder.RB.getString(key);425return (args != null) ? MessageFormat.format(msg, args) : msg;426}427428/**429* The java -help message is split into 3 parts, an invariant, followed430* by a set of platform dependent variant messages, finally an invariant431* set of lines.432* This method initializes the help message for the first time, and also433* assembles the invariant header part of the message.434*/435static void initHelpMessage(String progname) {436outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.header",437(progname == null) ? "java" : progname ));438outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.datamodel",43932));440outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.datamodel",44164));442}443444/**445* Appends the vm selection messages to the header, already created.446* initHelpSystem must already be called.447*/448static void appendVmSelectMessage(String vm1, String vm2) {449outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.vmselect",450vm1, vm2));451}452453/**454* Appends the vm synoym message to the header, already created.455* initHelpSystem must be called before using this method.456*/457static void appendVmSynonymMessage(String vm1, String vm2) {458outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.hotspot",459vm1, vm2));460}461462/**463* Appends the vm Ergo message to the header, already created.464* initHelpSystem must be called before using this method.465*/466static void appendVmErgoMessage(boolean isServerClass, String vm) {467outBuf = outBuf.append(getLocalizedMessage("java.launcher.ergo.message1",468vm));469outBuf = (isServerClass)470? outBuf.append(",\n" +471getLocalizedMessage("java.launcher.ergo.message2") + "\n\n")472: outBuf.append(".\n\n");473}474475/**476* Appends the last invariant part to the previously created messages,477* and finishes up the printing to the desired output stream.478* initHelpSystem must be called before using this method.479*/480static void printHelpMessage(boolean printToStderr) {481initOutput(printToStderr);482outBuf = outBuf.append(getLocalizedMessage("java.launcher.opt.footer",483File.pathSeparator));484ostream.println(outBuf.toString());485}486487/**488* Prints the Xusage text to the desired output stream.489*/490static void printXUsageMessage(boolean printToStderr) {491initOutput(printToStderr);492ostream.println(getLocalizedMessage("java.launcher.X.usage",493File.pathSeparator));494if (System.getProperty("os.name").contains("OS X")) {495ostream.println(getLocalizedMessage("java.launcher.X.macosx.usage",496File.pathSeparator));497}498}499500static void initOutput(boolean printToStderr) {501ostream = (printToStderr) ? System.err : System.out;502}503504static String getMainClassFromJar(String jarname) {505String mainValue = null;506try (JarFile jarFile = new JarFile(jarname)) {507Manifest manifest = jarFile.getManifest();508if (manifest == null) {509abort(null, "java.launcher.jar.error2", jarname);510}511Attributes mainAttrs = manifest.getMainAttributes();512if (mainAttrs == null) {513abort(null, "java.launcher.jar.error3", jarname);514}515mainValue = mainAttrs.getValue(MAIN_CLASS);516if (mainValue == null) {517abort(null, "java.launcher.jar.error3", jarname);518}519520/*521* Hand off to FXHelper if it detects a JavaFX application522* This must be done after ensuring a Main-Class entry523* exists to enforce compliance with the jar specification524*/525if (mainAttrs.containsKey(526new Attributes.Name(FXHelper.JAVAFX_APPLICATION_MARKER))) {527return FXHelper.class.getName();528}529530return mainValue.trim();531} catch (IOException ioe) {532abort(ioe, "java.launcher.jar.error1", jarname);533}534return null;535}536537// From src/share/bin/java.c:538// enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR };539540private static final int LM_UNKNOWN = 0;541private static final int LM_CLASS = 1;542private static final int LM_JAR = 2;543544static void abort(Throwable t, String msgKey, Object... args) {545if (msgKey != null) {546ostream.println(getLocalizedMessage(msgKey, args));547}548if (trace) {549if (t != null) {550t.printStackTrace();551} else {552Thread.dumpStack();553}554}555System.exit(1);556}557558/**559* This method does the following:560* 1. gets the classname from a Jar's manifest, if necessary561* 2. loads the class using the System ClassLoader562* 3. ensures the availability and accessibility of the main method,563* using signatureDiagnostic method.564* a. does the class exist565* b. is there a main566* c. is the main public567* d. is the main static568* e. does the main take a String array for args569* 4. if no main method and if the class extends FX Application, then call570* on FXHelper to determine the main class to launch571* 5. and off we go......572*573* @param printToStderr if set, all output will be routed to stderr574* @param mode LaunchMode as determined by the arguments passed on the575* command line576* @param what either the jar file to launch or the main class when using577* LM_CLASS mode578* @return the application's main class579*/580public static Class<?> checkAndLoadMain(boolean printToStderr,581int mode,582String what) {583initOutput(printToStderr);584// get the class name585String cn = null;586switch (mode) {587case LM_CLASS:588cn = what;589break;590case LM_JAR:591cn = getMainClassFromJar(what);592break;593default:594// should never happen595throw new InternalError("" + mode + ": Unknown launch mode");596}597cn = cn.replace('/', '.');598Class<?> mainClass = null;599try {600mainClass = scloader.loadClass(cn);601} catch (NoClassDefFoundError | ClassNotFoundException cnfe) {602if (System.getProperty("os.name", "").contains("OS X")603&& Normalizer.isNormalized(cn, Normalizer.Form.NFD)) {604try {605// On Mac OS X since all names with diacretic symbols are given as decomposed it606// is possible that main class name comes incorrectly from the command line607// and we have to re-compose it608mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));609} catch (NoClassDefFoundError | ClassNotFoundException cnfe1) {610abort(cnfe, "java.launcher.cls.error1", cn);611}612} else {613abort(cnfe, "java.launcher.cls.error1", cn);614}615}616// set to mainClass617appClass = mainClass;618619/*620* Check if FXHelper can launch it using the FX launcher. In an FX app,621* the main class may or may not have a main method, so do this before622* validating the main class.623*/624if (mainClass.equals(FXHelper.class) ||625FXHelper.doesExtendFXApplication(mainClass)) {626// Will abort() if there are problems with the FX runtime627FXHelper.setFXLaunchParameters(what, mode);628return FXHelper.class;629}630631validateMainClass(mainClass);632return mainClass;633}634635/*636* Accessor method called by the launcher after getting the main class via637* checkAndLoadMain(). The "application class" is the class that is finally638* executed to start the application and in this case is used to report639* the correct application name, typically for UI purposes.640*/641public static Class<?> getApplicationClass() {642return appClass;643}644645// Check the existence and signature of main and abort if incorrect646static void validateMainClass(Class<?> mainClass) {647Method mainMethod;648try {649mainMethod = mainClass.getMethod("main", String[].class);650} catch (NoSuchMethodException nsme) {651// invalid main or not FX application, abort with an error652abort(null, "java.launcher.cls.error4", mainClass.getName(),653FXHelper.JAVAFX_APPLICATION_CLASS_NAME);654return; // Avoid compiler issues655}656657/*658* getMethod (above) will choose the correct method, based659* on its name and parameter type, however, we still have to660* ensure that the method is static and returns a void.661*/662int mod = mainMethod.getModifiers();663if (!Modifier.isStatic(mod)) {664abort(null, "java.launcher.cls.error2", "static",665mainMethod.getDeclaringClass().getName());666}667if (mainMethod.getReturnType() != java.lang.Void.TYPE) {668abort(null, "java.launcher.cls.error3",669mainMethod.getDeclaringClass().getName());670}671}672673private static final String encprop = "sun.jnu.encoding";674private static String encoding = null;675private static boolean isCharsetSupported = false;676677/*678* converts a c or a byte array to a platform specific string,679* previously implemented as a native method in the launcher.680*/681static String makePlatformString(boolean printToStderr, byte[] inArray) {682initOutput(printToStderr);683if (encoding == null) {684encoding = System.getProperty(encprop);685isCharsetSupported = Charset.isSupported(encoding);686}687try {688String out = isCharsetSupported689? new String(inArray, encoding)690: new String(inArray);691return out;692} catch (UnsupportedEncodingException uee) {693abort(uee, null);694}695return null; // keep the compiler happy696}697698static String[] expandArgs(String[] argArray) {699List<StdArg> aList = new ArrayList<>();700for (String x : argArray) {701aList.add(new StdArg(x));702}703return expandArgs(aList);704}705706static String[] expandArgs(List<StdArg> argList) {707ArrayList<String> out = new ArrayList<>();708if (trace) {709System.err.println("Incoming arguments:");710}711for (StdArg a : argList) {712if (trace) {713System.err.println(a);714}715if (a.needsExpansion) {716File x = new File(a.arg);717File parent = x.getParentFile();718String glob = x.getName();719if (parent == null) {720parent = new File(".");721}722try (DirectoryStream<Path> dstream =723Files.newDirectoryStream(parent.toPath(), glob)) {724int entries = 0;725for (Path p : dstream) {726out.add(p.normalize().toString());727entries++;728}729if (entries == 0) {730out.add(a.arg);731}732} catch (Exception e) {733out.add(a.arg);734if (trace) {735System.err.println("Warning: passing argument as-is " + a);736System.err.print(e);737}738}739} else {740out.add(a.arg);741}742}743String[] oarray = new String[out.size()];744out.toArray(oarray);745746if (trace) {747System.err.println("Expanded arguments:");748for (String x : oarray) {749System.err.println(x);750}751}752return oarray;753}754755/* duplicate of the native StdArg struct */756private static class StdArg {757final String arg;758final boolean needsExpansion;759StdArg(String arg, boolean expand) {760this.arg = arg;761this.needsExpansion = expand;762}763// protocol: first char indicates whether expansion is required764// 'T' = true ; needs expansion765// 'F' = false; needs no expansion766StdArg(String in) {767this.arg = in.substring(1);768needsExpansion = in.charAt(0) == 'T';769}770public String toString() {771return "StdArg{" + "arg=" + arg + ", needsExpansion=" + needsExpansion + '}';772}773}774775static final class FXHelper {776// Marker entry in jar manifest that designates a JavaFX application jar777private static final String JAVAFX_APPLICATION_MARKER =778"JavaFX-Application-Class";779private static final String JAVAFX_APPLICATION_CLASS_NAME =780"javafx.application.Application";781private static final String JAVAFX_LAUNCHER_CLASS_NAME =782"com.sun.javafx.application.LauncherImpl";783784/*785* The launch method used to invoke the JavaFX launcher. These must786* match the strings used in the launchApplication method.787*788* Command line JavaFX-App-Class Launch mode FX Launch mode789* java -cp fxapp.jar FXClass N/A LM_CLASS "LM_CLASS"790* java -cp somedir FXClass N/A LM_CLASS "LM_CLASS"791* java -jar fxapp.jar Present LM_JAR "LM_JAR"792* java -jar fxapp.jar Not Present LM_JAR "LM_JAR"793*/794private static final String JAVAFX_LAUNCH_MODE_CLASS = "LM_CLASS";795private static final String JAVAFX_LAUNCH_MODE_JAR = "LM_JAR";796797/*798* FX application launcher and launch method, so we can launch799* applications with no main method.800*/801private static String fxLaunchName = null;802private static String fxLaunchMode = null;803804private static Class<?> fxLauncherClass = null;805private static Method fxLauncherMethod = null;806807/*808* Set the launch params according to what was passed to LauncherHelper809* so we can use the same launch mode for FX. Abort if there is any810* issue with loading the FX runtime or with the launcher method.811*/812private static void setFXLaunchParameters(String what, int mode) {813// Check for the FX launcher classes814try {815fxLauncherClass = scloader.loadClass(JAVAFX_LAUNCHER_CLASS_NAME);816/*817* signature must be:818* public static void launchApplication(String launchName,819* String launchMode, String[] args);820*/821fxLauncherMethod = fxLauncherClass.getMethod("launchApplication",822String.class, String.class, String[].class);823824// verify launcher signature as we do when validating the main method825int mod = fxLauncherMethod.getModifiers();826if (!Modifier.isStatic(mod)) {827abort(null, "java.launcher.javafx.error1");828}829if (fxLauncherMethod.getReturnType() != java.lang.Void.TYPE) {830abort(null, "java.launcher.javafx.error1");831}832} catch (ClassNotFoundException | NoSuchMethodException ex) {833abort(ex, "java.launcher.cls.error5", ex);834}835836fxLaunchName = what;837switch (mode) {838case LM_CLASS:839fxLaunchMode = JAVAFX_LAUNCH_MODE_CLASS;840break;841case LM_JAR:842fxLaunchMode = JAVAFX_LAUNCH_MODE_JAR;843break;844default:845// should not have gotten this far...846throw new InternalError(mode + ": Unknown launch mode");847}848}849850/*851* Check if the given class is a JavaFX Application class. This is done852* in a way that does not cause the Application class to load or throw853* ClassNotFoundException if the JavaFX runtime is not available.854*/855private static boolean doesExtendFXApplication(Class<?> mainClass) {856for (Class<?> sc = mainClass.getSuperclass(); sc != null;857sc = sc.getSuperclass()) {858if (sc.getName().equals(JAVAFX_APPLICATION_CLASS_NAME)) {859return true;860}861}862return false;863}864865public static void main(String... args) throws Exception {866if (fxLauncherMethod == null867|| fxLaunchMode == null868|| fxLaunchName == null) {869throw new RuntimeException("Invalid JavaFX launch parameters");870}871// launch appClass via fxLauncherMethod872fxLauncherMethod.invoke(null,873new Object[] {fxLaunchName, fxLaunchMode, args});874}875}876}877878879