src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java
changeset 47492 560fab171dc7
parent 47216 71c04702a3d5
child 47704 38aa08d2ec6c
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Fri Nov 03 02:21:58 2017 +0000
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Fri Nov 03 19:53:09 2017 +0530
@@ -27,8 +27,6 @@
 
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
-import java.awt.Desktop;
-import java.awt.GraphicsEnvironment;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
@@ -65,7 +63,6 @@
     private static final String DOC_PROPERTY_NAME = "__doc__";
 
     static final boolean DEBUG = Boolean.getBoolean("nashorn.jjs.debug");
-    static final boolean HEADLESS = GraphicsEnvironment.isHeadless();
 
     // file where history is persisted.
     private static final File HIST_FILE = new File(new File(System.getProperty("user.home")), ".jjs.history");
@@ -120,7 +117,49 @@
         final Global oldGlobal = Context.getGlobal();
         final boolean globalChanged = (oldGlobal != global);
         final PropertiesHelper propsHelper = new PropertiesHelper(context);
-        final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper);
+
+        if (globalChanged) {
+            Context.setGlobal(global);
+        }
+
+        // Check if java.desktop module is available and we're running in non-headless mode.
+        // We access AWT via script to avoid direct dependency on java.desktop module.
+        final boolean isHeadless = (boolean) context.eval(global,
+            "(function() { \n" +
+            "    var env = java.awt.GraphicsEnvironment; \n" +
+            "    return env && typeof env.isHeadless == 'function'? \n" +
+            "        env.isHeadless() : true; \n" +
+            "})()",
+            global, "<headless-check>");
+
+        // Function that shows a JFileChooser dialog and returns the file name chosen (if chosen).
+        // We access swing from script to avoid direct dependency on java.desktop module.
+        final ScriptFunction fileChooserFunc = isHeadless? null : (ScriptFunction) context.eval(global,
+            "(function() { \n" +
+            "    var ExtensionFilter = javax.swing.filechooser.FileNameExtensionFilter; \n" +
+            "    var JFileChooser = javax.swing.JFileChooser; \n" +
+            "    function run() { \n" +
+            "        var chooser = new JFileChooser(); \n" +
+            "        chooser.fileFilter = new ExtensionFilter('JavaScript Files', 'js'); \n" +
+            "        var retVal = chooser.showOpenDialog(null);  \n" +
+            "        return retVal == JFileChooser.APPROVE_OPTION ?  \n" +
+            "            chooser.selectedFile.absolutePath : null; \n" +
+            "    }; \n" +
+            "    var fileChooserTask = new java.util.concurrent.FutureTask(run); \n" +
+            "    javax.swing.SwingUtilities.invokeLater(fileChooserTask); \n" +
+            "    return fileChooserTask.get(); \n" +
+            "})",
+            global, "<file-chooser>");
+
+        final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper, fileChooserFunc);
+
+        // Function that opens up the desktop browser application with the given URI.
+        // We access AWT from script to avoid direct dependency on java.desktop module.
+        final ScriptFunction browseFunc = isHeadless? null : (ScriptFunction) context.eval(global,
+            "(function(uri) { \n" +
+            "    java.awt.Desktop.desktop.browse(uri); \n" +
+            "})",
+            global, "<browse>");
 
         try (final Console in = new Console(System.in, System.out, HIST_FILE, completer,
                 str -> {
@@ -128,14 +167,14 @@
                         final Object res = context.eval(global, str, global, "<shell>");
                         if (res != null && res != UNDEFINED) {
                             // Special case Java types: show the javadoc for the class.
-                            if (NativeJava.isType(UNDEFINED, res)) {
+                            if (!isHeadless && NativeJava.isType(UNDEFINED, res)) {
                                 final String typeName = NativeJava.typeName(UNDEFINED, res).toString();
                                 final String url = typeName.replace('.', '/').replace('$', '.') + ".html";
-                                openBrowserForJavadoc(url);
-                            } else if (res instanceof NativeJavaPackage) {
+                                openBrowserForJavadoc(browseFunc, url);
+                            } else if (!isHeadless && res instanceof NativeJavaPackage) {
                                 final String pkgName = ((NativeJavaPackage)res).getName();
                                 final String url = pkgName.replace('.', '/') + "/package-summary.html";
-                                openBrowserForJavadoc(url);
+                                openBrowserForJavadoc(browseFunc, url);
                             } else if (res instanceof ScriptObject) {
                                 final ScriptObject sobj = (ScriptObject)res;
                                 if (sobj.has(DOC_PROPERTY_NAME)) {
@@ -153,10 +192,6 @@
                      return null;
                 })) {
 
-            if (globalChanged) {
-                Context.setGlobal(global);
-            }
-
             global.addShellBuiltins();
 
             // redefine readLine to use jline Console's readLine!
@@ -282,11 +317,10 @@
     }
 
     private static String JAVADOC_BASE = "https://docs.oracle.com/javase/9/docs/api/";
-
-    private static void openBrowserForJavadoc(String relativeUrl) {
+    private static void openBrowserForJavadoc(ScriptFunction browse, String relativeUrl) {
         try {
             final URI uri = new URI(JAVADOC_BASE + relativeUrl);
-            Desktop.getDesktop().browse(uri);
+            ScriptRuntime.apply(browse, null, uri);
         } catch (Exception ignored) {
         }
     }