/*
 * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.nashorn.internal.runtime;

import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import jdk.nashorn.internal.objects.NativeArray;
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;

Global functions supported only in scripting mode.
/** * Global functions supported only in scripting mode. */
public final class ScriptingFunctions {
Handle to implementation of readLine - Nashorn extension
/** Handle to implementation of {@link ScriptingFunctions#readLine} - Nashorn extension */
public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class, Object.class);
Handle to implementation of readFully - Nashorn extension
/** Handle to implementation of {@link ScriptingFunctions#readFully} - Nashorn extension */
public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class);
Handle to implementation of exec - Nashorn extension
/** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */
public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object[].class);
EXEC name - special property used by $EXEC API.
/** EXEC name - special property used by $EXEC API. */
public static final String EXEC_NAME = "$EXEC";
OUT name - special property used by $EXEC API.
/** OUT name - special property used by $EXEC API. */
public static final String OUT_NAME = "$OUT";
ERR name - special property used by $EXEC API.
/** ERR name - special property used by $EXEC API. */
public static final String ERR_NAME = "$ERR";
EXIT name - special property used by $EXEC API.
/** EXIT name - special property used by $EXEC API. */
public static final String EXIT_NAME = "$EXIT";
Names of special properties used by $ENV API.
/** Names of special properties used by $ENV API. */
public static final String ENV_NAME = "$ENV";
Name of the environment variable for the current working directory.
/** Name of the environment variable for the current working directory. */
public static final String PWD_NAME = "PWD"; private ScriptingFunctions() { }
Nashorn extension: global.readLine (scripting-mode-only) Read one line of input from the standard input.
Params:
  • self – self reference
  • prompt – String used as input prompt
Throws:
Returns:line that was read
/** * Nashorn extension: global.readLine (scripting-mode-only) * Read one line of input from the standard input. * * @param self self reference * @param prompt String used as input prompt * * @return line that was read * * @throws IOException if an exception occurs */
public static Object readLine(final Object self, final Object prompt) throws IOException { return readLine(prompt); }
Nashorn extension: Read the entire contents of a text file and return as String.
Params:
  • self – self reference
  • file – The input file whose content is read.
Throws:
Returns:String content of the input file.
/** * Nashorn extension: Read the entire contents of a text file and return as String. * * @param self self reference * @param file The input file whose content is read. * * @return String content of the input file. * * @throws IOException if an exception occurs */
public static Object readFully(final Object self, final Object file) throws IOException { File f = null; if (file instanceof File) { f = (File)file; } else if (JSType.isString(file)) { f = new java.io.File(((CharSequence)file).toString()); } if (f == null || !f.isFile()) { throw typeError("not.a.file", ScriptRuntime.safeToString(file)); } return new String(Source.readFully(f)); }
Nashorn extension: exec a string in a separate process.
Params:
  • self – self reference
  • args – In one of four forms 1. String script, String input 2. String script, InputStream input, OutputStream output, OutputStream error 3. Array scriptTokens, String input 4. Array scriptTokens, InputStream input, OutputStream output, OutputStream error
Returns:output string from the request if in form of 1. or 3., empty string otherwise
/** * Nashorn extension: exec a string in a separate process. * * @param self self reference * @param args In one of four forms * 1. String script, String input * 2. String script, InputStream input, OutputStream output, OutputStream error * 3. Array scriptTokens, String input * 4. Array scriptTokens, InputStream input, OutputStream output, OutputStream error * * @return output string from the request if in form of 1. or 3., empty string otherwise */
public static Object exec(final Object self, final Object... args) { final Object arg0 = args.length > 0 ? args[0] : UNDEFINED; final Object arg1 = args.length > 1 ? args[1] : UNDEFINED; final Object arg2 = args.length > 2 ? args[2] : UNDEFINED; final Object arg3 = args.length > 3 ? args[3] : UNDEFINED; InputStream inputStream = null; OutputStream outputStream = null; OutputStream errorStream = null; String script = null; List<String> tokens = null; String inputString = null; if (arg0 instanceof NativeArray) { final String[] array = (String[])JSType.toJavaArray(arg0, String.class); tokens = new ArrayList<>(); tokens.addAll(Arrays.asList(array)); } else { script = JSType.toString(arg0); } if (arg1 instanceof InputStream) { inputStream = (InputStream)arg1; } else { inputString = JSType.toString(arg1); } if (arg2 instanceof OutputStream) { outputStream = (OutputStream)arg2; } if (arg3 instanceof OutputStream) { errorStream = (OutputStream)arg3; } // Current global is need to fetch additional inputs and for additional results. final ScriptObject global = Context.getGlobal(); // Capture ENV property state. final Map<String, String> environment = new HashMap<>(); final Object env = global.get(ENV_NAME); if (env instanceof ScriptObject) { final ScriptObject envProperties = (ScriptObject)env; // Copy ENV variables. envProperties.entrySet().stream().forEach((entry) -> { environment.put(JSType.toString(entry.getKey()), JSType.toString(entry.getValue())); }); } // get the $EXEC function object from the global object final Object exec = global.get(EXEC_NAME); assert exec instanceof ScriptObject : EXEC_NAME + " is not a script object!"; // Execute the commands final CommandExecutor executor = new CommandExecutor(); executor.setInputString(inputString); executor.setInputStream(inputStream); executor.setOutputStream(outputStream); executor.setErrorStream(errorStream); executor.setEnvironment(environment); if (tokens != null) { executor.process(tokens); } else { executor.process(script); } final String outString = executor.getOutputString(); final String errString = executor.getErrorString(); final int exitCode = executor.getExitCode(); // Set globals for secondary results. global.set(OUT_NAME, outString, 0); global.set(ERR_NAME, errString, 0); global.set(EXIT_NAME, exitCode, 0); // Return the result from stdout. return outString; } // Implementation for pluggable "readLine" functionality // Used by jjs interactive mode private static Function<String, String> readLineHelper; public static void setReadLineHelper(final Function<String, String> func) { readLineHelper = Objects.requireNonNull(func); } public static Function<String, String> getReadLineHelper() { return readLineHelper; } public static String readLine(final Object prompt) throws IOException { final String p = (prompt != UNDEFINED)? JSType.toString(prompt) : ""; if (readLineHelper != null) { return readLineHelper.apply(p); } else { System.out.print(p); final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); return reader.readLine(); } } private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { return MH.findStatic(MethodHandles.lookup(), ScriptingFunctions.class, name, MH.type(rtype, types)); } }