src/jdk/nashorn/internal/runtime/ScriptingFunctions.java

changeset 67
6f58c28c4faa
parent 57
59970b70ebb5
child 69
c48e8a28da90
equal deleted inserted replaced
66:bee7c8a45a04 67:6f58c28c4faa
30 import static jdk.nashorn.internal.runtime.linker.Lookup.MH; 30 import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
31 31
32 import java.io.BufferedReader; 32 import java.io.BufferedReader;
33 import java.io.File; 33 import java.io.File;
34 import java.io.IOException; 34 import java.io.IOException;
35 import java.io.InputStream;
35 import java.io.InputStreamReader; 36 import java.io.InputStreamReader;
37 import java.io.OutputStream;
36 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodHandle;
37 import java.lang.invoke.MethodHandles; 39 import java.lang.invoke.MethodHandles;
40 import java.util.HashMap;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.StringTokenizer;
38 44
39 /** 45 /**
40 * Global functions supported only in scripting mode. 46 * Global functions supported only in scripting mode.
41 */ 47 */
42 public class ScriptingFunctions { 48 public class ScriptingFunctions {
48 public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class); 54 public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class);
49 55
50 /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */ 56 /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */
51 public static final MethodHandle QUIT = findOwnMH("quit", Object.class, Object.class, Object.class); 57 public static final MethodHandle QUIT = findOwnMH("quit", Object.class, Object.class, Object.class);
52 58
59 /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */
60 public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class);
61
62 /** Names of special properties used by $EXEC API. */
63 public static final String EXEC_NAME = "$EXEC";
64 private static final String OUT_NAME = "$OUT";
65 private static final String ERR_NAME = "$ERR";
66 private static final String EXIT_NAME = "$EXIT";
67
68 /** Names of special properties used by $ENV API. */
69 public static final String ENV_NAME = "$ENV";
70 private static final String PWD_NAME = "PWD";
71
53 private ScriptingFunctions() { 72 private ScriptingFunctions() {
54 } 73 }
55 74
56 /** 75 /**
57 * Nashorn extension: global.readLine (scripting-mode-only) 76 * Nashorn extension: global.readLine (scripting-mode-only)
106 public static Object quit(final Object self, final Object code) { 125 public static Object quit(final Object self, final Object code) {
107 System.exit(JSType.toInt32(code)); 126 System.exit(JSType.toInt32(code));
108 return UNDEFINED; 127 return UNDEFINED;
109 } 128 }
110 129
130 /**
131 * Nashorn extension: exec a string in a separate process.
132 *
133 * @param self self reference
134 * @param string string to execute
135 *
136 * @return output string from the request
137 */
138 public static Object exec(final Object self, final Object string, final Object input) throws IOException, InterruptedException {
139 // Current global is need to fetch additional inputs and for additional results.
140 final ScriptObject global = Context.getGlobal();
141
142 // Current ENV property state.
143 final Object env = global.get(ENV_NAME);
144 // Make sure ENV is a valid script object.
145 if (!(env instanceof ScriptObject)) {
146 typeError("env.not.object");
147 }
148 final ScriptObject envProperties = (ScriptObject)env;
149
150 // Break exec string into tokens.
151 final StringTokenizer tokenizer = new StringTokenizer(JSType.toString(string));
152 final String[] cmdArray = new String[tokenizer.countTokens()];
153 for (int i = 0; tokenizer.hasMoreTokens(); i++) {
154 cmdArray[i] = tokenizer.nextToken();
155 }
156
157 // Set up initial process.
158 final ProcessBuilder processBuilder = new ProcessBuilder(cmdArray);
159
160 // If a working directory is present, use it.
161 final Object pwd = envProperties.get(PWD_NAME);
162 if (pwd != UNDEFINED) {
163 processBuilder.directory(new File(JSType.toString(pwd)));
164 }
165
166 // Set up ENV variables.
167 final Map<String, String> environment = processBuilder.environment();
168 environment.clear();
169 for (Map.Entry<Object, Object> entry : envProperties.entrySet()) {
170
171 environment.put(JSType.toString(entry.getKey()), JSType.toString(entry.getValue()));
172 }
173
174 // Start the process.
175 final Process process = processBuilder.start();
176
177 // If input is present, pass on to process.
178 try (OutputStream outputStream = process.getOutputStream()) {
179 if (input != UNDEFINED) {
180 outputStream.write(JSType.toString(input).getBytes());
181 }
182 }
183
184 // Wait for the process to complete.
185 final int exit = process.waitFor();
186
187 // Collect output.
188 String out;
189 try (InputStream inputStream = process.getInputStream()) {
190 final StringBuilder outBuffer = new StringBuilder();
191 for (int ch; (ch = inputStream.read()) != -1; ) {
192 outBuffer.append((char)ch);
193 }
194 out = outBuffer.toString();
195 }
196
197 // Collect errors.
198 String err;
199 try (InputStream errorStream = process.getErrorStream()) {
200 final StringBuilder errBuffer = new StringBuilder();
201 for (int ch; (ch = errorStream.read()) != -1; ) {
202 errBuffer.append((char)ch);
203 }
204 err = errBuffer.toString();
205 }
206
207 // Set globals for secondary results.
208 final boolean isStrict = global.isStrictContext();
209 global.set(OUT_NAME, out, isStrict);
210 global.set(ERR_NAME, err, isStrict);
211 global.set(EXIT_NAME, exit, isStrict);
212
213 // Return the result from stdout.
214 return out;
215 }
216
217 /**
218 * Return an object containing properties mapping to ENV variables.
219 *
220 * @param envProperties object to receive properties
221 * @param isStrict global's strict state
222 *
223 * @return Script object with properties mapping to ENV variables.
224 */
225 public static ScriptObject getENVValues(final ScriptObject envProperties, final boolean isStrict) {
226 // Retrieve current state of ENV variables.
227 Map<String, String> envVars;
228 try {
229 envVars = System.getenv();
230 } catch(SecurityException ex) {
231 envVars = new HashMap<>();
232 }
233
234 // Map ENV variables.
235 for (Map.Entry<String, String> entry : envVars.entrySet()) {
236 envProperties.set(entry.getKey(), entry.getValue(), isStrict);
237 }
238
239 return envProperties;
240 }
241
111 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 242 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
112 return MH.findStatic(MethodHandles.lookup(), ScriptingFunctions.class, name, MH.type(rtype, types)); 243 return MH.findStatic(MethodHandles.lookup(), ScriptingFunctions.class, name, MH.type(rtype, types));
113 } 244 }
114 } 245 }

mercurial