langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java
author rfield
Sun, 06 Nov 2016 22:50:46 -0800
changeset 41941 a935ac3f5274
parent 41628 664e7664343d
child 42969 a48d4f74d322
permissions -rw-r--r--
8161983: JShell API: Clean-up following 8160127 et. al. Reviewed-by: jlahoda
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     1
/*
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     2
 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     4
 *
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    10
 *
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    15
 * accompanied this code).
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    16
 *
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    20
 *
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    23
 * questions.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    24
 */
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    25
package jdk.jshell.execution;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    26
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    27
import jdk.jshell.spi.ExecutionEnv;
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
    28
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    29
import java.io.IOException;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    30
import java.io.InputStream;
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
    31
import java.io.InterruptedIOException;
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    32
import java.io.ObjectInput;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    33
import java.io.ObjectInputStream;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    34
import java.io.ObjectOutput;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    35
import java.io.ObjectOutputStream;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    36
import java.io.OutputStream;
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
    37
import java.util.Arrays;
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
    38
import java.util.HashMap;
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    39
import java.util.Map;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    40
import java.util.Map.Entry;
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
    41
import java.util.function.BiFunction;
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    42
import java.util.function.Consumer;
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
    43
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    44
import com.sun.jdi.VirtualMachine;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    45
import jdk.jshell.spi.ExecutionControl;
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
    46
