1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 (function () { 27 28 // Check if java.desktop module is available and we're running in non-headless mode. 29 // We access AWT via script to avoid direct dependency on java.desktop module. 30 function isHeadless() { 31 var GraphicsEnvironment = java.awt.GraphicsEnvironment; 32 return Java.isType(GraphicsEnvironment)? GraphicsEnvironment.isHeadless() : true; 33 } 34 35 36 // Function that shows a JFileChooser dialog and returns the file name chosen (if chosen). 37 // We access swing from script to avoid direct dependency on java.desktop module. 38 function chooseFile() { 39 var JFileChooser = javax.swing.JFileChooser; 40 if (!Java.isType(JFileChooser)) { 41 return null; 42 } 43 44 var ExtensionFilter = javax.swing.filechooser.FileNameExtensionFilter; 45 function run() { 46 var chooser = new JFileChooser(); 47 chooser.fileFilter = new ExtensionFilter('JavaScript Files', 'js'); 48 var retVal = chooser.showOpenDialog(null); 49 return retVal == JFileChooser.APPROVE_OPTION ? 50 chooser.selectedFile.absolutePath : null; 51 } 52 53 var FutureTask = java.util.concurrent.FutureTask; 54 var fileChooserTask = new FutureTask(run); 55 javax.swing.SwingUtilities.invokeLater(fileChooserTask); 56 57 return fileChooserTask.get(); 58 } 59 60 // Function that opens up the desktop browser application with the given URI. 61 // We access AWT from script to avoid direct dependency on java.desktop module. 62 function browse(uri) { 63 var Desktop = java.awt.Desktop; 64 if (Java.isType(Desktop)) { 65 Desktop.desktop.browse(uri); 66 } 67 } 68 69 function printDoc(list) { 70 list.forEach(function(doc) { 71 print(); 72 print(doc.signature()); 73 print(); 74 print(doc.javadoc()); 75 }); 76 } 77 78 var JShell = null; 79 var jshell = null; 80 81 function javadoc(obj) { 82 var str = String(obj); 83 if (!JShell) { 84 // first time - resolve JShell class 85 JShell = Packages.jdk.jshell.JShell; 86 // if JShell class is available, create an instance 87 jshell = Java.isType(JShell)? JShell.create() : null; 88 } 89 90 if (!jshell) { 91 // we don't have jshell. Just print the default! 92 return print(str); 93 } 94 95 /* 96 * A java method object's String representation looks something like this: 97 * 98 * For an overloaded method: 99 * 100 * [jdk.dynalink.beans.OverloadedDynamicMethod 101 * String java.lang.System.getProperty(String,String) 102 * String java.lang.System.getProperty(String) 103 * ] 104 * 105 * For a non-overloaded method: 106 * 107 * [jdk.dynalink.beans.SimpleDynamicMethod void java.lang.System.exit(int)] 108 * 109 * jshell expects "java.lang.System.getProperty(" or "java.lang.System.exit(" 110 * to retrieve the javadoc comment(s) for the method. 111 */ 112 var javaCode = str.split(" ")[2]; // stuff after second whitespace char 113 javaCode = javaCode.substring(0, javaCode.indexOf('(') + 1); // strip argument types 114 115 try { 116 var analysis = jshell.sourceCodeAnalysis(); 117 var docList = analysis.documentation(javaCode, javaCode.length, true); 118 if (!docList.isEmpty()) { 119 return printDoc(docList); 120 } 121 122 /* 123 * May be the method is a Java instance method. In such a case, jshell expects 124 * a valid starting portion of an instance method call expression. We cast null 125 * to Java object and call method on it. i.e., We pass something like this: 126 * 127 * "((java.io.PrintStream)null).println(" 128 */ 129 var javaType = javaCode.substring(0, javaCode.lastIndexOf('.')); 130 javaCode = "((" + javaType + ")null)" + javaCode.substring(javaCode.lastIndexOf('.')); 131 docList = analysis.documentation(javaCode, javaCode.length, true); 132 if (!docList.isEmpty()) { 133 return printDoc(docList); 134 } 135 } catch (e) { 136 } 137 print(str); 138 } 139 140 return { 141 isHeadless: isHeadless, 142 chooseFile: chooseFile, 143 browse: browse, 144 javadoc: javadoc 145 }; 146 147 })();