mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-18 22:35:12 +00:00
Merge
This commit is contained in:
commit
bc5b401e00
@ -197,6 +197,7 @@ public class JShellTool implements MessageHandler {
|
||||
public boolean testPrompt = false;
|
||||
private String cmdlineClasspath = null;
|
||||
private String startup = null;
|
||||
private String executionControlSpec = null;
|
||||
private EditorSetting editor = BUILT_IN_EDITOR;
|
||||
|
||||
private static final String[] EDITOR_ENV_VARS = new String[] {
|
||||
@ -546,6 +547,7 @@ public class JShellTool implements MessageHandler {
|
||||
OptionSpec<String> st = parser.accepts("startup").withRequiredArg();
|
||||
parser.acceptsAll(asList("n", "no-startup"));
|
||||
OptionSpec<String> fb = parser.accepts("feedback").withRequiredArg();
|
||||
OptionSpec<String> ec = parser.accepts("execution").withRequiredArg();
|
||||
parser.accepts("q");
|
||||
parser.accepts("s");
|
||||
parser.accepts("v");
|
||||
@ -648,6 +650,9 @@ public class JShellTool implements MessageHandler {
|
||||
remoteVMOptions.add("--add-modules");
|
||||
remoteVMOptions.addAll(options.valuesOf(amods));
|
||||
}
|
||||
if (options.has(ec)) {
|
||||
executionControlSpec = options.valueOf(ec);
|
||||
}
|
||||
|
||||
if (options.has(addExports)) {
|
||||
List<String> exports = options.valuesOf(addExports).stream()
|
||||
@ -718,18 +723,21 @@ public class JShellTool implements MessageHandler {
|
||||
// Reset the replayable history, saving the old for restore
|
||||
replayableHistoryPrevious = replayableHistory;
|
||||
replayableHistory = new ArrayList<>();
|
||||
|
||||
state = JShell.builder()
|
||||
JShell.Builder builder =
|
||||
JShell.builder()
|
||||
.in(userin)
|
||||
.out(userout)
|
||||
.err(usererr)
|
||||
.tempVariableNameGenerator(()-> "$" + currentNameSpace.tidNext())
|
||||
.tempVariableNameGenerator(() -> "$" + currentNameSpace.tidNext())
|
||||
.idGenerator((sn, i) -> (currentNameSpace == startNamespace || state.status(sn).isActive())
|
||||
? currentNameSpace.tid(sn)
|
||||
: errorNamespace.tid(sn))
|
||||
.remoteVMOptions(remoteVMOptions.stream().toArray(String[]::new))
|
||||
.compilerOptions(compilerOptions.stream().toArray(String[]::new))
|
||||
.build();
|
||||
.compilerOptions(compilerOptions.stream().toArray(String[]::new));
|
||||
if (executionControlSpec != null) {
|
||||
builder.executionEngine(executionControlSpec);
|
||||
}
|
||||
state = builder.build();
|
||||
shutdownSubscription = state.onShutdown((JShell deadState) -> {
|
||||
if (deadState == state) {
|
||||
hardmsg("jshell.msg.terminated");
|
||||
|
||||
@ -169,12 +169,12 @@ where possible options include:\n\
|
||||
\ --module-path <path> Specify where to find application modules\n\
|
||||
\ --add-modules <module>(,<module>)*\n\
|
||||
\ Specify modules to resolve, or all modules on the\n\
|
||||
\ module path if <module> is ALL-MODULE-PATHs\n\
|
||||
\ module path if <module> is ALL-MODULE-PATHs\n\
|
||||
\ --startup <file> One run replacement for the start-up definitions\n\
|
||||
\ --no-startup Do not run the start-up definitions\n\
|
||||
\ --feedback <mode> Specify the initial feedback mode. The mode may be\n\
|
||||
\ predefined (silent, concise, normal, or verbose) or\n\
|
||||
\ previously user-defined\n\
|
||||
\ predefined (silent, concise, normal, or verbose) or\n\
|
||||
\ previously user-defined\n\
|
||||
\ -q Quiet feedback. Same as: --feedback concise\n\
|
||||
\ -s Really quiet feedback. Same as: --feedback silent\n\
|
||||
\ -v Verbose feedback. Same as: --feedback verbose\n\
|
||||
@ -189,6 +189,10 @@ where possible options include:\n\
|
||||
\ -X Print help on non-standard options\n
|
||||
help.usage.x = \
|
||||
\ --add-exports <module>/<package> Export specified module-private package to snippets\n\
|
||||
\ --execution <spec> Specify an alternate execution engine.\n\
|
||||
\ Where <spec> is an ExecutionControl spec.\n\
|
||||
\ See the documentation of the package\n\
|
||||
\ jdk.jshell.spi for the syntax of the spec\n\
|
||||
\ \n\
|
||||
\These options are non-standard and subject to change without notice.\n
|
||||
|
||||
|
||||
@ -48,11 +48,10 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.jshell.debug.InternalDebugControl;
|
||||
import jdk.jshell.Snippet.Status;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
|
||||
import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
|
||||
import static jdk.jshell.Util.expunge;
|
||||
|
||||
/**
|
||||
@ -116,15 +115,20 @@ public class JShell implements AutoCloseable {
|
||||
this.idGenerator = b.idGenerator;
|
||||
this.extraRemoteVMOptions = b.extraRemoteVMOptions;
|
||||
this.extraCompilerOptions = b.extraCompilerOptions;
|
||||
ExecutionControl.Generator executionControlGenerator = b.executionControlGenerator==null
|
||||
? failOverExecutionControlGenerator(
|
||||
JdiDefaultExecutionControl.listen(InetAddress.getLoopbackAddress().getHostAddress()),
|
||||
JdiDefaultExecutionControl.launch(),
|
||||
JdiDefaultExecutionControl.listen(null)
|
||||
)
|
||||
: b.executionControlGenerator;
|
||||
try {
|
||||
executionControl = executionControlGenerator.generate(new ExecutionEnvImpl());
|
||||
if (b.executionControlProvider != null) {
|
||||
executionControl = b.executionControlProvider.generate(new ExecutionEnvImpl(),
|
||||
b.executionControlParameters == null
|
||||
? b.executionControlProvider.defaultParameters()
|
||||
: b.executionControlParameters);
|
||||
} else {
|
||||
String loopback = InetAddress.getLoopbackAddress().getHostAddress();
|
||||
String spec = b.executionControlSpec == null
|
||||
? "failover:0(jdi:hostname(" + loopback + ")),"
|
||||
+ "1(jdi:launch(true)), 2(jdi)"
|
||||
: b.executionControlSpec;
|
||||
executionControl = ExecutionControl.generate(new ExecutionEnvImpl(), spec);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
throw new IllegalStateException("Launching JShell execution engine threw: " + ex.getMessage(), ex);
|
||||
}
|
||||
@ -164,7 +168,9 @@ public class JShell implements AutoCloseable {
|
||||
BiFunction<Snippet, Integer, String> idGenerator = null;
|
||||
List<String> extraRemoteVMOptions = new ArrayList<>();
|
||||
List<String> extraCompilerOptions = new ArrayList<>();
|
||||
ExecutionControl.Generator executionControlGenerator;
|
||||
ExecutionControlProvider executionControlProvider;
|
||||
Map<String,String> executionControlParameters;
|
||||
String executionControlSpec;
|
||||
|
||||
Builder() { }
|
||||
|
||||
@ -322,14 +328,39 @@ public class JShell implements AutoCloseable {
|
||||
|
||||
/**
|
||||
* Sets the custom engine for execution. Snippet execution will be
|
||||
* provided by the specified {@link ExecutionControl} instance.
|
||||
* provided by the {@link ExecutionControl} instance selected by the
|
||||
* specified execution control spec.
|
||||
* Use, at most, one of these overloaded {@code executionEngine} builder
|
||||
* methods.
|
||||
*
|
||||
* @param executionControlGenerator the execution engine generator
|
||||
* @param executionControlSpec the execution control spec,
|
||||
* which is documented in the {@link jdk.jshell.spi}
|
||||
* package documentation.
|
||||
* @return the {@code Builder} instance (for use in chained
|
||||
* initialization)
|
||||
*/
|
||||
public Builder executionEngine(ExecutionControl.Generator executionControlGenerator) {
|
||||
this.executionControlGenerator = executionControlGenerator;
|
||||
public Builder executionEngine(String executionControlSpec) {
|
||||
this.executionControlSpec = executionControlSpec;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom engine for execution. Snippet execution will be
|
||||
* provided by the specified {@link ExecutionControl} instance.
|
||||
* Use, at most, one of these overloaded {@code executionEngine} builder
|
||||
* methods.
|
||||
*
|
||||
* @param executionControlProvider the provider to supply the execution
|
||||
* engine
|
||||
* @param executionControlParameters the parameters to the provider, or
|
||||
* {@code null} for default parameters
|
||||
* @return the {@code Builder} instance (for use in chained
|
||||
* initialization)
|
||||
*/
|
||||
public Builder executionEngine(ExecutionControlProvider executionControlProvider,
|
||||
Map<String,String> executionControlParameters) {
|
||||
this.executionControlProvider = executionControlProvider;
|
||||
this.executionControlParameters = executionControlParameters;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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. 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.jshell.execution;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
|
||||
/**
|
||||
* Tries other providers in sequence until one works.
|
||||
*/
|
||||
public class FailOverExecutionControlProvider implements ExecutionControlProvider{
|
||||
|
||||
private Logger logger = null;
|
||||
|
||||
/**
|
||||
* Create an instance. The instance can be used to start and return an
|
||||
* {@link ExecutionControl} instance by attempting to start a series of
|
||||
* {@code ExecutionControl} specs, until one is successful.
|
||||
*
|
||||
* @see #generate(jdk.jshell.spi.ExecutionEnv, java.util.Map)
|
||||
*/
|
||||
public FailOverExecutionControlProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique name of this {@code ExecutionControlProvider}.
|
||||
*
|
||||
* @return "failover"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "failover";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return the default parameter map for this
|
||||
* {@code ExecutionControlProvider}. There are ten parameters, "0" through
|
||||
* "9", their values are {@code ExecutionControlProvider} specification
|
||||
* strings, or empty string.
|
||||
*
|
||||
* @return a default parameter map
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> defaultParameters() {
|
||||
Map<String, String> dp = new HashMap<>();
|
||||
dp.put("0", "jdi");
|
||||
for (int i = 1; i <= 9; ++i) {
|
||||
dp.put("" + i, "");
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a locally executing {@code ExecutionControl} instance.
|
||||
* At least one parameter should have a spec.
|
||||
*
|
||||
* @param env the execution environment, provided by JShell
|
||||
* @param parameters the modified parameter map.
|
||||
* @return the execution engine
|
||||
* @throws Throwable if all the given providers fail, the exception that
|
||||
* occurred on the first attempt to create the execution engine.
|
||||
*/
|
||||
@Override
|
||||
public ExecutionControl generate(ExecutionEnv env, Map<String, String> parameters)
|
||||
throws Throwable {
|
||||
Throwable thrown = null;
|
||||
for (int i = 0; i <= 9; ++i) {
|
||||
String param = parameters.get("" + i);
|
||||
if (param != null && !param.isEmpty()) {
|
||||
try {
|
||||
ExecutionControl ec = ExecutionControl.generate(env, param);
|
||||
logger().finest(
|
||||
String.format("FailOverExecutionControlProvider: Success %s -- %d = %s\n",
|
||||
name(), i, param));
|
||||
return ec;
|
||||
} catch (Throwable ex) {
|
||||
logger().warning(
|
||||
String.format("FailOverExecutionControlProvider: Failure %s -- %d = %s -- %s\n",
|
||||
name(), i, param, ex.toString()));
|
||||
StringWriter writer = new StringWriter();
|
||||
PrintWriter log = new PrintWriter(writer);
|
||||
log.println("FailOverExecutionControlProvider:");
|
||||
ex.printStackTrace(log);
|
||||
logger().fine(log.toString());
|
||||
// only care about the first, and only if they all fail
|
||||
if (thrown == null) {
|
||||
thrown = ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
logger().severe("FailOverExecutionControlProvider: Terminating, failovers exhausted");
|
||||
if (thrown == null) {
|
||||
throw new IllegalArgumentException("All least one parameter must be set to a provider.");
|
||||
}
|
||||
throw thrown;
|
||||
}
|
||||
|
||||
private Logger logger() {
|
||||
if (logger == null) {
|
||||
logger = Logger.getLogger("jdk.jshell.execution");
|
||||
logger.setLevel(Level.ALL);
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
}
|
||||
@ -63,75 +63,13 @@ import static jdk.jshell.execution.Util.remoteInputOutput;
|
||||
*/
|
||||
public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
|
||||
/**
|
||||
* Default time-out expressed in milliseconds.
|
||||
*/
|
||||
private static final int DEFAULT_TIMEOUT = 5000;
|
||||
|
||||
private VirtualMachine vm;
|
||||
private Process process;
|
||||
private final String remoteAgent;
|
||||
|
||||
private final Object STOP_LOCK = new Object();
|
||||
private boolean userCodeRunning = false;
|
||||
|
||||
/**
|
||||
* Creates an ExecutionControl instance based on a JDI
|
||||
* {@code LaunchingConnector}. Same as
|
||||
* {@code JdiDefaultExecutionControl.create(defaultRemoteAgent(), true, null, defaultTimeout())}.
|
||||
*
|
||||
* @return the generator
|
||||
*/
|
||||
public static ExecutionControl.Generator launch() {
|
||||
return create(defaultRemoteAgent(), true, null, defaultTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExecutionControl instance based on a JDI
|
||||
* {@code ListeningConnector}. Same as
|
||||
* {@code JdiDefaultExecutionControl.create(defaultRemoteAgent(), false, host, defaultTimeout())}.
|
||||
*
|
||||
* @param host explicit hostname to use, if null use discovered
|
||||
* hostname, applies to listening only (!isLaunch)
|
||||
* @return the generator
|
||||
*/
|
||||
public static ExecutionControl.Generator listen(String host) {
|
||||
return create(defaultRemoteAgent(), false, host, defaultTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JDI based ExecutionControl instance.
|
||||
*
|
||||
* @param remoteAgent the remote agent to launch
|
||||
* @param isLaunch does JDI do the launch? That is, LaunchingConnector,
|
||||
* otherwise we start explicitly and use ListeningConnector
|
||||
* @param host explicit hostname to use, if null use discovered
|
||||
* hostname, applies to listening only (!isLaunch)
|
||||
* @param timeout the start-up time-out in milliseconds
|
||||
* @return the generator
|
||||
*/
|
||||
public static ExecutionControl.Generator create(String remoteAgent,
|
||||
boolean isLaunch, String host, int timeout) {
|
||||
return env -> create(env, remoteAgent, isLaunch, host, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default remote agent.
|
||||
*
|
||||
* @return the name of the standard remote agent
|
||||
*/
|
||||
public static String defaultRemoteAgent() {
|
||||
return RemoteExecutionControl.class.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default remote connection time-out
|
||||
*
|
||||
* @return time to wait for connection before failing, expressed in milliseconds.
|
||||
*/
|
||||
public static int defaultTimeout() {
|
||||
return DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExecutionControl instance based on a JDI
|
||||
* {@code ListeningConnector} or {@code LaunchingConnector}.
|
||||
@ -150,7 +88,7 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
* @return the channel
|
||||
* @throws IOException if there are errors in set-up
|
||||
*/
|
||||
private static ExecutionControl create(ExecutionEnv env, String remoteAgent,
|
||||
static ExecutionControl create(ExecutionEnv env, String remoteAgent,
|
||||
boolean isLaunch, String host, int timeout) throws IOException {
|
||||
try (final ServerSocket listener = new ServerSocket(0, 1, InetAddress.getLoopbackAddress())) {
|
||||
// timeout on I/O-socket
|
||||
@ -181,7 +119,8 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
outputs.put("err", env.userErr());
|
||||
Map<String, InputStream> input = new HashMap<>();
|
||||
input.put("in", env.userIn());
|
||||
return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new JdiDefaultExecutionControl(objOut, objIn, vm, process, deathListeners));
|
||||
return remoteInputOutput(socket.getInputStream(), out, outputs, input,
|
||||
(objIn, objOut) -> new JdiDefaultExecutionControl(objOut, objIn, vm, process, remoteAgent, deathListeners));
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,10 +131,12 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
* @param cmdin the input for responses
|
||||
*/
|
||||
private JdiDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin,
|
||||
VirtualMachine vm, Process process, List<Consumer<String>> deathListeners) {
|
||||
VirtualMachine vm, Process process, String remoteAgent,
|
||||
List<Consumer<String>> deathListeners) {
|
||||
super(cmdout, cmdin);
|
||||
this.vm = vm;
|
||||
this.process = process;
|
||||
this.remoteAgent = remoteAgent;
|
||||
deathListeners.add(s -> disposeVM());
|
||||
}
|
||||
|
||||
@ -237,7 +178,7 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
|
||||
for (ThreadReference thread : vm().allThreads()) {
|
||||
// could also tag the thread (e.g. using name), to find it easier
|
||||
for (StackFrame frame : thread.frames()) {
|
||||
if (defaultRemoteAgent().equals(frame.location().declaringType().name()) &&
|
||||
if (remoteAgent.equals(frame.location().declaringType().name()) &&
|
||||
( "invoke".equals(frame.location().method().name())
|
||||
|| "varValue".equals(frame.location().method().name()))) {
|
||||
ObjectReference thiz = frame.thisObject();
|
||||
|
||||
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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. 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.jshell.execution;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
|
||||
/**
|
||||
* A provider of remote JDI-controlled execution engines.
|
||||
* @author Robert Field
|
||||
*/
|
||||
public class JdiExecutionControlProvider implements ExecutionControlProvider {
|
||||
|
||||
/**
|
||||
* The remote agent to launch.
|
||||
*/
|
||||
public static final String PARAM_REMOTE_AGENT = "remoteAgent";
|
||||
|
||||
/**
|
||||
* Milliseconds before connect timeout.
|
||||
*/
|
||||
public static final String PARAM_TIMEOUT = "timeout";
|
||||
|
||||
/**
|
||||
* The local hostname to connect to.
|
||||
*/
|
||||
public static final String PARAM_HOST_NAME = "hostname";
|
||||
|
||||
/**
|
||||
* Should JDI-controlled launching be used?
|
||||
*/
|
||||
public static final String PARAM_LAUNCH = "launch";
|
||||
|
||||
/**
|
||||
* Default time-out expressed in milliseconds.
|
||||
*/
|
||||
private static final int DEFAULT_TIMEOUT = 5000;
|
||||
|
||||
/**
|
||||
* Create an instance. An instance can be used to
|
||||
* {@linkplain #generate generate} an {@link ExecutionControl} instance
|
||||
* that uses the Java Debug Interface as part of the control of a remote
|
||||
* process.
|
||||
*/
|
||||
public JdiExecutionControlProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique name of this {@code ExecutionControlProvider}.
|
||||
*
|
||||
* @return "jdi"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "jdi";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return the default parameter map for this
|
||||
* {@code ExecutionControlProvider}. The map can optionally be modified;
|
||||
* Modified or unmodified it can be passed to
|
||||
* {@link #generate(jdk.jshell.spi.ExecutionEnv, java.util.Map) }.
|
||||
* <table summary="Parameters">
|
||||
* <tr>
|
||||
* <th>Parameter</th>
|
||||
* <th>Description</th>
|
||||
* <th>Constant Field</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>remoteAgent</td>
|
||||
* <td>the remote agent to launch</td>
|
||||
* <td>{@link #PARAM_REMOTE_AGENT}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>timeout</td>
|
||||
* <td>milliseconds before connect timeout</td>
|
||||
* <td>{@link #PARAM_TIMEOUT}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>launch</td>
|
||||
* <td>"true" for JDI controlled launch</td>
|
||||
* <td>{@link #PARAM_LAUNCH}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>hostname</td>
|
||||
* <td>connect to the named of the local host ("" for discovered)</td>
|
||||
* <td>{@link #PARAM_HOST_NAME}</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @return the default parameter map
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> defaultParameters() {
|
||||
Map<String, String> dp = new HashMap<>();
|
||||
dp.put(PARAM_REMOTE_AGENT, RemoteExecutionControl.class.getName());
|
||||
dp.put(PARAM_TIMEOUT, "" + DEFAULT_TIMEOUT);
|
||||
dp.put(PARAM_HOST_NAME, "");
|
||||
dp.put(PARAM_LAUNCH, "false");
|
||||
return dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionControl generate(ExecutionEnv env, Map<String, String> parameters)
|
||||
throws IOException {
|
||||
Map<String, String> dp = defaultParameters();
|
||||
if (parameters == null) {
|
||||
parameters = dp;
|
||||
}
|
||||
String remoteAgent = parameters.getOrDefault(PARAM_REMOTE_AGENT, dp.get(PARAM_REMOTE_AGENT));
|
||||
int timeout = Integer.parseUnsignedInt(
|
||||
parameters.getOrDefault(PARAM_TIMEOUT, dp.get(PARAM_TIMEOUT)));
|
||||
String host = parameters.getOrDefault(PARAM_HOST_NAME, dp.get(PARAM_HOST_NAME));
|
||||
String sIsLaunch = parameters.getOrDefault(PARAM_LAUNCH, dp.get(PARAM_LAUNCH)).toLowerCase(Locale.ROOT);
|
||||
boolean isLaunch = sIsLaunch.length() > 0
|
||||
&& ("true".startsWith(sIsLaunch) || "yes".startsWith(sIsLaunch));
|
||||
return JdiDefaultExecutionControl.create(env, remoteAgent, isLaunch, host, timeout);
|
||||
}
|
||||
|
||||
}
|
||||
@ -27,7 +27,6 @@ package jdk.jshell.execution;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
|
||||
/**
|
||||
* An implementation of {@link jdk.jshell.spi.ExecutionControl} which executes
|
||||
@ -41,15 +40,6 @@ public class LocalExecutionControl extends DirectExecutionControl {
|
||||
private boolean userCodeRunning = false;
|
||||
private ThreadGroup execThreadGroup;
|
||||
|
||||
/**
|
||||
* Creates a local ExecutionControl instance.
|
||||
*
|
||||
* @return the generator
|
||||
*/
|
||||
public static ExecutionControl.Generator create() {
|
||||
return env -> new LocalExecutionControl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance, delegating loader operations to the specified
|
||||
* delegate.
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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. 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.jshell.execution;
|
||||
|
||||
import java.util.Map;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
|
||||
/**
|
||||
* A provider of execution engines which run in the same process as JShell.
|
||||
* @author Robert Field
|
||||
*/
|
||||
public class LocalExecutionControlProvider implements ExecutionControlProvider{
|
||||
|
||||
/**
|
||||
* Create an instance. An instance can be used to
|
||||
* {@linkplain #generate generate} an {@link ExecutionControl} instance
|
||||
* that executes code in the same process.
|
||||
*/
|
||||
public LocalExecutionControlProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique name of this {@code ExecutionControlProvider}.
|
||||
*
|
||||
* @return "local"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "local";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return the default parameter map for
|
||||
* {@code LocalExecutionControlProvider}.
|
||||
* {@code LocalExecutionControlProvider} has no parameters.
|
||||
*
|
||||
* @return an empty parameter map
|
||||
*/
|
||||
@Override
|
||||
public Map<String,String> defaultParameters() {
|
||||
return ExecutionControlProvider.super.defaultParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a locally executing {@code ExecutionControl} instance.
|
||||
*
|
||||
* @param env the execution environment, provided by JShell
|
||||
* @param parameters the {@linkplain #defaultParameters() default} or
|
||||
* modified parameter map.
|
||||
* @return the execution engine
|
||||
*/
|
||||
@Override
|
||||
public ExecutionControl generate(ExecutionEnv env, Map<String, String> parameters) {
|
||||
return new LocalExecutionControl();
|
||||
}
|
||||
|
||||
}
|
||||
@ -63,36 +63,6 @@ public class Util {
|
||||
// never instanciated
|
||||
private Util() {}
|
||||
|
||||
/**
|
||||
* Create a composite {@link ExecutionControl.Generator} instance that, when
|
||||
* generating, will try each specified generator until successfully creating
|
||||
* an {@link ExecutionControl} instance, or, if all fail, will re-throw the
|
||||
* first exception.
|
||||
*
|
||||
* @param gec0 the first instance to try
|
||||
* @param gecs the second through Nth instance to try
|
||||
* @return the fail-over generator
|
||||
*/
|
||||
public static ExecutionControl.Generator failOverExecutionControlGenerator(
|
||||
ExecutionControl.Generator gec0, ExecutionControl.Generator... gecs) {
|
||||
return (ExecutionEnv env) -> {
|
||||
Throwable thrown;
|
||||
try {
|
||||
return gec0.generate(env);
|
||||
} catch (Throwable ex) {
|
||||
thrown = ex;
|
||||
}
|
||||
for (ExecutionControl.Generator gec : gecs) {
|
||||
try {
|
||||
return gec.generate(env);
|
||||
} catch (Throwable ignore) {
|
||||
// only care about the first, and only if they all fail
|
||||
}
|
||||
}
|
||||
throw thrown;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward commands from the input to the specified {@link ExecutionControl}
|
||||
* instance, then responses back on the output.
|
||||
|
||||
@ -25,6 +25,11 @@
|
||||
package jdk.jshell.spi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This interface specifies the functionality that must provided to implement a
|
||||
@ -40,30 +45,9 @@ import java.io.Serializable;
|
||||
* <p>
|
||||
* Methods defined in this interface should only be called by the core JShell
|
||||
* implementation.
|
||||
* <p>
|
||||
* To install an {@code ExecutionControl}, its {@code Generator} is passed to
|
||||
* {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator) }.
|
||||
*/
|
||||
public interface ExecutionControl extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Defines a functional interface for creating {@link ExecutionControl}
|
||||
* instances.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Generator {
|
||||
|
||||
/**
|
||||
* Generates an execution engine, given an execution environment.
|
||||
*
|
||||
* @param env the context in which the {@link ExecutionControl} is to
|
||||
* be created
|
||||
* @return the created instance
|
||||
* @throws Throwable if problems occurred
|
||||
*/
|
||||
ExecutionControl generate(ExecutionEnv env) throws Throwable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to load new classes.
|
||||
*
|
||||
@ -176,8 +160,150 @@ public interface ExecutionControl extends AutoCloseable {
|
||||
* <p>
|
||||
* No calls to methods on this interface should be made after close.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Search for a provider, then create and return the
|
||||
* {@code ExecutionControl} instance.
|
||||
*
|
||||
* @param env the execution environment (provided by JShell)
|
||||
* @param name the name of provider
|
||||
* @param parameters the parameter map.
|
||||
* @return the execution engine
|
||||
* @throws Throwable an exception that occurred attempting to find or create
|
||||
* the execution engine.
|
||||
* @throws IllegalArgumentException if no ExecutionControlProvider has the
|
||||
* specified {@code name} and {@code parameters}.
|
||||
*/
|
||||
static ExecutionControl generate(ExecutionEnv env, String name, Map<String, String> parameters)
|
||||
throws Throwable {
|
||||
Set<String> keys = parameters == null
|
||||
? Collections.emptySet()
|
||||
: parameters.keySet();
|
||||
for (ExecutionControlProvider p : ServiceLoader.load(ExecutionControlProvider.class)) {
|
||||
if (p.name().equals(name)
|
||||
&& p.defaultParameters().keySet().containsAll(keys)) {
|
||||
return p.generate(env, parameters);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No ExecutionControlProvider with name '"
|
||||
+ name + "' and parameter keys: " + keys.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a provider, then create and return the
|
||||
* {@code ExecutionControl} instance.
|
||||
*
|
||||
* @param env the execution environment (provided by JShell)
|
||||
* @param spec the {@code ExecutionControl} spec, which is described in
|
||||
* the documentation of this
|
||||
* {@linkplain jdk.jshell.spi package documentation}.
|
||||
* @return the execution engine
|
||||
* @throws Throwable an exception that occurred attempting to find or create
|
||||
* the execution engine.
|
||||
* @throws IllegalArgumentException if no ExecutionControlProvider has the
|
||||
* specified {@code name} and {@code parameters}.
|
||||
* @throws IllegalArgumentException if {@code spec} is malformed
|
||||
*/
|
||||
static ExecutionControl generate(ExecutionEnv env, String spec)
|
||||
throws Throwable {
|
||||
class SpecReader {
|
||||
|
||||
int len = spec.length();
|
||||
int i = -1;
|
||||
|
||||
char ch;
|
||||
|
||||
SpecReader() {
|
||||
next();
|
||||
}
|
||||
|
||||
boolean more() {
|
||||
return i < len;
|
||||
}
|
||||
|
||||
char current() {
|
||||
return ch;
|
||||
}
|
||||
|
||||
final boolean next() {
|
||||
++i;
|
||||
if (i < len) {
|
||||
ch = spec.charAt(i);
|
||||
return true;
|
||||
}
|
||||
i = len;
|
||||
return false;
|
||||
}
|
||||
|
||||
void skipWhite() {
|
||||
while (more() && Character.isWhitespace(ch)) {
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
String readId() {
|
||||
skipWhite();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (more() && Character.isJavaIdentifierPart(ch)) {
|
||||
sb.append(ch);
|
||||
next();
|
||||
}
|
||||
skipWhite();
|
||||
String id = sb.toString();
|
||||
if (id.isEmpty()) {
|
||||
throw new IllegalArgumentException("Expected identifier in " + spec);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void expect(char exp) {
|
||||
skipWhite();
|
||||
if (!more() || ch != exp) {
|
||||
throw new IllegalArgumentException("Expected '" + exp + "' in " + spec);
|
||||
}
|
||||
next();
|
||||
skipWhite();
|
||||
}
|
||||
|
||||
String readValue() {
|
||||
expect('(');
|
||||
int parenDepth = 1;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (more()) {
|
||||
if (ch == ')') {
|
||||
--parenDepth;
|
||||
if (parenDepth == 0) {
|
||||
break;
|
||||
}
|
||||
} else if (ch == '(') {
|
||||
++parenDepth;
|
||||
}
|
||||
sb.append(ch);
|
||||
next();
|
||||
}
|
||||
expect(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
SpecReader sr = new SpecReader();
|
||||
String name = sr.readId();
|
||||
if (sr.more()) {
|
||||
sr.expect(':');
|
||||
while (sr.more()) {
|
||||
String key = sr.readId();
|
||||
String value = sr.readValue();
|
||||
parameters.put(key, value);
|
||||
if (sr.more()) {
|
||||
sr.expect(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
return generate(env, name, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bundles class name with class bytecodes.
|
||||
*/
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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. 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.jshell.spi;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The provider used by JShell to generate the execution engine needed to
|
||||
* evaluate Snippets. Alternate execution engines can be created by
|
||||
* implementing this interface, then configuring JShell with the provider or
|
||||
* the providers name and parameter specifier.
|
||||
* @author Robert Field
|
||||
*/
|
||||
public interface ExecutionControlProvider {
|
||||
|
||||
/**
|
||||
* The unique name of this {@code ExecutionControlProvider}. The name must
|
||||
* be a sequence of characters from the Basic Multilingual Plane which are
|
||||
* {@link Character#isJavaIdentifierPart(char) }.
|
||||
*
|
||||
* @return the ExecutionControlProvider's name
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Create and return the default parameter map for this
|
||||
* {@code ExecutionControlProvider}. The map can optionally be modified;
|
||||
* Modified or unmodified it can be passed to
|
||||
* {@link #generate(jdk.jshell.spi.ExecutionEnv, java.util.Map) }.
|
||||
*
|
||||
* @return the default parameter map
|
||||
*/
|
||||
default Map<String,String> defaultParameters() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return the {@code ExecutionControl} instance.
|
||||
*
|
||||
* @param env the execution environment, provided by JShell
|
||||
* @param parameters the {@linkplain #defaultParameters() default} or
|
||||
* modified parameter map.
|
||||
* @return the execution engine
|
||||
* @throws Throwable an exception that occurred attempting to create the
|
||||
* execution engine.
|
||||
*/
|
||||
ExecutionControl generate(ExecutionEnv env, Map<String,String> parameters)
|
||||
throws Throwable;
|
||||
}
|
||||
@ -28,7 +28,6 @@ package jdk.jshell.spi;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
import jdk.jshell.JShell;
|
||||
|
||||
/**
|
||||
* Functionality made available to a pluggable JShell execution engine. It is
|
||||
|
||||
@ -30,9 +30,41 @@
|
||||
* and in the case of executable Snippets, execution. The JShell
|
||||
* implementation includes a default execution engine (currently a remote
|
||||
* process which is JDI controlled). By implementing the
|
||||
* {@link jdk.jshell.spi.ExecutionControl} interface and installing it with
|
||||
* {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl.Generator) }
|
||||
* other execution engines can be used.
|
||||
* {@link jdk.jshell.spi.ExecutionControl} interface and its generating class,
|
||||
* an implementation of the {@link jdk.jshell.spi.ExecutionControlProvider}
|
||||
* interface, and installing it with
|
||||
* {@link jdk.jshell.JShell.Builder#executionEngine(String)}
|
||||
* other execution engines can be used. Where the passed String is an
|
||||
* {@code ExecutionControl} spec.
|
||||
* <p>
|
||||
* The {@code ExecutionControl} spec is the {@code ExecutionControlProvider}
|
||||
* name optionally followed by a parameter specification.
|
||||
* The syntax of the spec is:
|
||||
* <pre>
|
||||
* spec := name : params
|
||||
* | name
|
||||
* name := identifier
|
||||
* params := param , params
|
||||
* | param
|
||||
* |
|
||||
* param := identifier ( value )
|
||||
* </pre>
|
||||
* Where 'name' is the {@code ExecutionControlProvider}
|
||||
* {@linkplain ExecutionControlProvider#name() name}.
|
||||
* Where 'param' is a Map key from
|
||||
* {@link ExecutionControlProvider#defaultParameters()} and the parenthesized
|
||||
* value; See, for example,
|
||||
* {@link jdk.jshell.execution.JdiExecutionControlProvider}.
|
||||
* Where 'identifier' is a sequence of
|
||||
* {@linkplain java.lang.Character#isJavaIdentifierPart(char)
|
||||
* Java identifier part characters} from the Basic Multilingual Plane.
|
||||
* <p>
|
||||
* For example:
|
||||
* <ul>
|
||||
* <li>local</li>
|
||||
* <li>jdi:hostname(localhost)</li>
|
||||
* <li>failover:1(jdi),2(jdi:launch(true),timeout(3000)),3(local)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see jdk.jshell.execution for execution implementation support
|
||||
*/
|
||||
|
||||
@ -56,6 +56,7 @@ module jdk.jshell {
|
||||
requires transitive java.compiler;
|
||||
requires transitive jdk.jdi;
|
||||
requires transitive java.prefs;
|
||||
requires java.logging;
|
||||
requires jdk.compiler;
|
||||
requires jdk.internal.le;
|
||||
requires jdk.internal.ed;
|
||||
@ -66,7 +67,14 @@ module jdk.jshell {
|
||||
exports jdk.jshell.execution;
|
||||
exports jdk.jshell.tool;
|
||||
|
||||
uses jdk.jshell.spi.ExecutionControlProvider;
|
||||
uses jdk.internal.editor.spi.BuildInEditorProvider;
|
||||
|
||||
provides javax.tools.Tool with jdk.internal.jshell.tool.JShellToolProvider;
|
||||
provides jdk.jshell.spi.ExecutionControlProvider
|
||||
with jdk.jshell.execution.JdiExecutionControlProvider;
|
||||
provides jdk.jshell.spi.ExecutionControlProvider
|
||||
with jdk.jshell.execution.LocalExecutionControlProvider;
|
||||
provides jdk.jshell.spi.ExecutionControlProvider
|
||||
with jdk.jshell.execution.FailOverExecutionControlProvider;
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ EXIT = exit
|
||||
EXIT_IF_FATAL = status=$$?; if [ $$status -ge $(1) ]; then exit $$status ; fi
|
||||
|
||||
# Root of all test results
|
||||
TEST_OUTPUT_DIR = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)/test/langtools
|
||||
TEST_OUTPUT_DIR ?= $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)/test/langtools
|
||||
ABS_TEST_OUTPUT_DIR := \
|
||||
$(shell mkdir -p $(TEST_OUTPUT_DIR); \
|
||||
cd $(TEST_OUTPUT_DIR); \
|
||||
|
||||
96
langtools/test/jdk/jshell/BadExecutionControlSpecTest.java
Normal file
96
langtools/test/jdk/jshell/BadExecutionControlSpecTest.java
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 8168615
|
||||
* @summary Test bad input to ExecutionControl.generate
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
* jdk.jshell/jdk.internal.jshell.tool
|
||||
* @run testng BadExecutionControlSpecTest
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.testng.annotations.Test;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@Test
|
||||
public class BadExecutionControlSpecTest {
|
||||
private static void assertIllegal(String spec) throws Throwable {
|
||||
try {
|
||||
ExecutionEnv env = new ExecutionEnv() {
|
||||
@Override
|
||||
public InputStream userIn() {
|
||||
return new ByteArrayInputStream(new byte[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintStream userOut() {
|
||||
return new PrintStream(new ByteArrayOutputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintStream userErr() {
|
||||
return new PrintStream(new ByteArrayOutputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> extraRemoteVMOptions() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeDown() {
|
||||
}
|
||||
|
||||
};
|
||||
ExecutionControl.generate(env, spec);
|
||||
fail("Expected exception -- " + spec);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// The expected happened
|
||||
}
|
||||
}
|
||||
|
||||
public void syntaxTest() throws Throwable {
|
||||
assertIllegal(":launch(true)");
|
||||
assertIllegal("jdi:launch(true");
|
||||
assertIllegal("jdi:launch(true)$");
|
||||
assertIllegal("jdi:,");
|
||||
}
|
||||
|
||||
public void notFoundTest() throws Throwable {
|
||||
assertIllegal("fruitbats");
|
||||
assertIllegal("jdi:baz(true)");
|
||||
assertIllegal("random:launch(true)");
|
||||
assertIllegal("jdi:,");
|
||||
}
|
||||
}
|
||||
@ -21,10 +21,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.util.Map;
|
||||
import jdk.jshell.JShell;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import jdk.jshell.execution.JdiExecutionControlProvider;
|
||||
import jdk.jshell.execution.RemoteExecutionControl;
|
||||
import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
|
||||
class DyingRemoteAgent extends RemoteExecutionControl {
|
||||
|
||||
@ -39,11 +40,13 @@ class DyingRemoteAgent extends RemoteExecutionControl {
|
||||
}
|
||||
|
||||
static JShell state(boolean isLaunch, String host) {
|
||||
return JShell.builder().executionEngine(
|
||||
JdiDefaultExecutionControl.create(
|
||||
DyingRemoteAgent.class.getName(),
|
||||
isLaunch,
|
||||
host,
|
||||
defaultTimeout())).build();
|
||||
ExecutionControlProvider ecp = new JdiExecutionControlProvider();
|
||||
Map<String,String> pm = ecp.defaultParameters();
|
||||
pm.put(JdiExecutionControlProvider.PARAM_REMOTE_AGENT, DyingRemoteAgent.class.getName());
|
||||
pm.put(JdiExecutionControlProvider.PARAM_HOST_NAME, host==null? "" : host);
|
||||
pm.put(JdiExecutionControlProvider.PARAM_LAUNCH, ""+isLaunch);
|
||||
return JShell.builder()
|
||||
.executionEngine(ecp, pm)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
101
langtools/test/jdk/jshell/ExecutionControlSpecTest.java
Normal file
101
langtools/test/jdk/jshell/ExecutionControlSpecTest.java
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 8168615
|
||||
* @summary Test ExecutionControlProvider specs can load user ExecutionControlProviders
|
||||
* with direct maps.
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
* jdk.jshell/jdk.jshell.execution
|
||||
* jdk.jshell/jdk.jshell.spi
|
||||
* @library /tools/lib
|
||||
* @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask
|
||||
* @build KullaTesting Compiler
|
||||
* @run testng ExecutionControlSpecTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
|
||||
public class ExecutionControlSpecTest extends KullaTesting {
|
||||
|
||||
ClassLoader ccl;
|
||||
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
String mod = "my.ec";
|
||||
String pkg = "package my.ec;\n";
|
||||
Compiler compiler = new Compiler();
|
||||
Path modDir = Paths.get("mod");
|
||||
compiler.compile(modDir,
|
||||
pkg +
|
||||
"public class PrefixingExecutionControl extends jdk.jshell.execution.LocalExecutionControl {\n" +
|
||||
" @Override\n" +
|
||||
" public String invoke(String className, String methodName)\n" +
|
||||
" throws RunException, InternalException, EngineTerminationException {\n" +
|
||||
" return \"Blah:\" + super.invoke(className, methodName);\n" +
|
||||
" }\n" +
|
||||
"}\n",
|
||||
pkg +
|
||||
"public class PrefixingExecutionControlProvider implements jdk.jshell.spi.ExecutionControlProvider {\n" +
|
||||
" @Override\n" +
|
||||
" public String name() {\n" +
|
||||
" return \"prefixing\";\n" +
|
||||
" }\n" +
|
||||
" @Override\n" +
|
||||
" public jdk.jshell.spi.ExecutionControl generate(jdk.jshell.spi.ExecutionEnv env,\n" +
|
||||
" java.util.Map<String, String> parameters) {\n" +
|
||||
" return new PrefixingExecutionControl();\n" +
|
||||
" }\n" +
|
||||
"}\n",
|
||||
"module my.ec {\n" +
|
||||
" requires transitive jdk.jshell;\n" +
|
||||
" provides jdk.jshell.spi.ExecutionControlProvider\n" +
|
||||
" with my.ec.PrefixingExecutionControlProvider;\n" +
|
||||
" }");
|
||||
Path modPath = compiler.getPath(modDir);
|
||||
ccl = createAndRunFromModule(mod, modPath);
|
||||
|
||||
setUp(builder -> builder.executionEngine("prefixing"));
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
@Override
|
||||
public void tearDown() {
|
||||
super.tearDown();
|
||||
Thread.currentThread().setContextClassLoader(ccl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefix() {
|
||||
assertEval("43;", "Blah:43");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 8168615
|
||||
* @summary Test that fail-over works for fail-over ExecutionControlProvider
|
||||
* with direct maps.
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
* jdk.jshell/jdk.jshell.execution
|
||||
* jdk.jshell/jdk.jshell.spi
|
||||
* @library /tools/lib
|
||||
* @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask
|
||||
* @build KullaTesting ExecutionControlTestBase Compiler
|
||||
* @run testng FailOverDirectExecutionControlTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.FailOverExecutionControlProvider;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
@Test
|
||||
public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase {
|
||||
|
||||
ClassLoader ccl;
|
||||
ExecutionControlProvider provider;
|
||||
Map<Level, List<String>> logged = new HashMap<>();
|
||||
|
||||
private class LogTestHandler extends Handler {
|
||||
|
||||
LogTestHandler() {
|
||||
setLevel(Level.ALL);
|
||||
setFilter(lr -> lr.getLoggerName().equals("jdk.jshell.execution"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(LogRecord lr) {
|
||||
List<String> l = logged.get(lr.getLevel());
|
||||
if (l == null) {
|
||||
l = new ArrayList<>();
|
||||
logged.put(lr.getLevel(), l);
|
||||
}
|
||||
l.add(lr.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
Logger logger = Logger.getLogger("jdk.jshell.execution");
|
||||
logger.setLevel(Level.ALL);
|
||||
logger.addHandler(new LogTestHandler());
|
||||
Compiler compiler = new Compiler();
|
||||
Path modDir = Paths.get("mod");
|
||||
compiler.compile(modDir,
|
||||
"package my.provide; import java.util.Map;\n" +
|
||||
"import jdk.jshell.spi.ExecutionControl;\n" +
|
||||
"import jdk.jshell.spi.ExecutionControlProvider;\n" +
|
||||
"import jdk.jshell.spi.ExecutionEnv;\n" +
|
||||
"public class AlwaysFailingProvider implements ExecutionControlProvider {\n" +
|
||||
" @Override\n" +
|
||||
" public String name() {\n" +
|
||||
" return \"alwaysFailing\";\n" +
|
||||
" }\n" +
|
||||
" @Override\n" +
|
||||
" public ExecutionControl generate(ExecutionEnv env, Map<String, String> parameters) throws Throwable {\n" +
|
||||
" throw new UnsupportedOperationException(\"This operation intentionally broken.\");\n" +
|
||||
" }\n" +
|
||||
"}\n",
|
||||
"module my.provide {\n" +
|
||||
" requires transitive jdk.jshell;\n" +
|
||||
" provides jdk.jshell.spi.ExecutionControlProvider\n" +
|
||||
" with my.provide.AlwaysFailingProvider;\n" +
|
||||
" }");
|
||||
Path modPath = compiler.getPath(modDir);
|
||||
ccl = createAndRunFromModule("my.provide", modPath);
|
||||
|
||||
provider = new FailOverExecutionControlProvider();
|
||||
Map<String, String> pm = provider.defaultParameters();
|
||||
pm.put("0", "alwaysFailing");
|
||||
pm.put("1", "alwaysFailing");
|
||||
pm.put("2", "jdi");
|
||||
setUp(builder -> builder.executionEngine(provider, pm));
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
@Override
|
||||
public void tearDown() {
|
||||
super.tearDown();
|
||||
Thread.currentThread().setContextClassLoader(ccl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void variables() {
|
||||
super.variables();
|
||||
assertEquals(logged.get(Level.FINEST).size(), 1);
|
||||
assertEquals(logged.get(Level.FINE).size(), 2);
|
||||
assertEquals(logged.get(Level.WARNING).size(), 2);
|
||||
assertNull(logged.get(Level.SEVERE));
|
||||
String log = logged.get(Level.WARNING).get(0);
|
||||
assertTrue(log.contains("Failure failover -- 0 = alwaysFailing"), log);
|
||||
assertTrue(log.contains("This operation intentionally broken"), log);
|
||||
log = logged.get(Level.WARNING).get(1);
|
||||
assertTrue(log.contains("Failure failover -- 1 = alwaysFailing"), log);
|
||||
assertTrue(log.contains("This operation intentionally broken"), log);
|
||||
log = logged.get(Level.FINEST).get(0);
|
||||
assertTrue(log.contains("Success failover -- 2 = jdi"), log);
|
||||
}
|
||||
}
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8131029 8160127 8159935 8169519
|
||||
* @bug 8131029 8160127 8159935 8169519 8168615
|
||||
* @summary Test that fail-over works for fail-over ExecutionControl generators.
|
||||
* @modules jdk.jshell/jdk.jshell.execution
|
||||
* jdk.jshell/jdk.jshell.spi
|
||||
@ -33,9 +33,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
|
||||
import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
|
||||
|
||||
@Test
|
||||
public class FailOverExecutionControlDyingLaunchTest extends ExecutionControlTestBase {
|
||||
@ -43,12 +40,7 @@ public class FailOverExecutionControlDyingLaunchTest extends ExecutionControlTes
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
|
||||
JdiDefaultExecutionControl.create(
|
||||
DyingRemoteAgent.class.getName(),
|
||||
true,
|
||||
null,
|
||||
defaultTimeout()),
|
||||
JdiDefaultExecutionControl.launch())));
|
||||
setUp(builder -> builder.executionEngine(
|
||||
"failover:0(jdi:remoteAgent(DyingRemoteAgent),launch(true)), 4(jdi:launch(true))"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,9 +33,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
|
||||
import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
|
||||
|
||||
@Test
|
||||
public class FailOverExecutionControlHangingLaunchTest extends ExecutionControlTestBase {
|
||||
@ -43,12 +40,7 @@ public class FailOverExecutionControlHangingLaunchTest extends ExecutionControlT
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
|
||||
JdiDefaultExecutionControl.create(
|
||||
HangingRemoteAgent.class.getName(),
|
||||
true,
|
||||
null,
|
||||
defaultTimeout()),
|
||||
JdiDefaultExecutionControl.launch())));
|
||||
setUp(builder -> builder.executionEngine(
|
||||
"failover:0(jdi:remoteAgent(HangingRemoteAgent),launch(true)), 1(jdi:launch(true))"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,9 +34,6 @@
|
||||
import java.net.InetAddress;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import static jdk.jshell.execution.JdiDefaultExecutionControl.defaultTimeout;
|
||||
import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
|
||||
|
||||
@Test
|
||||
public class FailOverExecutionControlHangingListenTest extends ExecutionControlTestBase {
|
||||
@ -45,12 +42,8 @@ public class FailOverExecutionControlHangingListenTest extends ExecutionControlT
|
||||
@Override
|
||||
public void setUp() {
|
||||
String loopback = InetAddress.getLoopbackAddress().getHostAddress();
|
||||
setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
|
||||
JdiDefaultExecutionControl.create(
|
||||
HangingRemoteAgent.class.getName(),
|
||||
false,
|
||||
loopback,
|
||||
defaultTimeout()),
|
||||
JdiDefaultExecutionControl.listen(loopback))));
|
||||
setUp(builder -> builder.executionEngine(
|
||||
"failover:0(jdi:remoteAgent(HangingRemoteAgent),hostname(" + loopback + ")),"
|
||||
+ "1(jdi:hostname(" + loopback + "))"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8131029 8160127 8159935
|
||||
* @bug 8131029 8160127 8159935 8168615
|
||||
* @summary Test that fail-over works for fail-over ExecutionControl generators.
|
||||
* @modules jdk.jshell/jdk.jshell.execution
|
||||
* jdk.jshell/jdk.jshell.spi
|
||||
@ -33,10 +33,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
|
||||
|
||||
@Test
|
||||
public class FailOverExecutionControlTest extends ExecutionControlTestBase {
|
||||
@ -44,18 +40,7 @@ public class FailOverExecutionControlTest extends ExecutionControlTestBase {
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
|
||||
new AlwaysFailingGenerator(),
|
||||
new AlwaysFailingGenerator(),
|
||||
JdiDefaultExecutionControl.launch())));
|
||||
setUp(builder -> builder.executionEngine("failover:0(nonExistent), 1(nonExistent), 2(jdi:launch(true))"));
|
||||
}
|
||||
|
||||
class AlwaysFailingGenerator implements ExecutionControl.Generator {
|
||||
|
||||
@Override
|
||||
public ExecutionControl generate(ExecutionEnv env) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("This operation intentionally broken.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.util.Map;
|
||||
import jdk.jshell.JShell;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import jdk.jshell.execution.JdiExecutionControlProvider;
|
||||
import jdk.jshell.execution.RemoteExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
|
||||
/**
|
||||
* Hang for three minutes (long enough to cause a timeout).
|
||||
@ -51,12 +53,15 @@ class HangingRemoteAgent extends RemoteExecutionControl {
|
||||
}
|
||||
|
||||
static JShell state(boolean isLaunch, String host) {
|
||||
return JShell.builder().executionEngine(
|
||||
JdiDefaultExecutionControl.create(
|
||||
HangingRemoteAgent.class.getName(),
|
||||
isLaunch,
|
||||
host,
|
||||
TIMEOUT)).build();
|
||||
ExecutionControlProvider ecp = new JdiExecutionControlProvider();
|
||||
Map<String,String> pm = ecp.defaultParameters();
|
||||
pm.put(JdiExecutionControlProvider.PARAM_REMOTE_AGENT, HangingRemoteAgent.class.getName());
|
||||
pm.put(JdiExecutionControlProvider.PARAM_HOST_NAME, host==null? "" : host);
|
||||
pm.put(JdiExecutionControlProvider.PARAM_LAUNCH, ""+isLaunch);
|
||||
pm.put(JdiExecutionControlProvider.PARAM_TIMEOUT, ""+TIMEOUT);
|
||||
return JShell.builder()
|
||||
.executionEngine(ecp, pm)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import jdk.jshell.JShell;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@ -44,7 +43,7 @@ public class JdiBadOptionLaunchExecutionControlTest {
|
||||
public void badOptionLaunchTest() {
|
||||
try {
|
||||
JShell.builder()
|
||||
.executionEngine(JdiDefaultExecutionControl.launch())
|
||||
.executionEngine("jdi:launch(true)")
|
||||
.remoteVMOptions("-BadBadOption")
|
||||
.build();
|
||||
} catch (IllegalStateException ex) {
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import jdk.jshell.JShell;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@ -44,7 +43,7 @@ public class JdiBadOptionListenExecutionControlTest {
|
||||
public void badOptionListenTest() {
|
||||
try {
|
||||
JShell.builder()
|
||||
.executionEngine(JdiDefaultExecutionControl.listen(null))
|
||||
.executionEngine("jdi")
|
||||
.remoteVMOptions("-BadBadOption")
|
||||
.build();
|
||||
} catch (IllegalStateException ex) {
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8169519
|
||||
* @bug 8169519 8168615
|
||||
* @summary Tests for JDI connector failure
|
||||
* @modules jdk.jshell/jdk.jshell jdk.jshell/jdk.jshell.spi jdk.jshell/jdk.jshell.execution
|
||||
* @run testng JdiBogusHostListenExecutionControlTest
|
||||
@ -31,7 +31,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import jdk.jshell.JShell;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@ -44,7 +43,7 @@ public class JdiBogusHostListenExecutionControlTest {
|
||||
public void badOptionListenTest() {
|
||||
try {
|
||||
JShell.builder()
|
||||
.executionEngine(JdiDefaultExecutionControl.listen("BattyRumbleBuckets-Snurfle-99-Blip"))
|
||||
.executionEngine("jdi:hostname(BattyRumbleBuckets-Snurfle-99-Blip)")
|
||||
.build();
|
||||
} catch (IllegalStateException ex) {
|
||||
assertTrue(ex.getMessage().startsWith(EXPECTED_ERROR), ex.getMessage());
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8164518
|
||||
* @bug 8164518 8168615
|
||||
* @summary Tests for standard JDI connector (without failover) -- launching
|
||||
* @modules jdk.jshell/jdk.jshell.execution
|
||||
* @build KullaTesting ExecutionControlTestBase
|
||||
@ -33,7 +33,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
|
||||
@Test
|
||||
public class JdiLaunchingExecutionControlTest extends ExecutionControlTestBase {
|
||||
@ -41,6 +40,6 @@ public class JdiLaunchingExecutionControlTest extends ExecutionControlTestBase {
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.launch()));
|
||||
setUp(builder -> builder.executionEngine("jdi:launch(true)"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
|
||||
@Test
|
||||
public class JdiListeningExecutionControlTest extends ExecutionControlTestBase {
|
||||
@ -41,6 +40,6 @@ public class JdiListeningExecutionControlTest extends ExecutionControlTestBase {
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.listen(null)));
|
||||
setUp(builder -> builder.executionEngine("jdi"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.execution.JdiDefaultExecutionControl;
|
||||
|
||||
@Test
|
||||
public class JdiListeningLocalhostExecutionControlTest extends ExecutionControlTestBase {
|
||||
@ -41,6 +40,6 @@ public class JdiListeningLocalhostExecutionControlTest extends ExecutionControlT
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.listen("localhost")));
|
||||
setUp(builder -> builder.executionEngine("jdi:hostname(localhost)"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,10 @@ import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.reflect.Layer;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -209,6 +213,19 @@ public class KullaTesting {
|
||||
classpath = null;
|
||||
}
|
||||
|
||||
public ClassLoader createAndRunFromModule(String moduleName, Path modPath) {
|
||||
ModuleFinder finder = ModuleFinder.of(modPath);
|
||||
Layer parent = Layer.boot();
|
||||
Configuration cf = parent.configuration()
|
||||
.resolveRequires(finder, ModuleFinder.of(), Set.of(moduleName));
|
||||
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||
Layer layer = parent.defineModulesWithOneLoader(cf, scl);
|
||||
ClassLoader loader = layer.findLoader(moduleName);
|
||||
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(loader);
|
||||
return ccl;
|
||||
}
|
||||
|
||||
public List<String> assertUnresolvedDependencies(DeclarationSnippet key, int unresolvedSize) {
|
||||
List<String> unresolved = getState().unresolvedDependencies(key).collect(toList());
|
||||
assertEquals(unresolved.size(), unresolvedSize, "Input: " + key.source() + ", checking unresolved: ");
|
||||
|
||||
160
langtools/test/jdk/jshell/MyExecutionControl.java
Normal file
160
langtools/test/jdk/jshell/MyExecutionControl.java
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import com.sun.jdi.VMDisconnectedException;
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
import jdk.jshell.execution.JdiExecutionControl;
|
||||
import jdk.jshell.execution.JdiInitiator;
|
||||
import jdk.jshell.execution.Util;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
import static org.testng.Assert.fail;
|
||||
import static jdk.jshell.execution.Util.remoteInputOutput;
|
||||
|
||||
class MyExecutionControl extends JdiExecutionControl {
|
||||
|
||||
private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName();
|
||||
private static final int TIMEOUT = 2000;
|
||||
|
||||
private VirtualMachine vm;
|
||||
private Process process;
|
||||
|
||||
/**
|
||||
* Creates an ExecutionControl instance based on a JDI
|
||||
* {@code ListeningConnector} or {@code LaunchingConnector}.
|
||||
*
|
||||
* Initialize JDI and use it to launch the remote JVM. Set-up a socket for
|
||||
* commands and results. This socket also transports the user
|
||||
* input/output/error.
|
||||
*
|
||||
* @param env the context passed by
|
||||
* {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }
|
||||
* @return the channel
|
||||
* @throws IOException if there are errors in set-up
|
||||
*/
|
||||
static ExecutionControl make(ExecutionEnv env, UserJdiUserRemoteTest test) throws IOException {
|
||||
try (final ServerSocket listener = new ServerSocket(0)) {
|
||||
// timeout for socket
|
||||
listener.setSoTimeout(TIMEOUT);
|
||||
int port = listener.getLocalPort();
|
||||
|
||||
// Set-up the JDI connection
|
||||
List<String> opts = new ArrayList<>(env.extraRemoteVMOptions());
|
||||
opts.add("-classpath");
|
||||
opts.add(System.getProperty("java.class.path")
|
||||
+ System.getProperty("path.separator")
|
||||
+ System.getProperty("user.dir"));
|
||||
JdiInitiator jdii = new JdiInitiator(port,
|
||||
opts, REMOTE_AGENT, true, null, TIMEOUT);
|
||||
VirtualMachine vm = jdii.vm();
|
||||
Process process = jdii.process();
|
||||
|
||||
List<Consumer<String>> deathListeners = new ArrayList<>();
|
||||
deathListeners.add(s -> env.closeDown());
|
||||
Util.detectJdiExitEvent(vm, s -> {
|
||||
for (Consumer<String> h : deathListeners) {
|
||||
h.accept(s);
|
||||
}
|
||||
});
|
||||
|
||||
// Set-up the commands/reslts on the socket. Piggy-back snippet
|
||||
// output.
|
||||
Socket socket = listener.accept();
|
||||
// out before in -- match remote creation so we don't hang
|
||||
OutputStream out = socket.getOutputStream();
|
||||
Map<String, OutputStream> outputs = new HashMap<>();
|
||||
outputs.put("out", env.userOut());
|
||||
outputs.put("err", env.userErr());
|
||||
outputs.put("aux", test.auxStream);
|
||||
Map<String, InputStream> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance.
|
||||
*
|
||||
* @param out the output for commands
|
||||
* @param in the input for responses
|
||||
*/
|
||||
private MyExecutionControl(ObjectOutput out, ObjectInput in,
|
||||
VirtualMachine vm, Process process,
|
||||
List<Consumer<String>> deathListeners) {
|
||||
super(out, in);
|
||||
this.vm = vm;
|
||||
this.process = process;
|
||||
deathListeners.add(s -> disposeVM());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
disposeVM();
|
||||
}
|
||||
|
||||
private synchronized void disposeVM() {
|
||||
try {
|
||||
if (vm != null) {
|
||||
vm.dispose(); // This could NPE, so it is caught below
|
||||
vm = null;
|
||||
}
|
||||
} catch (VMDisconnectedException ex) {
|
||||
// Ignore if already closed
|
||||
} catch (Throwable e) {
|
||||
fail("disposeVM threw: " + e);
|
||||
} finally {
|
||||
if (process != null) {
|
||||
process.destroy();
|
||||
process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized VirtualMachine vm() throws EngineTerminationException {
|
||||
if (vm == null) {
|
||||
throw new EngineTerminationException("VM closed");
|
||||
} else {
|
||||
return vm;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
langtools/test/jdk/jshell/MyExecutionControlProvider.java
Normal file
47
langtools/test/jdk/jshell/MyExecutionControlProvider.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.Map;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControlProvider;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
|
||||
public class MyExecutionControlProvider implements ExecutionControlProvider {
|
||||
|
||||
private final UserJdiUserRemoteTest test;
|
||||
|
||||
MyExecutionControlProvider(UserJdiUserRemoteTest test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "my";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionControl generate(ExecutionEnv env, Map<String, String> parameters) throws Throwable {
|
||||
return MyExecutionControl.make(env, test);
|
||||
}
|
||||
|
||||
}
|
||||
87
langtools/test/jdk/jshell/MyRemoteExecutionControl.java
Normal file
87
langtools/test/jdk/jshell/MyRemoteExecutionControl.java
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import jdk.jshell.execution.DirectExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
|
||||
import jdk.jshell.spi.ExecutionControl.InternalException;
|
||||
import jdk.jshell.spi.ExecutionControl.RunException;
|
||||
import static jdk.jshell.execution.Util.forwardExecutionControlAndIO;
|
||||
|
||||
/**
|
||||
* A custom remote agent to verify aux channel and custom ExecutionControl.
|
||||
*/
|
||||
public class MyRemoteExecutionControl extends DirectExecutionControl implements ExecutionControl {
|
||||
|
||||
static PrintStream auxPrint;
|
||||
|
||||
/**
|
||||
* Launch the agent, connecting to the JShell-core over the socket specified
|
||||
* in the command-line argument.
|
||||
*
|
||||
* @param args standard command-line arguments, expectation is the socket
|
||||
* number is the only argument
|
||||
* @throws Exception any unexpected exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
String loopBack = null;
|
||||
Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
|
||||
InputStream inStream = socket.getInputStream();
|
||||
OutputStream outStream = socket.getOutputStream();
|
||||
Map<String, Consumer<OutputStream>> 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<String, Consumer<InputStream>> input = new HashMap<>();
|
||||
input.put("in", st -> System.setIn(st));
|
||||
forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, outputs, input);
|
||||
} catch (Throwable ex) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String varValue(String className, String varName)
|
||||
throws RunException, EngineTerminationException, InternalException {
|
||||
auxPrint.print(varName);
|
||||
return super.varValue(className, varName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object extensionCommand(String className, Object arg)
|
||||
throws RunException, EngineTerminationException, InternalException {
|
||||
if (!arg.equals("test")) {
|
||||
throw new InternalException("expected extensionCommand arg to be 'test' got: " + arg);
|
||||
}
|
||||
return "ribbit";
|
||||
}
|
||||
|
||||
}
|
||||
79
langtools/test/jdk/jshell/ToolLocalSimpleTest.java
Normal file
79
langtools/test/jdk/jshell/ToolLocalSimpleTest.java
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 8168615
|
||||
* @summary Test all the ToolSimpleTest tests, but in local execution. Verify --execution flag
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.jdeps/com.sun.tools.javap
|
||||
* jdk.jshell/jdk.internal.jshell.tool
|
||||
* @build KullaTesting TestingInputStream ToolSimpleTest
|
||||
* @run testng ToolLocalSimpleTest
|
||||
*/
|
||||
|
||||
import java.util.Locale;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class ToolLocalSimpleTest extends ToolSimpleTest {
|
||||
|
||||
@Override
|
||||
public void test(Locale locale, boolean isDefaultStartUp, String[] args, String startUpMessage, ReplTest... tests) {
|
||||
String[] wargs = new String[args.length + 2];
|
||||
wargs[0] = "--execution";
|
||||
wargs[1] = "local";
|
||||
System.arraycopy(args, 0, wargs, 2, args.length);
|
||||
super.test(locale, isDefaultStartUp, wargs, startUpMessage, tests);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyLocal() {
|
||||
System.setProperty("LOCAL_CHECK", "Here");
|
||||
assertEquals(System.getProperty("LOCAL_CHECK"), "Here");
|
||||
test(new String[]{"--no-startup"},
|
||||
a -> assertCommand(a, "System.getProperty(\"LOCAL_CHECK\")", "$1 ==> \"Here\""),
|
||||
a -> assertCommand(a, "System.setProperty(\"LOCAL_CHECK\", \"After\")", "$2 ==> \"Here\"")
|
||||
);
|
||||
assertEquals(System.getProperty("LOCAL_CHECK"), "After");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testOptionR() {
|
||||
test(new String[]{"-R-Dthe.sound=blorp", "--no-startup"},
|
||||
(a) -> assertCommand(a, "System.getProperty(\"the.sound\")",
|
||||
"$1 ==> null")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionBadR() {
|
||||
test(new String[]{"-R-RottenLiver"},
|
||||
(a) -> assertCommand(a, "43",
|
||||
"$1 ==> 43")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -45,9 +45,9 @@ import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
@Test
|
||||
public class ToolSimpleTest extends ReplToolTesting {
|
||||
|
||||
@Test
|
||||
public void testRemaining() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "int z; z =", "z ==> 0"),
|
||||
@ -62,6 +62,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenComment() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "int z = /* blah", ""),
|
||||
@ -72,6 +73,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oneLineOfError() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "12+", null),
|
||||
@ -80,6 +82,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineVariables() {
|
||||
test(
|
||||
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
|
||||
@ -96,6 +99,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineMethods() {
|
||||
test(
|
||||
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
|
||||
@ -112,6 +116,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineTypes() {
|
||||
test(
|
||||
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
|
||||
@ -131,6 +136,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineImports() {
|
||||
test(
|
||||
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
|
||||
@ -150,6 +156,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineVar() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "int x = 72", "x ==> 72"),
|
||||
@ -158,6 +165,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineUnresolvedVar() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "undefined x",
|
||||
@ -166,6 +174,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnresolved() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "int f() { return g() + x + new A().a; }",
|
||||
@ -178,16 +187,19 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownCommand() {
|
||||
test((a) -> assertCommand(a, "/unknown",
|
||||
"| No such command or snippet id: /unknown\n" +
|
||||
"| Type /help for help."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyClassPath() {
|
||||
test(after -> assertCommand(after, "/classpath", "| The /classpath command requires a path argument."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoArgument() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "/save",
|
||||
@ -199,6 +211,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDebug() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "/deb", "| Debugging on"),
|
||||
@ -208,6 +221,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDrop() {
|
||||
test(false, new String[]{"--no-startup"},
|
||||
a -> assertVariable(a, "int", "a"),
|
||||
@ -240,6 +254,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDropNegative() {
|
||||
test(false, new String[]{"--no-startup"},
|
||||
a -> assertCommandOutputStartsWith(a, "/drop 0", "| No such snippet: 0"),
|
||||
@ -255,6 +270,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmbiguousDrop() {
|
||||
Consumer<String> check = s -> {
|
||||
assertTrue(s.startsWith("| The argument references more than one import, variable, method, or class"), s);
|
||||
@ -280,6 +296,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplicationOfPost() {
|
||||
test(
|
||||
(a) -> assertCommand(a, "/set mode t normal -command", "| Created new feedback mode: t"),
|
||||
@ -290,6 +307,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpLength() {
|
||||
Consumer<String> testOutput = (s) -> {
|
||||
List<String> ss = Stream.of(s.split("\n"))
|
||||
@ -304,6 +322,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelp() {
|
||||
test(
|
||||
(a) -> assertHelp(a, "/?", "/list", "/help", "/exit", "intro"),
|
||||
@ -315,6 +334,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpFormat() {
|
||||
test(
|
||||
(a) -> assertCommandCheckOutput(a, "/help", s -> {
|
||||
@ -355,6 +375,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListArgs() {
|
||||
String arg = "qqqq";
|
||||
List<String> startVarList = new ArrayList<>(START_UP);
|
||||
@ -377,6 +398,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarsArgs() {
|
||||
String arg = "qqqq";
|
||||
List<String> startVarList = new ArrayList<>();
|
||||
@ -402,6 +424,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodsArgs() {
|
||||
String arg = "qqqq";
|
||||
List<String> startMethodList = new ArrayList<>(START_UP_CMD_METHOD);
|
||||
@ -436,6 +459,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypesArgs() {
|
||||
String arg = "qqqq";
|
||||
List<String> startTypeList = new ArrayList<>();
|
||||
@ -468,6 +492,8 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
s -> checkLineToList(s, startTypeList))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defineClasses() {
|
||||
test(
|
||||
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
|
||||
@ -486,6 +512,8 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
(a) -> assertCommandCheckOutput(a, "/types", assertClasses())
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommandPrefix() {
|
||||
test(a -> assertCommandCheckOutput(a, "/s",
|
||||
assertStartsWith("| Command: '/s' is ambiguous: /save, /set")),
|
||||
@ -496,6 +524,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
assertStartsWith("| '/save' requires a filename argument.")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionQ() {
|
||||
test(Locale.ROOT, false, new String[]{"-q", "--no-startup"}, "",
|
||||
(a) -> assertCommand(a, "1+1", "$1 ==> 2"),
|
||||
@ -503,12 +532,14 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionS() {
|
||||
test(Locale.ROOT, false, new String[]{"-s", "--no-startup"}, "",
|
||||
(a) -> assertCommand(a, "1+1", "")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionV() {
|
||||
test(new String[]{"-v", "--no-startup"},
|
||||
(a) -> assertCommand(a, "1+1",
|
||||
@ -517,6 +548,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionFeedback() {
|
||||
test(Locale.ROOT, false, new String[]{"--feedback", "concise", "--no-startup"}, "",
|
||||
(a) -> assertCommand(a, "1+1", "$1 ==> 2"),
|
||||
@ -524,6 +556,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompoundOptions() {
|
||||
Consumer<String> confirmNoStartup = s -> {
|
||||
assertEquals(0, Stream.of(s.split("\n"))
|
||||
@ -546,6 +579,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionR() {
|
||||
test(new String[]{"-R-Dthe.sound=blorp", "--no-startup"},
|
||||
(a) -> assertCommand(a, "System.getProperty(\"the.sound\")",
|
||||
@ -553,6 +587,7 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test8156910() {
|
||||
test(
|
||||
(a) -> assertCommandOutputContains(a, "System.out.println(\"%5d\", 10);", "%5d"),
|
||||
|
||||
@ -23,14 +23,13 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8156101 8159935 8159122
|
||||
* @bug 8156101 8159935 8159122 8168615
|
||||
* @summary Tests for ExecutionControl SPI
|
||||
* @build KullaTesting ExecutionControlTestBase
|
||||
* @run testng UserExecutionControlTest
|
||||
*/
|
||||
|
||||
|
||||
import jdk.jshell.execution.LocalExecutionControl;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
@ -41,12 +40,13 @@ public class UserExecutionControlTest extends ExecutionControlTestBase {
|
||||
@BeforeMethod
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(builder -> builder.executionEngine(LocalExecutionControl.create()));
|
||||
setUp(builder -> builder.executionEngine("local"));
|
||||
}
|
||||
|
||||
public void verifyLocal() throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
|
||||
System.setProperty("LOCAL_CHECK", "TBD");
|
||||
assertEquals(System.getProperty("LOCAL_CHECK"), "TBD");
|
||||
assertEval("System.getProperty(\"LOCAL_CHECK\")", "\"TBD\"");
|
||||
assertEval("System.setProperty(\"LOCAL_CHECK\", \"local\")");
|
||||
assertEquals(System.getProperty("LOCAL_CHECK"), "local");
|
||||
}
|
||||
|
||||
@ -23,9 +23,9 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8160128 8159935
|
||||
* @bug 8160128 8159935 8168615
|
||||
* @summary Tests for Aux channel, custom remote agents, custom JDI implementations.
|
||||
* @build KullaTesting ExecutionControlTestBase
|
||||
* @build KullaTesting ExecutionControlTestBase MyExecutionControl MyRemoteExecutionControl MyExecutionControlProvider
|
||||
* @run testng UserJdiUserRemoteTest
|
||||
*/
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@ -34,34 +34,10 @@ import org.testng.annotations.BeforeMethod;
|
||||
import jdk.jshell.Snippet;
|
||||
import static jdk.jshell.Snippet.Status.OVERWRITTEN;
|
||||
import static jdk.jshell.Snippet.Status.VALID;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.sun.jdi.VMDisconnectedException;
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
import jdk.jshell.VarSnippet;
|
||||
import jdk.jshell.execution.DirectExecutionControl;
|
||||
import jdk.jshell.execution.JdiExecutionControl;
|
||||
import jdk.jshell.execution.JdiInitiator;
|
||||
import jdk.jshell.execution.Util;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import jdk.jshell.spi.ExecutionControl;
|
||||
import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
|
||||
import jdk.jshell.spi.ExecutionEnv;
|
||||
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.remoteInputOutput;
|
||||
|
||||
@Test
|
||||
public class UserJdiUserRemoteTest extends ExecutionControlTestBase {
|
||||
@ -73,7 +49,7 @@ public class UserJdiUserRemoteTest extends ExecutionControlTestBase {
|
||||
@Override
|
||||
public void setUp() {
|
||||
auxStream = new ByteArrayOutputStream();
|
||||
setUp(builder -> builder.executionEngine(MyExecutionControl.create(this)));
|
||||
setUp(builder -> builder.executionEngine(new MyExecutionControlProvider(this), null));
|
||||
}
|
||||
|
||||
public void testVarValue() {
|
||||
@ -114,174 +90,3 @@ public class UserJdiUserRemoteTest extends ExecutionControlTestBase {
|
||||
assertActiveKeys();
|
||||
}
|
||||
}
|
||||
|
||||
class MyExecutionControl extends JdiExecutionControl {
|
||||
|
||||
private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName();
|
||||
private static final int TIMEOUT = 2000;
|
||||
|
||||
private VirtualMachine vm;
|
||||
private Process process;
|
||||
|
||||
/**
|
||||
* Creates an ExecutionControl instance based on a JDI
|
||||
* {@code LaunchingConnector}.
|
||||
*
|
||||
* @return the generator
|
||||
*/
|
||||
public static ExecutionControl.Generator create(UserJdiUserRemoteTest test) {
|
||||
return env -> make(env, test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExecutionControl instance based on a JDI
|
||||
* {@code ListeningConnector} or {@code LaunchingConnector}.
|
||||
*
|
||||
* Initialize JDI and use it to launch the remote JVM. Set-up a socket for
|
||||
* commands and results. This socket also transports the user
|
||||
* input/output/error.
|
||||
*
|
||||
* @param env the context passed by
|
||||
* {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }
|
||||
* @return the channel
|
||||
* @throws IOException if there are errors in set-up
|
||||
*/
|
||||
static ExecutionControl make(ExecutionEnv env, UserJdiUserRemoteTest test) throws IOException {
|
||||
try (final ServerSocket listener = new ServerSocket(0)) {
|
||||
// timeout for socket
|
||||
listener.setSoTimeout(TIMEOUT);
|
||||
int port = listener.getLocalPort();
|
||||
|
||||
// Set-up the JDI connection
|
||||
List<String> opts = new ArrayList<>(env.extraRemoteVMOptions());
|
||||
opts.add("-classpath");
|
||||
opts.add(System.getProperty("java.class.path")
|
||||
+ System.getProperty("path.separator")
|
||||
+ System.getProperty("user.dir"));
|
||||
JdiInitiator jdii = new JdiInitiator(port,
|
||||
opts, REMOTE_AGENT, true, null, TIMEOUT);
|
||||
VirtualMachine vm = jdii.vm();
|
||||
Process process = jdii.process();
|
||||
|
||||
List<Consumer<String>> deathListeners = new ArrayList<>();
|
||||
deathListeners.add(s -> env.closeDown());
|
||||
Util.detectJdiExitEvent(vm, s -> {
|
||||
for (Consumer<String> h : deathListeners) {
|
||||
h.accept(s);
|
||||
}
|
||||
});
|
||||
|
||||
// Set-up the commands/reslts on the socket. Piggy-back snippet
|
||||
// output.
|
||||
Socket socket = listener.accept();
|
||||
// out before in -- match remote creation so we don't hang
|
||||
OutputStream out = socket.getOutputStream();
|
||||
Map<String, OutputStream> outputs = new HashMap<>();
|
||||
outputs.put("out", env.userOut());
|
||||
outputs.put("err", env.userErr());
|
||||
outputs.put("aux", test.auxStream);
|
||||
Map<String, InputStream> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance.
|
||||
*
|
||||
* @param out the output for commands
|
||||
* @param in the input for responses
|
||||
*/
|
||||
private MyExecutionControl(ObjectOutput out, ObjectInput in,
|
||||
VirtualMachine vm, Process process,
|
||||
List<Consumer<String>> deathListeners) {
|
||||
super(out, in);
|
||||
this.vm = vm;
|
||||
this.process = process;
|
||||
deathListeners.add(s -> disposeVM());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
disposeVM();
|
||||
}
|
||||
|
||||
private synchronized void disposeVM() {
|
||||
try {
|
||||
if (vm != null) {
|
||||
vm.dispose(); // This could NPE, so it is caught below
|
||||
vm = null;
|
||||
}
|
||||
} catch (VMDisconnectedException ex) {
|
||||
// Ignore if already closed
|
||||
} catch (Throwable e) {
|
||||
fail("disposeVM threw: " + e);
|
||||
} finally {
|
||||
if (process != null) {
|
||||
process.destroy();
|
||||
process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized VirtualMachine vm() throws EngineTerminationException {
|
||||
if (vm == null) {
|
||||
throw new EngineTerminationException("VM closed");
|
||||
} else {
|
||||
return vm;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MyRemoteExecutionControl extends DirectExecutionControl implements ExecutionControl {
|
||||
|
||||
static PrintStream auxPrint;
|
||||
|
||||
/**
|
||||
* Launch the agent, connecting to the JShell-core over the socket specified
|
||||
* in the command-line argument.
|
||||
*
|
||||
* @param args standard command-line arguments, expectation is the socket
|
||||
* number is the only argument
|
||||
* @throws Exception any unexpected exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
String loopBack = null;
|
||||
Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
|
||||
InputStream inStream = socket.getInputStream();
|
||||
OutputStream outStream = socket.getOutputStream();
|
||||
Map<String, Consumer<OutputStream>> 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<String, Consumer<InputStream>> input = new HashMap<>();
|
||||
input.put("in", st -> System.setIn(st));
|
||||
forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, outputs, input);
|
||||
} catch (Throwable ex) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String varValue(String className, String varName)
|
||||
throws RunException, EngineTerminationException, InternalException {
|
||||
auxPrint.print(varName);
|
||||
return super.varValue(className, varName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object extensionCommand(String className, Object arg)
|
||||
throws RunException, EngineTerminationException, InternalException {
|
||||
if (!arg.equals("test")) {
|
||||
throw new InternalException("expected extensionCommand arg to be 'test' got: " + arg);
|
||||
}
|
||||
return "ribbit";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user