import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    47
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    48
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    49
/**
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    50
 * Miscellaneous utility methods for setting-up implementations of
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    51
 * {@link ExecutionControl}. Particularly implementations with remote
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    52
 * execution.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    53
 *
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    54
 * @author Jan Lahoda
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    55
 * @author Robert Field
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    56
 */
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    57
public class Util {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    58
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
    59
    private static final int TAG_DATA = 0;
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
    60
    private static final int TAG_CLOSED = 1;
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
    61
    private static final int TAG_EXCEPTION = 2;
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
    62
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    63
    // never instanciated
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    64
    private Util() {}
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    65
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    66
    /**
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    67
     * Create a composite {@link ExecutionControl.Generator} instance that, when
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    68
     * generating, will try each specified generator until successfully creating
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    69
     * an {@link ExecutionControl} instance, or, if all fail, will re-throw the
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    70
     * first exception.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    71
     *
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    72
     * @param gec0 the first instance to try
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    73
     * @param gecs the second through Nth instance to try
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    74
     * @return the fail-over generator
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    75
     */
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    76
    public static ExecutionControl.Generator failOverExecutionControlGenerator(
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    77
            ExecutionControl.Generator gec0, ExecutionControl.Generator... gecs) {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    78
        return (ExecutionEnv env) -> {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    79
            Throwable thrown;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    80
            try {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    81
                return gec0.generate(env);
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    82
            } catch (Throwable ex) {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    83
                thrown = ex;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    84
            }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    85
            for (ExecutionControl.Generator gec : gecs) {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    86
                try {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    87
                    return gec.generate(env);
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    88
                } catch (Throwable ignore) {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    89
                    // only care about the first, and only if they all fail
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    90
                }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    91
            }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    92
            throw thrown;
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    93
        };
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    94
    }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    95
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    96
    /**
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    97
     * Forward commands from the input to the specified {@link ExecutionControl}
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    98
     * instance, then responses back on the output.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
    99
     * @param ec the direct instance of {@link ExecutionControl} to process commands
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   100
     * @param in the command input
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   101
     * @param out the command response output
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   102
     */
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   103
    public static void forwardExecutionControl(ExecutionControl ec,
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   104
            ObjectInput in, ObjectOutput out) {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   105
        new ExecutionControlForwarder(ec, in, out).commandLoop();
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   106
    }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   107
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   108
    /**
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   109
     * Forward commands from the input to the specified {@link ExecutionControl}
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   110
     * instance, then responses back on the output.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   111
     * @param ec the direct instance of {@link ExecutionControl} to process commands
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   112
     * @param inStream the stream from which to create the command input
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   113
     * @param outStream the stream that will carry any specified auxiliary channels (like
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   114
     *                  {@code System.out} and {@code System.err}), and the command response output.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   115
     * @param outputStreamMap a map between names of additional streams to carry and setters
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   116
     *                        for the stream. Names starting with '$' are reserved for internal use.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   117
     * @param inputStreamMap a map between names of additional streams to carry and setters
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   118
     *                       for the stream. Names starting with '$' are reserved for internal use.
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   119
     * @throws IOException if there are errors using the passed streams
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   120
     */
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   121
    public static void forwardExecutionControlAndIO(ExecutionControl ec,
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   122
            InputStream inStream, OutputStream outStream,
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   123
            Map<String, Consumer<OutputStream>> outputStreamMap,
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   124
            Map<String, Consumer<InputStream>> inputStreamMap) throws IOException {
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   125
        for (Entry<String, Consumer<OutputStream>> e : outputStreamMap.entrySet()) {
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   126
            e.getValue().accept(multiplexingOutputStream(e.getKey(), outStream));
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   127
        }
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   128
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   129
        ObjectOutputStream cmdOut = new ObjectOutputStream(multiplexingOutputStream("$command", outStream));
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   130
        PipeInputStream cmdInPipe = new PipeInputStream();
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   131
        Map<String, OutputStream> inputs = new HashMap<>();
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   132
        inputs.put("$command", cmdInPipe.createOutput());
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   133
        for (Entry<String, Consumer<InputStream>> e : inputStreamMap.entrySet()) {
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   134
            OutputStream inputSignal = multiplexingOutputStream("$" + e.getKey() + "-input-requested", outStream);
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   135
            PipeInputStream inputPipe = new PipeInputStream() {
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   136
                @Override protected void inputNeeded() throws IOException {
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   137
                    inputSignal.write('1');
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   138
                    inputSignal.flush();
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   139
                }
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   140
                @Override
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   141
                public synchronized int read() throws IOException {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   142
                    int tag = super.read();
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   143
                    switch (tag) {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   144
                        case TAG_DATA: return super.read();
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   145
                        case TAG_CLOSED: close(); return -1;
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   146
                        case TAG_EXCEPTION:
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   147
                            int len = (super.read() << 0) + (super.read() << 8) + (super.read() << 16) + (super.read() << 24);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   148
                            byte[] message = new byte[len];
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   149
                            for (int i = 0; i < len; i++) {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   150
                                message[i] = (byte) super.read();
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   151
                            }
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   152
                            throw new IOException(new String(message, "UTF-8"));
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   153
                        case -1:
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   154
                            return -1;
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   155
                        default:
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   156
                            throw new IOException("Internal error: unrecognized message tag: " + tag);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   157
                    }
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   158
                }
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   159
            };
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   160
            inputs.put(e.getKey(), inputPipe.createOutput());
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   161
            e.getValue().accept(inputPipe);
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   162
        }
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   163
        new DemultiplexInput(inStream, inputs, inputs.values()).start();
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   164
        ObjectInputStream cmdIn = new ObjectInputStream(cmdInPipe);
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   165
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   166
        forwardExecutionControl(ec, cmdIn, cmdOut);
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   167
    }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   168
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   169
    static OutputStream multiplexingOutputStream(String label, OutputStream outputStream) {
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   170
        return new MultiplexingOutputStream(label, outputStream);
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   171
    }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   172
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   173
    /**
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   174
     * Creates an ExecutionControl for given packetized input and output. The given InputStream
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   175
     * is de-packetized, and content forwarded to ObjectInput and given OutputStreams. The ObjectOutput
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   176
     * and values read from the given InputStream are packetized and sent to the given OutputStream.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   177
     *
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   178
     * @param input the packetized input stream
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   179
     * @param output the packetized output stream
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   180
     * @param outputStreamMap a map between stream names and the output streams to forward.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   181
     *                        Names starting with '$' are reserved for internal use.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   182
     * @param inputStreamMap a map between stream names and the input streams to forward.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   183
     *                       Names starting with '$' are reserved for internal use.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   184
     * @param factory to create the ExecutionControl from ObjectInput and ObjectOutput.
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   185
     * @return the created ExecutionControl
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   186
     * @throws IOException if setting up the streams raised an exception
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   187
     */
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   188
    public static ExecutionControl remoteInputOutput(InputStream input, OutputStream output,
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   189
            Map<String, OutputStream> outputStreamMap, Map<String, InputStream> inputStreamMap,
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   190
            BiFunction<ObjectInput, ObjectOutput, ExecutionControl> factory) throws IOException {
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   191
        ExecutionControl[] result = new ExecutionControl[1];
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   192
        Map<String, OutputStream> augmentedStreamMap = new HashMap<>(outputStreamMap);
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   193
        ObjectOutput commandOut = new ObjectOutputStream(Util.multiplexingOutputStream("$command", output));
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   194
        for (Entry<String, InputStream> e : inputStreamMap.entrySet()) {
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   195
            InputStream  in = e.getValue();
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   196
            OutputStream inTarget = Util.multiplexingOutputStream(e.getKey(), output);
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   197
            augmentedStreamMap.put("$" + e.getKey() + "-input-requested", new OutputStream() {
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   198
                @Override
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   199
                public void write(int b) throws IOException {
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   200
                    //value ignored, just a trigger to read from the input
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   201
                    try {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   202
                        int r = in.read();
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   203
                        if (r == (-1)) {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   204
                            inTarget.write(TAG_CLOSED);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   205
                        } else {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   206
                            inTarget.write(new byte[] {TAG_DATA, (byte) r});
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   207
                        }
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   208
                    } catch (InterruptedIOException exc) {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   209
                        try {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   210
                            result[0].stop();
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   211
                        } catch (ExecutionControlException ex) {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   212
                            debug(ex, "$" + e.getKey() + "-input-requested.write");
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   213
                        }
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   214
                    } catch (IOException exc) {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   215
                        byte[] message = exc.getMessage().getBytes("UTF-8");
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   216
                        inTarget.write(TAG_EXCEPTION);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   217
                        inTarget.write((message.length >>  0) & 0xFF);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   218
                        inTarget.write((message.length >>  8) & 0xFF);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   219
                        inTarget.write((message.length >> 16) & 0xFF);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   220
                        inTarget.write((message.length >> 24) & 0xFF);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   221
                        inTarget.write(message);
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   222
                    }
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   223
                }
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   224
            });
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   225
        }
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   226
        PipeInputStream commandIn = new PipeInputStream();
40767
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   227
        OutputStream commandInTarget = commandIn.createOutput();
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   228
        augmentedStreamMap.put("$command", commandInTarget);
c7908e8c786b 8131023: JShell: System.in does not work
jlahoda
parents: 39807
diff changeset
   229
        new DemultiplexInput(input, augmentedStreamMap, Arrays.asList(commandInTarget)).start();
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   230
        return result[0] = factory.apply(new ObjectInputStream(commandIn), commandOut);
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   231
    }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   232
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   233
    /**
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   234
     * Monitor the JDI event stream for {@link com.sun.jdi.event.VMDeathEvent}
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   235
     * and {@link com.sun.jdi.event.VMDisconnectEvent}. If encountered, invokes
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   236
     * {@code unbiddenExitHandler}.
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   237
     *
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   238
     * @param vm the virtual machine to check
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   239
     * @param unbiddenExitHandler the handler, which will accept the exit
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   240
     * information
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   241
     */
41941
a935ac3f5274 8161983: JShell API: Clean-up following 8160127 et. al.
rfield
parents: 41628
diff changeset
   242
    public static void detectJdiExitEvent(VirtualMachine vm, Consumer<String> unbiddenExitHandler) {
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   243
        if (vm.canBeModified()) {
41941
a935ac3f5274 8161983: JShell API: Clean-up following 8160127 et. al.
rfield
parents: 41628
diff changeset
   244
            new JdiEventHandler(vm, unbiddenExitHandler).start();
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   245
        }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   246
    }
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   247
41628
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   248
    /**
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   249
     * Log a serious unexpected internal exception.
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   250
     *
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   251
     * @param ex the exception
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   252
     * @param where a description of the context of the exception
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   253
     */
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   254
    private static void debug(Throwable ex, String where) {
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   255
        // Reserved for future logging
664e7664343d 8167461: jshell tool: Scanner#next() hangs tool
jlahoda
parents: 40767
diff changeset
   256
    }
39807
ba0ff343d241 8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
diff changeset
   257
}