# HG changeset patch # User jlahoda # Date 1472135774 -7200 # Thu Aug 25 16:36:14 2016 +0200 # Node ID ed4dbd31b6d9ae2e6abfdd4549c47d2324344a80 # Parent 34dea0a7b9ab1afbbbaaa30a05fa0b60b96f2338 imported patch 8131023 diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -57,6 +57,8 @@ import jdk.internal.jline.console.KeyMap; import jdk.internal.jline.console.UserInterruptException; import jdk.internal.jline.console.completer.Completer; +import jdk.internal.jline.console.history.History; +import jdk.internal.jline.console.history.MemoryHistory; import jdk.internal.jline.extra.EditingHistory; import jdk.internal.jshell.tool.StopDetectingInputStream.State; @@ -68,6 +70,7 @@ final StopDetectingInputStream input; final ConsoleReader in; final EditingHistory history; + final MemoryHistory userInputHistory = new MemoryHistory(); String prefix = ""; @@ -299,6 +302,9 @@ } public void beforeUserCode() { + synchronized (this) { + inputBytes = null; + } input.setState(State.BUFFER); } @@ -380,6 +386,36 @@ } } + private byte[] inputBytes; + private int inputBytesPointer; + + @Override + public synchronized int readUserInput() { + while (inputBytes == null || inputBytes.length <= inputBytesPointer) { + boolean prevHandleUserInterrupt = in.getHandleUserInterrupt(); + History prevHistory = in.getHistory(); + + try { + input.setState(State.WAIT); + in.setHandleUserInterrupt(true); + in.setHistory(userInputHistory); + inputBytes = (in.readLine("") + System.getProperty("line.separator")).getBytes(); + inputBytesPointer = 0; + } catch (IOException ex) { + ex.printStackTrace(); + return -1; + } catch (UserInterruptException ex) { + repl.state.stop(); + return -1; + } finally { + in.setHistory(prevHistory); + in.setHandleUserInterrupt(prevHandleUserInterrupt); + input.setState(State.BUFFER); + } + } + return inputBytes[inputBytesPointer++]; + } + /** * A possible action which the user can choose to perform. */ diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java @@ -54,6 +54,8 @@ public abstract void replaceLastHistoryEntry(String source); + public abstract int readUserInput(); + class InputInterruptedException extends Exception { private static final long serialVersionUID = 1L; } diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -26,7 +26,6 @@ package jdk.internal.jshell.tool; import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; @@ -153,13 +152,18 @@ */ public JShellTool(InputStream cmdin, PrintStream cmdout, PrintStream cmderr, PrintStream console, - InputStream userin, PrintStream userout, PrintStream usererr, + PrintStream userout, PrintStream usererr, Preferences prefs, Locale locale) { this.cmdin = cmdin; this.cmdout = cmdout; this.cmderr = cmderr; this.console = console; - this.userin = userin; + this.userin = new InputStream() { + @Override + public int read() throws IOException { + return input.readUserInput(); + } + }; this.userout = userout; this.usererr = usererr; this.prefs = prefs; @@ -450,7 +454,7 @@ */ public static void main(String[] args) throws Exception { new JShellTool(System.in, System.out, System.err, System.out, - new ByteArrayInputStream(new byte[0]), System.out, System.err, + System.out, System.err, Preferences.userRoot().node("tool/JShell"), Locale.getDefault()) .start(args); @@ -2566,6 +2570,11 @@ public void close() { scannerIn.close(); } + + @Override + public int readUserInput() { + return -1; + } } class FileScannerIOContext extends ScannerIOContext { @@ -2604,4 +2613,9 @@ @Override public void close() { } + + @Override + public int readUserInput() { + return -1; + } } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/DemultiplexInput.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/DemultiplexInput.java --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/DemultiplexInput.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/DemultiplexInput.java @@ -40,15 +40,14 @@ class DemultiplexInput extends Thread { private final DataInputStream delegate; - private final PipeInputStream command; private final Map io; + private final Iterable closeList; - DemultiplexInput(InputStream input, PipeInputStream command, - Map io) { + DemultiplexInput(InputStream input, Map io, Iterable closeList) { super("output reader"); this.delegate = new DataInputStream(input); - this.command = command; this.io = io; + this.closeList = closeList; } @Override @@ -65,23 +64,23 @@ byte[] data = new byte[dataLen]; DemultiplexInput.this.delegate.readFully(data); String chan = new String(name, "UTF-8"); - if (chan.equals("command")) { - for (byte b : data) { - command.write(Byte.toUnsignedInt(b)); - } + OutputStream out = io.get(chan); + if (out == null) { + debug("Unexpected channel name: %s", chan); } else { - OutputStream out = io.get(chan); - if (out == null) { - debug("Unexpected channel name: %s", chan); - } else { - out.write(data); - } + out.write(data); } } } catch (IOException ex) { debug(ex, "Failed reading output"); } finally { - command.close(); + for (OutputStream out : closeList) { + try { + out.close(); + } catch (IOException ex) { + debug(ex, "Failed reading output"); + } + } } } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java @@ -25,9 +25,9 @@ package jdk.jshell.execution; import java.io.IOException; +import java.io.InputStream; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; @@ -48,7 +48,7 @@ import com.sun.jdi.VirtualMachine; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionEnv; -import static jdk.jshell.execution.Util.remoteInput; +import static jdk.jshell.execution.Util.remoteInputOutput; /** * The implementation of {@link jdk.jshell.spi.ExecutionControl} that the @@ -103,7 +103,7 @@ * @return the channel * @throws IOException if there are errors in set-up */ - private static JDIDefaultExecutionControl create(ExecutionEnv env, boolean isLaunch) throws IOException { + private static ExecutionControl create(ExecutionEnv env, boolean isLaunch) throws IOException { try (final ServerSocket listener = new ServerSocket(0)) { // timeout after 60 seconds listener.setSoTimeout(60000); @@ -115,10 +115,6 @@ VirtualMachine vm = jdii.vm(); Process process = jdii.process(); - // Forward input to the remote agent - Util.forwardInputToRemote(env.userIn(), process.getOutputStream(), - ex -> debug(ex, "input forwarding failure")); - List> deathListeners = new ArrayList<>(); deathListeners.add(s -> env.closeDown()); Util.detectJDIExitEvent(vm, s -> { @@ -131,12 +127,13 @@ // output. Socket socket = listener.accept(); // out before in -- match remote creation so we don't hang - ObjectOutput cmdout = new ObjectOutputStream(socket.getOutputStream()); - Map io = new HashMap<>(); - io.put("out", env.userOut()); - io.put("err", env.userErr()); - ObjectInput cmdin = remoteInput(socket.getInputStream(), io); - return new JDIDefaultExecutionControl(cmdout, cmdin, vm, process, deathListeners); + OutputStream out = socket.getOutputStream(); + Map outputs = new HashMap<>(); + outputs.put("out", env.userOut()); + outputs.put("err", env.userErr()); + Map input = new HashMap<>(); + input.put("in", env.userIn()); + return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new JDIDefaultExecutionControl(objOut, objIn, vm, process, deathListeners)); } } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/MultiplexingOutputStream.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/MultiplexingOutputStream.java --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/MultiplexingOutputStream.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/MultiplexingOutputStream.java @@ -51,10 +51,12 @@ @Override public void write(int b) throws IOException { synchronized (delegate) { - delegate.write(name.length); //assuming the len is small enough to fit into byte - delegate.write(name); - delegate.write(1); - delegate.write(b); + byte[] data = new byte[name.length + 1 + 1 + 1]; + data[0] = (byte) name.length; //assuming the len is small enough to fit into byte + System.arraycopy(name, 0, data, 1, name.length); + data[name.length + 1] = 1; + data[name.length + 2] = (byte) b; + delegate.write(data); delegate.flush(); } } @@ -65,10 +67,12 @@ int i = 0; while (len > 0) { int size = Math.min(PACKET_SIZE, len); - delegate.write(name.length); //assuming the len is small enough to fit into byte - delegate.write(name); - delegate.write(size); - delegate.write(b, off + i, size); + byte[] data = new byte[name.length + 1 + size + 1]; + data[0] = (byte) name.length; //assuming the len is small enough to fit into byte + System.arraycopy(name, 0, data, 1, name.length); + data[name.length + 1] = (byte) size; + System.arraycopy(b, off + i, data, name.length + 2, size); + delegate.write(data); i += size; len -= size; } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/PipeInputStream.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/PipeInputStream.java --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/PipeInputStream.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/PipeInputStream.java @@ -24,7 +24,9 @@ */ package jdk.jshell.execution; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; /** * @@ -39,7 +41,10 @@ private boolean closed; @Override - public synchronized int read() { + public synchronized int read() throws IOException { + if (start == end) { + inputNeeded(); + } while (start == end) { if (closed) { return -1; @@ -57,7 +62,9 @@ } } - public synchronized void write(int b) { + protected void inputNeeded() throws IOException {} + + private synchronized void write(int b) { if (closed) { throw new IllegalStateException("Already closed."); } @@ -85,4 +92,22 @@ notifyAll(); } + public OutputStream createOutput() { + return new OutputStream() { + @Override public void write(int b) throws IOException { + PipeInputStream.this.write(b); + } + @Override + public void write(byte[] b, int off, int len) throws IOException { + for (int i = 0 ; i < len ; i++) { + write(Byte.toUnsignedInt(b[off + i])); + } + } + @Override + public void close() throws IOException { + PipeInputStream.this.close(); + } + }; + } + } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java @@ -61,10 +61,12 @@ Socket socket = new Socket(loopBack, Integer.parseInt(args[0])); InputStream inStream = socket.getInputStream(); OutputStream outStream = socket.getOutputStream(); - Map> chans = new HashMap<>(); - chans.put("out", st -> System.setOut(new PrintStream(st, true))); - chans.put("err", st -> System.setErr(new PrintStream(st, true))); - forwardExecutionControlAndIO(new RemoteExecutionControl(), inStream, outStream, chans); + Map> outputs = new HashMap<>(); + outputs.put("out", st -> System.setOut(new PrintStream(st, true))); + outputs.put("err", st -> System.setErr(new PrintStream(st, true))); + Map> input = new HashMap<>(); + input.put("in", st -> System.setIn(st)); + forwardExecutionControlAndIO(new RemoteExecutionControl(), inStream, outStream, outputs, input); } // These three variables are used by the main JShell process in interrupting diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java @@ -25,6 +25,7 @@ package jdk.jshell.execution; import jdk.jshell.spi.ExecutionEnv; + import java.io.IOException; import java.io.InputStream; import java.io.ObjectInput; @@ -32,9 +33,13 @@ import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; +import java.util.Arrays; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.function.BiFunction; import java.util.function.Consumer; + import com.sun.jdi.VirtualMachine; import jdk.jshell.spi.ExecutionControl; @@ -99,21 +104,40 @@ * instance, then responses back on the output. * @param ec the direct instance of {@link ExecutionControl} to process commands * @param inStream the stream from which to create the command input - * @param outStream the stream that will carry {@code System.out}, - * {@code System.err}, any specified auxiliary channels, and the - * command response output. - * @param streamMap a map between names of additional streams to carry and setters - * for the stream + * @param outStream the stream that will carry any specified auxiliary channels (like + * {@code System.out} and {@code System.err}), and the command response output. + * @param outputStreamMap a map between names of additional streams to carry and setters + * for the stream. Names starting with '$' are reserved for internal use. + * @param inputStreamMap a map between names of additional streams to carry and setters + * for the stream. Names starting with '$' are reserved for internal use. * @throws IOException if there are errors using the passed streams */ public static void forwardExecutionControlAndIO(ExecutionControl ec, InputStream inStream, OutputStream outStream, - Map> streamMap) throws IOException { - ObjectInputStream cmdIn = new ObjectInputStream(inStream); - for (Entry> e : streamMap.entrySet()) { + Map> outputStreamMap, + Map> inputStreamMap) throws IOException { + for (Entry> e : outputStreamMap.entrySet()) { e.getValue().accept(multiplexingOutputStream(e.getKey(), outStream)); } - ObjectOutputStream cmdOut = new ObjectOutputStream(multiplexingOutputStream("command", outStream)); + + ObjectOutputStream cmdOut = new ObjectOutputStream(multiplexingOutputStream("$command", outStream)); + PipeInputStream cmdInPipe = new PipeInputStream(); + Map inputs = new HashMap<>(); + inputs.put("$command", cmdInPipe.createOutput()); + for (Entry> e : inputStreamMap.entrySet()) { + OutputStream inputSignal = multiplexingOutputStream("$" + e.getKey() + "-input-requested", outStream); + PipeInputStream inputPipe = new PipeInputStream() { + @Override protected void inputNeeded() throws IOException { + inputSignal.write('1'); + inputSignal.flush(); + } + }; + inputs.put(e.getKey(), inputPipe.createOutput()); + e.getValue().accept(inputPipe); + } + new DemultiplexInput(inStream, inputs, inputs.values()).start(); + ObjectInputStream cmdIn = new ObjectInputStream(cmdInPipe); + forwardExecutionControl(ec, cmdIn, cmdOut); } @@ -122,18 +146,41 @@ } /** - * Reads from an InputStream which has been packetized and write its contents - * to the out and err OutputStreams; Copies the command stream. + * Creates an ExecutionControl for given packetized input and output. The given InputStream + * is de-packetized, and content forwarded to ObjectInput and given OutputStreams. The ObjectOutput + * and values read from the given InputStream are packetized and sent to the given OutputStream. + * * @param input the packetized input stream - * @param streamMap a map between stream names and the output streams to forward - * @return the command stream + * @param output the packetized output stream + * @param outputStreamMap a map between stream names and the output streams to forward. + * Names starting with '$' are reserved for internal use. + * @param inputStreamMap a map between stream names and the input streams to forward. + * Names starting with '$' are reserved for internal use. + * @param factory to create the ExecutionControl from ObjectInput and ObjectOutput. + * @return the created ExecutionControl * @throws IOException if setting up the streams raised an exception */ - public static ObjectInput remoteInput(InputStream input, - Map streamMap) throws IOException { + public static ExecutionControl remoteInputOutput(InputStream input, OutputStream output, + Map outputStreamMap, Map inputStreamMap, + BiFunction factory) throws IOException { + Map augmentedStreamMap = new HashMap<>(outputStreamMap); + ObjectOutput commandOut = new ObjectOutputStream(Util.multiplexingOutputStream("$command", output)); + for (Entry e : inputStreamMap.entrySet()) { + InputStream in = e.getValue(); + OutputStream inTarget = Util.multiplexingOutputStream(e.getKey(), output); + augmentedStreamMap.put("$" + e.getKey() + "-input-requested", new OutputStream() { + @Override + public void write(int b) throws IOException { + //value ignored, just a trigger to read from the input + inTarget.write(in.read()); + } + }); + } PipeInputStream commandIn = new PipeInputStream(); - new DemultiplexInput(input, commandIn, streamMap).start(); - return new ObjectInputStream(commandIn); + OutputStream commandInTarget = commandIn.createOutput(); + augmentedStreamMap.put("$command", commandInTarget); + new DemultiplexInput(input, augmentedStreamMap, Arrays.asList(commandInTarget)).start(); + return factory.apply(new ObjectInputStream(commandIn), commandOut); } /** @@ -151,32 +198,4 @@ } } - /** - * Creates a Thread that will ship all input to the remote agent. - * - * @param inputStream the user input - * @param outStream the input to the remote agent - * @param handler a failure handler - */ - public static void forwardInputToRemote(final InputStream inputStream, - final OutputStream outStream, final Consumer handler) { - Thread thr = new Thread("input reader") { - @Override - public void run() { - try { - byte[] buf = new byte[256]; - int cnt; - while ((cnt = inputStream.read(buf)) != -1) { - outStream.write(buf, 0, cnt); - outStream.flush(); - } - } catch (Exception ex) { - handler.accept(ex); - } - } - }; - thr.setPriority(Thread.MAX_PRIORITY - 1); - thr.start(); - } - } diff --git a/test/jdk/jshell/ReplToolTesting.java b/test/jdk/jshell/ReplToolTesting.java --- a/test/jdk/jshell/ReplToolTesting.java +++ b/test/jdk/jshell/ReplToolTesting.java @@ -247,7 +247,6 @@ new PrintStream(cmdout), new PrintStream(cmderr), new PrintStream(console), - userin, new PrintStream(userout), new PrintStream(usererr), prefs, @@ -463,7 +462,7 @@ private List computeCompletions(String code, boolean isSmart) { JShellTool js = this.repl != null ? this.repl - : new JShellTool(null, null, null, null, null, null, null, prefs, Locale.ROOT); + : new JShellTool(null, null, null, null, null, null, prefs, Locale.ROOT); int cursor = code.indexOf('|'); code = code.replace("|", ""); assertTrue(cursor > -1, "'|' not found: " + code); diff --git a/test/jdk/jshell/StartOptionTest.java b/test/jdk/jshell/StartOptionTest.java --- a/test/jdk/jshell/StartOptionTest.java +++ b/test/jdk/jshell/StartOptionTest.java @@ -63,7 +63,6 @@ new PrintStream(cmdout), new PrintStream(cmderr), new PrintStream(console), - new TestingInputStream(), new PrintStream(userout), new PrintStream(usererr), new ReplToolTesting.MemoryPreferences(), diff --git a/test/jdk/jshell/UserInputTest.java b/test/jdk/jshell/UserInputTest.java new file mode 100644 --- /dev/null +++ b/test/jdk/jshell/UserInputTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, 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. + * + * 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. + */ + +/* + * @test + * @bug 8131023 + * @summary Verify that the user's code can read System.in + * @build KullaTesting TestingInputStream + * @run testng UserInputTest + */ + +import org.testng.annotations.Test; + +@Test +public class UserInputTest extends KullaTesting { + + public void testReadInput() { + setInput("AB\n"); + assertEval("System.in.read()", "65"); + setInput("BC\n"); + assertEval("System.in.read()", "66"); + } + +} diff --git a/test/jdk/jshell/UserJDIUserRemoteTest.java b/test/jdk/jshell/UserJDIUserRemoteTest.java --- a/test/jdk/jshell/UserJDIUserRemoteTest.java +++ b/test/jdk/jshell/UserJDIUserRemoteTest.java @@ -37,7 +37,6 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.util.ArrayList; import java.util.List; @@ -62,7 +61,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; import static jdk.jshell.execution.Util.forwardExecutionControlAndIO; -import static jdk.jshell.execution.Util.remoteInput; +import static jdk.jshell.execution.Util.remoteInputOutput; @Test public class UserJDIUserRemoteTest extends ExecutionControlTestBase { @@ -146,7 +145,7 @@ * @return the channel * @throws IOException if there are errors in set-up */ - static MyExecutionControl make(ExecutionEnv env, UserJDIUserRemoteTest test) throws IOException { + static ExecutionControl make(ExecutionEnv env, UserJDIUserRemoteTest test) throws IOException { try (final ServerSocket listener = new ServerSocket(0)) { // timeout after 60 seconds listener.setSoTimeout(60000); @@ -175,13 +174,14 @@ // output. Socket socket = listener.accept(); // out before in -- match remote creation so we don't hang - ObjectOutput cmdout = new ObjectOutputStream(socket.getOutputStream()); - Map io = new HashMap<>(); - io.put("out", env.userOut()); - io.put("err", env.userErr()); - io.put("aux", test.auxStream); - ObjectInput cmdin = remoteInput(socket.getInputStream(), io); - MyExecutionControl myec = new MyExecutionControl(cmdout, cmdin, vm, process, deathListeners); + OutputStream out = socket.getOutputStream(); + Map outputs = new HashMap<>(); + outputs.put("out", env.userOut()); + outputs.put("err", env.userErr()); + outputs.put("aux", test.auxStream); + Map input = new HashMap<>(); + input.put("in", env.userIn()); + ExecutionControl myec = remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new MyExecutionControl(objOut, objIn, vm, process, deathListeners)); test.currentEC = myec; return myec; } @@ -255,11 +255,13 @@ Socket socket = new Socket(loopBack, Integer.parseInt(args[0])); InputStream inStream = socket.getInputStream(); OutputStream outStream = socket.getOutputStream(); - Map> chans = new HashMap<>(); - chans.put("out", st -> System.setOut(new PrintStream(st, true))); - chans.put("err", st -> System.setErr(new PrintStream(st, true))); - chans.put("aux", st -> { auxPrint = new PrintStream(st, true); }); - forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, chans); + Map> outputs = new HashMap<>(); + outputs.put("out", st -> System.setOut(new PrintStream(st, true))); + outputs.put("err", st -> System.setErr(new PrintStream(st, true))); + outputs.put("aux", st -> { auxPrint = new PrintStream(st, true); }); + Map> input = new HashMap<>(); + input.put("in", st -> System.setIn(st)); + forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, outputs, input); } catch (Throwable ex) { throw ex; }