src/share/classes/sun/launcher/LauncherHelper.java

Print this page
rev 9771 : 8035782 : sun/launcher/LauncherHelper loaded unnecessarily


  52 import java.nio.file.Files;
  53 import java.nio.file.Path;
  54 import java.text.Normalizer;
  55 import java.util.ResourceBundle;
  56 import java.text.MessageFormat;
  57 import java.util.ArrayList;
  58 import java.util.Collections;
  59 import java.util.Iterator;
  60 import java.util.List;
  61 import java.util.Locale;
  62 import java.util.Locale.Category;
  63 import java.util.Properties;
  64 import java.util.Set;
  65 import java.util.TreeSet;
  66 import java.util.jar.Attributes;
  67 import java.util.jar.JarFile;
  68 import java.util.jar.Manifest;
  69 
  70 public enum LauncherHelper {
  71     INSTANCE;








  72     private static final String MAIN_CLASS = "Main-Class";
  73 
  74     private static StringBuilder outBuf = new StringBuilder();
  75 
  76     private static final String INDENT = "    ";
  77     private static final String VM_SETTINGS     = "VM settings:";
  78     private static final String PROP_SETTINGS   = "Property settings:";
  79     private static final String LOCALE_SETTINGS = "Locale settings:";
  80 
  81     // sync with java.c and sun.misc.VM
  82     private static final String diagprop = "sun.java.launcher.diag";
  83     final static boolean trace = sun.misc.VM.getSavedProperty(diagprop) != null;
  84 
  85     private static final String defaultBundleName =
  86             "sun.launcher.resources.launcher";
  87     private static class ResourceBundleHolder {
  88         private static final ResourceBundle RB =
  89                 ResourceBundle.getBundle(defaultBundleName);
  90     }
  91     private static PrintStream ostream;


 401         try (JarFile jarFile = new JarFile(jarname)) {
 402             Manifest manifest = jarFile.getManifest();
 403             if (manifest == null) {
 404                 abort(null, "java.launcher.jar.error2", jarname);
 405             }
 406             Attributes mainAttrs = manifest.getMainAttributes();
 407             if (mainAttrs == null) {
 408                 abort(null, "java.launcher.jar.error3", jarname);
 409             }
 410             mainValue = mainAttrs.getValue(MAIN_CLASS);
 411             if (mainValue == null) {
 412                 abort(null, "java.launcher.jar.error3", jarname);
 413             }
 414 
 415             /*
 416              * Hand off to FXHelper if it detects a JavaFX application
 417              * This must be done after ensuring a Main-Class entry
 418              * exists to enforce compliance with the jar specification
 419              */
 420             if (mainAttrs.containsKey(
 421                     new Attributes.Name(FXHelper.JAVAFX_APPLICATION_MARKER))) {

 422                 return FXHelper.class.getName();
 423             }
 424 
 425             return mainValue.trim();
 426         } catch (IOException ioe) {
 427             abort(ioe, "java.launcher.jar.error1", jarname);
 428         }
 429         return null;
 430     }
 431 
 432     // From src/share/bin/java.c:
 433     //   enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR };
 434 
 435     private static final int LM_UNKNOWN = 0;
 436     private static final int LM_CLASS   = 1;
 437     private static final int LM_JAR     = 2;
 438 
 439     static void abort(Throwable t, String msgKey, Object... args) {
 440         if (msgKey != null) {
 441             ostream.println(getLocalizedMessage(msgKey, args));


 499                 try {
 500                     // On Mac OS X since all names with diacretic symbols are given as decomposed it
 501                     // is possible that main class name comes incorrectly from the command line
 502                     // and we have to re-compose it
 503                     mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));
 504                 } catch (NoClassDefFoundError | ClassNotFoundException cnfe1) {
 505                     abort(cnfe, "java.launcher.cls.error1", cn);
 506                 }
 507             } else {
 508                 abort(cnfe, "java.launcher.cls.error1", cn);
 509             }
 510         }
 511         // set to mainClass
 512         appClass = mainClass;
 513 
 514         /*
 515          * Check if FXHelper can launch it using the FX launcher. In an FX app,
 516          * the main class may or may not have a main method, so do this before
 517          * validating the main class.
 518          */
 519         if (mainClass.equals(FXHelper.class) ||
 520                 FXHelper.doesExtendFXApplication(mainClass)) {
 521             // Will abort() if there are problems with the FX runtime
 522             FXHelper.setFXLaunchParameters(what, mode);
 523             return FXHelper.class;
 524         }
 525 
 526         validateMainClass(mainClass);
 527         return mainClass;
 528     }
 529 
 530     /*
 531      * Accessor method called by the launcher after getting the main class via
 532      * checkAndLoadMain(). The "application class" is the class that is finally
 533      * executed to start the application and in this case is used to report
 534      * the correct application name, typically for UI purposes.
 535      */
 536     public static Class<?> getApplicationClass() {
 537         return appClass;
 538     }
 539 















 540     // Check the existence and signature of main and abort if incorrect
 541     static void validateMainClass(Class<?> mainClass) {
 542         Method mainMethod;
 543         try {
 544             mainMethod = mainClass.getMethod("main", String[].class);
 545         } catch (NoSuchMethodException nsme) {
 546             // invalid main or not FX application, abort with an error
 547             abort(null, "java.launcher.cls.error4", mainClass.getName(),
 548                   FXHelper.JAVAFX_APPLICATION_CLASS_NAME);
 549             return; // Avoid compiler issues
 550         }
 551 
 552         /*
 553          * getMethod (above) will choose the correct method, based
 554          * on its name and parameter type, however, we still have to
 555          * ensure that the method is static and returns a void.
 556          */
 557         int mod = mainMethod.getModifiers();
 558         if (!Modifier.isStatic(mod)) {
 559             abort(null, "java.launcher.cls.error2", "static",
 560                   mainMethod.getDeclaringClass().getName());
 561         }
 562         if (mainMethod.getReturnType() != java.lang.Void.TYPE) {
 563             abort(null, "java.launcher.cls.error3",
 564                   mainMethod.getDeclaringClass().getName());
 565         }

 566     }
 567 
 568     private static final String encprop = "sun.jnu.encoding";
 569     private static String encoding = null;
 570     private static boolean isCharsetSupported = false;
 571 
 572     /*
 573      * converts a c or a byte array to a platform specific string,
 574      * previously implemented as a native method in the launcher.
 575      */
 576     static String makePlatformString(boolean printToStderr, byte[] inArray) {
 577         initOutput(printToStderr);
 578         if (encoding == null) {
 579             encoding = System.getProperty(encprop);
 580             isCharsetSupported = Charset.isSupported(encoding);
 581         }
 582         try {
 583             String out = isCharsetSupported
 584                     ? new String(inArray, encoding)
 585                     : new String(inArray);


 651     private static class StdArg {
 652         final String arg;
 653         final boolean needsExpansion;
 654         StdArg(String arg, boolean expand) {
 655             this.arg = arg;
 656             this.needsExpansion = expand;
 657         }
 658         // protocol: first char indicates whether expansion is required
 659         // 'T' = true ; needs expansion
 660         // 'F' = false; needs no expansion
 661         StdArg(String in) {
 662             this.arg = in.substring(1);
 663             needsExpansion = in.charAt(0) == 'T';
 664         }
 665         public String toString() {
 666             return "StdArg{" + "arg=" + arg + ", needsExpansion=" + needsExpansion + '}';
 667         }
 668     }
 669 
 670     static final class FXHelper {
 671         // Marker entry in jar manifest that designates a JavaFX application jar
 672         private static final String JAVAFX_APPLICATION_MARKER =
 673                 "JavaFX-Application-Class";
 674         private static final String JAVAFX_APPLICATION_CLASS_NAME =
 675                 "javafx.application.Application";
 676         private static final String JAVAFX_LAUNCHER_CLASS_NAME =
 677                 "com.sun.javafx.application.LauncherImpl";
 678 
 679         /*
 680          * The launch method used to invoke the JavaFX launcher. These must
 681          * match the strings used in the launchApplication method.
 682          *
 683          * Command line                 JavaFX-App-Class  Launch mode  FX Launch mode
 684          * java -cp fxapp.jar FXClass   N/A               LM_CLASS     "LM_CLASS"
 685          * java -cp somedir FXClass     N/A               LM_CLASS     "LM_CLASS"
 686          * java -jar fxapp.jar          Present           LM_JAR       "LM_JAR"
 687          * java -jar fxapp.jar          Not Present       LM_JAR       "LM_JAR"
 688          */
 689         private static final String JAVAFX_LAUNCH_MODE_CLASS = "LM_CLASS";
 690         private static final String JAVAFX_LAUNCH_MODE_JAR = "LM_JAR";
 691 
 692         /*
 693          * FX application launcher and launch method, so we can launch
 694          * applications with no main method.
 695          */


 725                     abort(null, "java.launcher.javafx.error1");
 726                 }
 727             } catch (ClassNotFoundException | NoSuchMethodException ex) {
 728                 abort(ex, "java.launcher.cls.error5", ex);
 729             }
 730 
 731             fxLaunchName = what;
 732             switch (mode) {
 733                 case LM_CLASS:
 734                     fxLaunchMode = JAVAFX_LAUNCH_MODE_CLASS;
 735                     break;
 736                 case LM_JAR:
 737                     fxLaunchMode = JAVAFX_LAUNCH_MODE_JAR;
 738                     break;
 739                 default:
 740                     // should not have gotten this far...
 741                     throw new InternalError(mode + ": Unknown launch mode");
 742             }
 743         }
 744 
 745         /*
 746          * Check if the given class is a JavaFX Application class. This is done
 747          * in a way that does not cause the Application class to load or throw
 748          * ClassNotFoundException if the JavaFX runtime is not available.
 749          */
 750         private static boolean doesExtendFXApplication(Class<?> mainClass) {
 751             for (Class<?> sc = mainClass.getSuperclass(); sc != null;
 752                     sc = sc.getSuperclass()) {
 753                 if (sc.getName().equals(JAVAFX_APPLICATION_CLASS_NAME)) {
 754                     return true;
 755                 }
 756             }
 757             return false;
 758         }
 759 
 760         public static void main(String... args) throws Exception {
 761             if (fxLauncherMethod == null
 762                     || fxLaunchMode == null
 763                     || fxLaunchName == null) {
 764                 throw new RuntimeException("Invalid JavaFX launch parameters");
 765             }
 766             // launch appClass via fxLauncherMethod
 767             fxLauncherMethod.invoke(null,
 768                     new Object[] {fxLaunchName, fxLaunchMode, args});
 769         }
 770     }
 771 }


  52 import java.nio.file.Files;
  53 import java.nio.file.Path;
  54 import java.text.Normalizer;
  55 import java.util.ResourceBundle;
  56 import java.text.MessageFormat;
  57 import java.util.ArrayList;
  58 import java.util.Collections;
  59 import java.util.Iterator;
  60 import java.util.List;
  61 import java.util.Locale;
  62 import java.util.Locale.Category;
  63 import java.util.Properties;
  64 import java.util.Set;
  65 import java.util.TreeSet;
  66 import java.util.jar.Attributes;
  67 import java.util.jar.JarFile;
  68 import java.util.jar.Manifest;
  69 
  70 public enum LauncherHelper {
  71     INSTANCE;
  72 
  73     // used to identify JavaFX applications
  74     private static final String JAVAFX_APPLICATION_MARKER =
  75             "JavaFX-Application-Class";
  76     private static final String JAVAFX_APPLICATION_CLASS_NAME =
  77             "javafx.application.Application";
  78     private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX =
  79             "LauncherHelper$FXHelper";
  80     private static final String MAIN_CLASS = "Main-Class";
  81 
  82     private static StringBuilder outBuf = new StringBuilder();
  83 
  84     private static final String INDENT = "    ";
  85     private static final String VM_SETTINGS     = "VM settings:";
  86     private static final String PROP_SETTINGS   = "Property settings:";
  87     private static final String LOCALE_SETTINGS = "Locale settings:";
  88 
  89     // sync with java.c and sun.misc.VM
  90     private static final String diagprop = "sun.java.launcher.diag";
  91     final static boolean trace = sun.misc.VM.getSavedProperty(diagprop) != null;
  92 
  93     private static final String defaultBundleName =
  94             "sun.launcher.resources.launcher";
  95     private static class ResourceBundleHolder {
  96         private static final ResourceBundle RB =
  97                 ResourceBundle.getBundle(defaultBundleName);
  98     }
  99     private static PrintStream ostream;


 409         try (JarFile jarFile = new JarFile(jarname)) {
 410             Manifest manifest = jarFile.getManifest();
 411             if (manifest == null) {
 412                 abort(null, "java.launcher.jar.error2", jarname);
 413             }
 414             Attributes mainAttrs = manifest.getMainAttributes();
 415             if (mainAttrs == null) {
 416                 abort(null, "java.launcher.jar.error3", jarname);
 417             }
 418             mainValue = mainAttrs.getValue(MAIN_CLASS);
 419             if (mainValue == null) {
 420                 abort(null, "java.launcher.jar.error3", jarname);
 421             }
 422 
 423             /*
 424              * Hand off to FXHelper if it detects a JavaFX application
 425              * This must be done after ensuring a Main-Class entry
 426              * exists to enforce compliance with the jar specification
 427              */
 428             if (mainAttrs.containsKey(
 429                     new Attributes.Name(JAVAFX_APPLICATION_MARKER))) {
 430                 FXHelper.setFXLaunchParameters(jarname, LM_JAR);
 431                 return FXHelper.class.getName();
 432             }
 433 
 434             return mainValue.trim();
 435         } catch (IOException ioe) {
 436             abort(ioe, "java.launcher.jar.error1", jarname);
 437         }
 438         return null;
 439     }
 440 
 441     // From src/share/bin/java.c:
 442     //   enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR };
 443 
 444     private static final int LM_UNKNOWN = 0;
 445     private static final int LM_CLASS   = 1;
 446     private static final int LM_JAR     = 2;
 447 
 448     static void abort(Throwable t, String msgKey, Object... args) {
 449         if (msgKey != null) {
 450             ostream.println(getLocalizedMessage(msgKey, args));


 508                 try {
 509                     // On Mac OS X since all names with diacretic symbols are given as decomposed it
 510                     // is possible that main class name comes incorrectly from the command line
 511                     // and we have to re-compose it
 512                     mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));
 513                 } catch (NoClassDefFoundError | ClassNotFoundException cnfe1) {
 514                     abort(cnfe, "java.launcher.cls.error1", cn);
 515                 }
 516             } else {
 517                 abort(cnfe, "java.launcher.cls.error1", cn);
 518             }
 519         }
 520         // set to mainClass
 521         appClass = mainClass;
 522 
 523         /*
 524          * Check if FXHelper can launch it using the FX launcher. In an FX app,
 525          * the main class may or may not have a main method, so do this before
 526          * validating the main class.
 527          */
 528         if ( mainClass.getName().contains(JAVAFX_FXHELPER_CLASS_NAME_SUFFIX) ||
 529             doesExtendFXApplication(mainClass)) {
 530             // Will abort() if there are problems with FX runtime
 531             FXHelper.setFXLaunchParameters(what, mode);
 532             return FXHelper.class;
 533         }
 534 
 535         validateMainClass(mainClass);
 536         return mainClass;
 537     }
 538 
 539     /*
 540      * Accessor method called by the launcher after getting the main class via
 541      * checkAndLoadMain(). The "application class" is the class that is finally
 542      * executed to start the application and in this case is used to report
 543      * the correct application name, typically for UI purposes.
 544      */
 545     public static Class<?> getApplicationClass() {
 546         return appClass;
 547     }
 548 
 549     /*
 550      * Check if the given class is a JavaFX Application class. This is done
 551      * in a way that does not cause the Application class to load or throw
 552      * ClassNotFoundException if the JavaFX runtime is not available.
 553      */
 554     private static boolean doesExtendFXApplication(Class<?> mainClass) {
 555         for (Class<?> sc = mainClass.getSuperclass(); sc != null;
 556                 sc = sc.getSuperclass()) {
 557             if (sc.getName().equals(JAVAFX_APPLICATION_CLASS_NAME)) {
 558                 return true;
 559             }
 560         }
 561         return false;
 562     }
 563 
 564     // Check the existence and signature of main and abort if incorrect
 565     static void validateMainClass(Class<?> mainClass) {
 566         Method mainMethod;
 567         try {
 568             mainMethod = mainClass.getMethod("main", String[].class);
 569         } catch (NoSuchMethodException nsme) {
 570             // invalid main or not FX application, abort with an error
 571             abort(null, "java.launcher.cls.error4", mainClass.getName(),
 572                   JAVAFX_APPLICATION_CLASS_NAME);
 573             return; // Avoid compiler issues
 574         }
 575 
 576         /*
 577          * getMethod (above) will choose the correct method, based
 578          * on its name and parameter type, however, we still have to
 579          * ensure that the method is static and returns a void.
 580          */
 581         int mod = mainMethod.getModifiers();
 582         if (!Modifier.isStatic(mod)) {
 583             abort(null, "java.launcher.cls.error2", "static",
 584                   mainMethod.getDeclaringClass().getName());
 585         }
 586         if (mainMethod.getReturnType() != java.lang.Void.TYPE) {
 587             abort(null, "java.launcher.cls.error3",
 588                   mainMethod.getDeclaringClass().getName());
 589         }
 590         return;
 591     }
 592 
 593     private static final String encprop = "sun.jnu.encoding";
 594     private static String encoding = null;
 595     private static boolean isCharsetSupported = false;
 596 
 597     /*
 598      * converts a c or a byte array to a platform specific string,
 599      * previously implemented as a native method in the launcher.
 600      */
 601     static String makePlatformString(boolean printToStderr, byte[] inArray) {
 602         initOutput(printToStderr);
 603         if (encoding == null) {
 604             encoding = System.getProperty(encprop);
 605             isCharsetSupported = Charset.isSupported(encoding);
 606         }
 607         try {
 608             String out = isCharsetSupported
 609                     ? new String(inArray, encoding)
 610                     : new String(inArray);


 676     private static class StdArg {
 677         final String arg;
 678         final boolean needsExpansion;
 679         StdArg(String arg, boolean expand) {
 680             this.arg = arg;
 681             this.needsExpansion = expand;
 682         }
 683         // protocol: first char indicates whether expansion is required
 684         // 'T' = true ; needs expansion
 685         // 'F' = false; needs no expansion
 686         StdArg(String in) {
 687             this.arg = in.substring(1);
 688             needsExpansion = in.charAt(0) == 'T';
 689         }
 690         public String toString() {
 691             return "StdArg{" + "arg=" + arg + ", needsExpansion=" + needsExpansion + '}';
 692         }
 693     }
 694 
 695     static final class FXHelper {
 696 




 697         private static final String JAVAFX_LAUNCHER_CLASS_NAME =
 698                 "com.sun.javafx.application.LauncherImpl";
 699 
 700         /*
 701          * The launch method used to invoke the JavaFX launcher. These must
 702          * match the strings used in the launchApplication method.
 703          *
 704          * Command line                 JavaFX-App-Class  Launch mode  FX Launch mode
 705          * java -cp fxapp.jar FXClass   N/A               LM_CLASS     "LM_CLASS"
 706          * java -cp somedir FXClass     N/A               LM_CLASS     "LM_CLASS"
 707          * java -jar fxapp.jar          Present           LM_JAR       "LM_JAR"
 708          * java -jar fxapp.jar          Not Present       LM_JAR       "LM_JAR"
 709          */
 710         private static final String JAVAFX_LAUNCH_MODE_CLASS = "LM_CLASS";
 711         private static final String JAVAFX_LAUNCH_MODE_JAR = "LM_JAR";
 712 
 713         /*
 714          * FX application launcher and launch method, so we can launch
 715          * applications with no main method.
 716          */


 746                     abort(null, "java.launcher.javafx.error1");
 747                 }
 748             } catch (ClassNotFoundException | NoSuchMethodException ex) {
 749                 abort(ex, "java.launcher.cls.error5", ex);
 750             }
 751 
 752             fxLaunchName = what;
 753             switch (mode) {
 754                 case LM_CLASS:
 755                     fxLaunchMode = JAVAFX_LAUNCH_MODE_CLASS;
 756                     break;
 757                 case LM_JAR:
 758                     fxLaunchMode = JAVAFX_LAUNCH_MODE_JAR;
 759                     break;
 760                 default:
 761                     // should not have gotten this far...
 762                     throw new InternalError(mode + ": Unknown launch mode");
 763             }
 764         }
 765 















 766         public static void main(String... args) throws Exception {
 767             if (fxLauncherMethod == null
 768                     || fxLaunchMode == null
 769                     || fxLaunchName == null) {
 770                 throw new RuntimeException("Invalid JavaFX launch parameters");
 771             }
 772             // launch appClass via fxLauncherMethod
 773             fxLauncherMethod.invoke(null,
 774                     new Object[] {fxLaunchName, fxLaunchMode, args});
 775         }
 776     }
 777 }