ScriptingFunctions.java revision 1637:f27bb66ac9d3
194541Sru/* 294541Sru * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. 394541Sru * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 494541Sru * 594541Sru * This code is free software; you can redistribute it and/or modify it 694541Sru * under the terms of the GNU General Public License version 2 only, as 794541Sru * published by the Free Software Foundation. Oracle designates this 894541Sru * particular file as subject to the "Classpath" exception as provided 994541Sru * by Oracle in the LICENSE file that accompanied this code. 1094541Sru * 1194541Sru * This code is distributed in the hope that it will be useful, but WITHOUT 1294541Sru * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1394541Sru * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1494541Sru * version 2 for more details (a copy is included in the LICENSE file that 1594541Sru * accompanied this code). 1694541Sru * 1794541Sru * You should have received a copy of the GNU General Public License version 1894541Sru * 2 along with this work; if not, write to the Free Software Foundation, 1994541Sru * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2094541Sru * 2194541Sru * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2294541Sru * or visit www.oracle.com if you need additional information or have any 2394541Sru * questions. 2494541Sru */ 2594541Sru 2694541Srupackage jdk.nashorn.internal.runtime; 2794541Sru 2894541Sruimport static jdk.nashorn.internal.lookup.Lookup.MH; 29172400Sruimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 3094541Sruimport static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 31255454Sdes 3294541Sruimport java.io.BufferedReader; 3394541Sruimport java.io.File; 3494541Sruimport java.io.IOException; 3594541Sruimport java.io.InputStream; 3694541Sruimport java.io.InputStreamReader; 3794541Sruimport java.io.OutputStream; 3894541Sruimport java.lang.invoke.MethodHandle; 3994541Sruimport java.lang.invoke.MethodHandles; 4094541Sruimport java.util.ArrayList; 41172400Sruimport java.util.Arrays; 4294541Sruimport java.util.HashMap; 4394541Sruimport java.util.List; 4494541Sruimport java.util.Map; 4594541Sruimport jdk.nashorn.internal.objects.NativeArray; 4694541Sruimport static jdk.nashorn.internal.runtime.ECMAErrors.rangeError; 4794541Sru 4894541Sru/** 4994541Sru * Global functions supported only in scripting mode. 50115122Sru */ 51247779Sbaptpublic final class ScriptingFunctions { 52202969Sru 5394541Sru /** Handle to implementation of {@link ScriptingFunctions#readLine} - Nashorn extension */ 54202969Sru public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class, Object.class); 55202969Sru 56202969Sru /** Handle to implementation of {@link ScriptingFunctions#readFully} - Nashorn extension */ 57233294Sstas public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class); 58128184Sru 5994541Sru /** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */ 6094541Sru public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object[].class); 6194541Sru 6294541Sru /** EXEC name - special property used by $EXEC API. */ 6394541Sru public static final String EXEC_NAME = "$EXEC"; 6494541Sru 6594541Sru /** OUT name - special property used by $EXEC API. */ 6694541Sru public static final String OUT_NAME = "$OUT"; 6794541Sru 68255454Sdes /** ERR name - special property used by $EXEC API. */ 6994541Sru public static final String ERR_NAME = "$ERR"; 7094541Sru 7194541Sru /** EXIT name - special property used by $EXEC API. */ 7294541Sru public static final String EXIT_NAME = "$EXIT"; 7394541Sru 74164581Sdelphij /** Names of special properties used by $ENV API. */ 7594541Sru public static final String ENV_NAME = "$ENV"; 7694541Sru 7794541Sru /** Name of the environment variable for the current working directory. */ 7894541Sru public static final String PWD_NAME = "PWD"; 7994541Sru 8094541Sru private ScriptingFunctions() { 8194541Sru } 8294541Sru 8394541Sru /** 8494541Sru * Nashorn extension: global.readLine (scripting-mode-only) 8594541Sru * Read one line of input from the standard input. 8694541Sru * 8794541Sru * @param self self reference 8894541Sru * @param prompt String used as input prompt 8994541Sru * 9094541Sru * @return line that was read 9194541Sru * 9294541Sru * @throws IOException if an exception occurs 9394541Sru */ 9494541Sru public static Object readLine(final Object self, final Object prompt) throws IOException { 9594541Sru if (prompt != UNDEFINED) { 9694541Sru System.out.print(JSType.toString(prompt)); 9794541Sru } 9894541Sru final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 9994541Sru return reader.readLine(); 10094541Sru } 10194541Sru 10294541Sru /** 10394541Sru * Nashorn extension: Read the entire contents of a text file and return as String. 10494541Sru * 10594541Sru * @param self self reference 10694541Sru * @param file The input file whose content is read. 10794541Sru * 10894541Sru * @return String content of the input file. 10994541Sru * 11094541Sru * @throws IOException if an exception occurs 11194541Sru */ 11294541Sru public static Object readFully(final Object self, final Object file) throws IOException { 11394541Sru File f = null; 11494541Sru 11594541Sru if (file instanceof File) { 11694541Sru f = (File)file; 11794541Sru } else if (JSType.isString(file)) { 11894541Sru f = new java.io.File(((CharSequence)file).toString()); 11994541Sru } 12094541Sru 12194541Sru if (f == null || !f.isFile()) { 122 throw typeError("not.a.file", ScriptRuntime.safeToString(file)); 123 } 124 125 return new String(Source.readFully(f)); 126 } 127 128 /** 129 * Nashorn extension: exec a string in a separate process. 130 * 131 * @param self self reference 132 * @param args In one of four forms 133 * 1. String script, String input 134 * 2. String script, InputStream input, OutputStream output, OutputStream error 135 * 3. Array scriptTokens, String input 136 * 4. Array scriptTokens, InputStream input, OutputStream output, OutputStream error 137 * 138 * @return output string from the request if in form of 1. or 3., empty string otherwise 139 */ 140 public static Object exec(final Object self, final Object... args) { 141 final Object arg0 = args.length > 0 ? args[0] : UNDEFINED; 142 final Object arg1 = args.length > 1 ? args[1] : UNDEFINED; 143 final Object arg2 = args.length > 2 ? args[2] : UNDEFINED; 144 final Object arg3 = args.length > 3 ? args[3] : UNDEFINED; 145 146 InputStream inputStream = null; 147 OutputStream outputStream = null; 148 OutputStream errorStream = null; 149 String script = null; 150 List<String> tokens = null; 151 String inputString = null; 152 153 if (arg0 instanceof NativeArray) { 154 String[] array = (String[])JSType.toJavaArray(arg0, String.class); 155 tokens = new ArrayList<>(); 156 tokens.addAll(Arrays.asList(array)); 157 } else { 158 script = JSType.toString(arg0); 159 } 160 161 if (arg1 instanceof InputStream) { 162 inputStream = (InputStream)arg1; 163 } else { 164 inputString = JSType.toString(arg1); 165 } 166 167 if (arg2 instanceof OutputStream) { 168 outputStream = (OutputStream)arg2; 169 } 170 171 if (arg3 instanceof OutputStream) { 172 errorStream = (OutputStream)arg3; 173 } 174 175 // Current global is need to fetch additional inputs and for additional results. 176 final ScriptObject global = Context.getGlobal(); 177 178 // Capture ENV property state. 179 final Map<String, String> environment = new HashMap<>(); 180 final Object env = global.get(ENV_NAME); 181 182 if (env instanceof ScriptObject) { 183 final ScriptObject envProperties = (ScriptObject)env; 184 185 // Copy ENV variables. 186 envProperties.entrySet().stream().forEach((entry) -> { 187 environment.put(JSType.toString(entry.getKey()), JSType.toString(entry.getValue())); 188 }); 189 } 190 191 // get the $EXEC function object from the global object 192 final Object exec = global.get(EXEC_NAME); 193 assert exec instanceof ScriptObject : EXEC_NAME + " is not a script object!"; 194 195 // Execute the commands 196 final CommandExecutor executor = new CommandExecutor(); 197 executor.setInputString(inputString); 198 executor.setInputStream(inputStream); 199 executor.setOutputStream(outputStream); 200 executor.setErrorStream(errorStream); 201 executor.setEnvironment(environment); 202 203 if (tokens != null) { 204 executor.process(tokens); 205 } else { 206 executor.process(script); 207 } 208 209 final String outString = executor.getOutputString(); 210 final String errString = executor.getErrorString(); 211 int exitCode = executor.getExitCode(); 212 213 // Set globals for secondary results. 214 global.set(OUT_NAME, outString, 0); 215 global.set(ERR_NAME, errString, 0); 216 global.set(EXIT_NAME, exitCode, 0); 217 218 // Return the result from stdout. 219 return outString; 220 } 221 222 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 223 return MH.findStatic(MethodHandles.lookup(), ScriptingFunctions.class, name, MH.type(rtype, types)); 224 } 225} 226