author | hseigel |
Wed, 01 Mar 2017 08:00:02 -0500 | |
changeset 46194 | 5596e6f63072 |
parent 43770 | a321bed02000 |
child 45045 | 834233132ab1 |
permissions | -rw-r--r-- |
33362 | 1 |
/* |
43758 | 2 |
* Copyright (c) 2015, 2017 Oracle and/or its affiliates. All rights reserved. |
33362 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package jdk.jshell; |
|
27 |
||
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
28 |
import jdk.jshell.spi.ExecutionControl; |
33362 | 29 |
import java.io.ByteArrayInputStream; |
30 |
import java.io.InputStream; |
|
41628 | 31 |
import java.io.InterruptedIOException; |
33362 | 32 |
import java.io.PrintStream; |
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
33 |
import java.net.InetAddress; |
36990 | 34 |
import java.text.MessageFormat; |
37745
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
35 |
import java.util.ArrayList; |
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
36 |
import java.util.Arrays; |
33362 | 37 |
import java.util.Collections; |
38 |
import java.util.HashMap; |
|
39 |
import java.util.List; |
|
40 |
import java.util.Map; |
|
36990 | 41 |
import java.util.MissingResourceException; |
33362 | 42 |
import java.util.Objects; |
36990 | 43 |
import java.util.ResourceBundle; |
33362 | 44 |
import java.util.function.BiFunction; |
45 |
import java.util.function.Consumer; |
|
46 |
||
43758 | 47 |
import java.util.function.Function; |
33362 | 48 |
import java.util.function.Supplier; |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
49 |
import java.util.stream.Stream; |
43758 | 50 |
import javax.tools.StandardJavaFileManager; |
33362 | 51 |
import jdk.internal.jshell.debug.InternalDebugControl; |
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
52 |
import jdk.jshell.Snippet.Status; |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
53 |
import jdk.jshell.spi.ExecutionControl.EngineTerminationException; |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
54 |
import jdk.jshell.spi.ExecutionControl.ExecutionControlException; |
42969
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
55 |
import jdk.jshell.spi.ExecutionControlProvider; |
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
56 |
import jdk.jshell.spi.ExecutionEnv; |
33362 | 57 |
import static jdk.jshell.Util.expunge; |
58 |
||
59 |
/** |
|
60 |
* The JShell evaluation state engine. This is the central class in the JShell |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
61 |
* API. A {@code JShell} instance holds the evolving compilation and |
33362 | 62 |
* execution state. The state is changed with the instance methods |
63 |
* {@link jdk.jshell.JShell#eval(java.lang.String) eval(String)}, |
|
41514
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
64 |
* {@link jdk.jshell.JShell#drop(jdk.jshell.Snippet) drop(Snippet)} and |
33362 | 65 |
* {@link jdk.jshell.JShell#addToClasspath(java.lang.String) addToClasspath(String)}. |
66 |
* The majority of methods query the state. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
67 |
* A {@code JShell} instance also allows registering for events with |
33362 | 68 |
* {@link jdk.jshell.JShell#onSnippetEvent(java.util.function.Consumer) onSnippetEvent(Consumer)} |
69 |
* and {@link jdk.jshell.JShell#onShutdown(java.util.function.Consumer) onShutdown(Consumer)}, which |
|
70 |
* are unregistered with |
|
71 |
* {@link jdk.jshell.JShell#unsubscribe(jdk.jshell.JShell.Subscription) unsubscribe(Subscription)}. |
|
72 |
* Access to the source analysis utilities is via |
|
73 |
* {@link jdk.jshell.JShell#sourceCodeAnalysis()}. |
|
74 |
* When complete the instance should be closed to free resources -- |
|
75 |
* {@link jdk.jshell.JShell#close()}. |
|
76 |
* <p> |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
77 |
* An instance of {@code JShell} is created with |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
78 |
* {@code JShell.create()}. |
33362 | 79 |
* <p> |
80 |
* This class is not thread safe, except as noted, all access should be through |
|
81 |
* a single thread. |
|
43770 | 82 |
* |
33362 | 83 |
* @author Robert Field |
43770 | 84 |
* @since 9 |
33362 | 85 |
*/ |
86 |
public class JShell implements AutoCloseable { |
|
87 |
||
88 |
final SnippetMaps maps; |
|
89 |
final KeyMap keyMap; |
|
37644
33cf53901cac
8154485: JShell: infrastructure for multi-Snippet class wrappers
rfield
parents:
37004
diff
changeset
|
90 |
final OuterWrapMap outerMap; |
33362 | 91 |
final TaskFactory taskFactory; |
92 |
final InputStream in; |
|
93 |
final PrintStream out; |
|
94 |
final PrintStream err; |
|
95 |
final Supplier<String> tempVariableNameGenerator; |
|
96 |
final BiFunction<Snippet, Integer, String> idGenerator; |
|
37745
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
97 |
final List<String> extraRemoteVMOptions; |
39369 | 98 |
final List<String> extraCompilerOptions; |
43758 | 99 |
final Function<StandardJavaFileManager, StandardJavaFileManager> fileManagerMapping; |
33362 | 100 |
|
101 |
private int nextKeyIndex = 1; |
|
102 |
||
103 |
final Eval eval; |
|
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
104 |
final ClassTracker classTracker; |
33362 | 105 |
private final Map<Subscription, Consumer<JShell>> shutdownListeners = new HashMap<>(); |
106 |
private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>(); |
|
107 |
private boolean closed = false; |
|
108 |
||
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
109 |
private final ExecutionControl executionControl; |
33715
74b1bed86932
8141092: JShell: Completion hangs on identifier completion
jlahoda
parents:
33714
diff
changeset
|
110 |
private SourceCodeAnalysisImpl sourceCodeAnalysis = null; |
33362 | 111 |
|
36990 | 112 |
private static final String L10N_RB_NAME = "jdk.jshell.resources.l10n"; |
113 |
private static ResourceBundle outputRB = null; |
|
33362 | 114 |
|
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
115 |
JShell(Builder b) throws IllegalStateException { |
33362 | 116 |
this.in = b.in; |
117 |
this.out = b.out; |
|
118 |
this.err = b.err; |
|
119 |
this.tempVariableNameGenerator = b.tempVariableNameGenerator; |
|
120 |
this.idGenerator = b.idGenerator; |
|
37745
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
121 |
this.extraRemoteVMOptions = b.extraRemoteVMOptions; |
39369 | 122 |
this.extraCompilerOptions = b.extraCompilerOptions; |
43758 | 123 |
this.fileManagerMapping = b.fileManagerMapping; |
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
124 |
try { |
42969
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
125 |
if (b.executionControlProvider != null) { |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
126 |
executionControl = b.executionControlProvider.generate(new ExecutionEnvImpl(), |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
127 |
b.executionControlParameters == null |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
128 |
? b.executionControlProvider.defaultParameters() |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
129 |
: b.executionControlParameters); |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
130 |
} else { |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
131 |
String loopback = InetAddress.getLoopbackAddress().getHostAddress(); |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
132 |
String spec = b.executionControlSpec == null |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
133 |
? "failover:0(jdi:hostname(" + loopback + "))," |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
134 |
+ "1(jdi:launch(true)), 2(jdi)" |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
135 |
: b.executionControlSpec; |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
136 |
executionControl = ExecutionControl.generate(new ExecutionEnvImpl(), spec); |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
137 |
} |
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
138 |
} catch (Throwable ex) { |
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
139 |
throw new IllegalStateException("Launching JShell execution engine threw: " + ex.getMessage(), ex); |
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
140 |
} |
33362 | 141 |
|
142 |
this.maps = new SnippetMaps(this); |
|
143 |
this.keyMap = new KeyMap(this); |
|
37644
33cf53901cac
8154485: JShell: infrastructure for multi-Snippet class wrappers
rfield
parents:
37004
diff
changeset
|
144 |
this.outerMap = new OuterWrapMap(this); |
33362 | 145 |
this.taskFactory = new TaskFactory(this); |
146 |
this.eval = new Eval(this); |
|
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
147 |
this.classTracker = new ClassTracker(); |
33362 | 148 |
} |
149 |
||
150 |
/** |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
151 |
* Builder for {@code JShell} instances. |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
152 |
* Create custom instances of {@code JShell} by using the setter |
33362 | 153 |
* methods on this class. After zero or more of these, use the |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
154 |
* {@link #build()} method to create a {@code JShell} instance. |
33362 | 155 |
* These can all be chained. For example, setting the remote output and |
156 |
* error streams: |
|
157 |
* <pre> |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
158 |
* {@code |
33362 | 159 |
* JShell myShell = |
160 |
* JShell.builder() |
|
161 |
* .out(myOutStream) |
|
162 |
* .err(myErrStream) |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
163 |
* .build(); } </pre> |
33362 | 164 |
* If no special set-up is needed, just use |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
165 |
* {@code JShell.builder().build()} or the short-cut equivalent |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
166 |
* {@code JShell.create()}. |
33362 | 167 |
*/ |
168 |
public static class Builder { |
|
169 |
||
170 |
InputStream in = new ByteArrayInputStream(new byte[0]); |
|
171 |
PrintStream out = System.out; |
|
172 |
PrintStream err = System.err; |
|
173 |
Supplier<String> tempVariableNameGenerator = null; |
|
174 |
BiFunction<Snippet, Integer, String> idGenerator = null; |
|
37745
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
175 |
List<String> extraRemoteVMOptions = new ArrayList<>(); |
39369 | 176 |
List<String> extraCompilerOptions = new ArrayList<>(); |
42969
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
177 |
ExecutionControlProvider executionControlProvider; |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
178 |
Map<String,String> executionControlParameters; |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
179 |
String executionControlSpec; |
43758 | 180 |
Function<StandardJavaFileManager, StandardJavaFileManager> fileManagerMapping; |
33362 | 181 |
|
182 |
Builder() { } |
|
183 |
||
184 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
185 |
* Sets the input for the running evaluation (it's {@code System.in}). Note: |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
186 |
* applications that use {@code System.in} for snippet or other |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
187 |
* user input cannot use {@code System.in} as the input stream for |
33362 | 188 |
* the remote process. |
189 |
* <p> |
|
41628 | 190 |
* The {@code read} method of the {@code InputStream} may throw the {@link InterruptedIOException} |
191 |
* to signal the user canceled the input. The currently running snippet will be automatically |
|
192 |
* {@link JShell#stop() stopped}. |
|
193 |
* <p> |
|
33362 | 194 |
* The default, if this is not set, is to provide an empty input stream |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
195 |
* -- {@code new ByteArrayInputStream(new byte[0])}. |
33362 | 196 |
* |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
197 |
* @param in the {@code InputStream} to be channelled to |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
198 |
* {@code System.in} in the remote execution process |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
199 |
* @return the {@code Builder} instance (for use in chained |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
200 |
* initialization) |
33362 | 201 |
*/ |
202 |
public Builder in(InputStream in) { |
|
203 |
this.in = in; |
|
204 |
return this; |
|
205 |
} |
|
206 |
||
207 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
208 |
* Sets the output for the running evaluation (it's {@code System.out}). |
33362 | 209 |
* The controlling process and |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
210 |
* the remote process can share {@code System.out}. |
33362 | 211 |
* <p> |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
212 |
* The default, if this is not set, is {@code System.out}. |
33362 | 213 |
* |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
214 |
* @param out the {@code PrintStream} to be channelled to |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
215 |
* {@code System.out} in the remote execution process |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
216 |
* @return the {@code Builder} instance (for use in chained |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
217 |
* initialization) |
33362 | 218 |
*/ |
219 |
public Builder out(PrintStream out) { |
|
220 |
this.out = out; |
|
221 |
return this; |
|
222 |
} |
|
223 |
||
224 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
225 |
* Sets the error output for the running evaluation (it's |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
226 |
* {@code System.err}). The controlling process and the remote |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
227 |
* process can share {@code System.err}. |
33362 | 228 |
* <p> |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
229 |
* The default, if this is not set, is {@code System.err}. |
33362 | 230 |
* |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
231 |
* @param err the {@code PrintStream} to be channelled to |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
232 |
* {@code System.err} in the remote execution process |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
233 |
* @return the {@code Builder} instance (for use in chained |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
234 |
* initialization) |
33362 | 235 |
*/ |
236 |
public Builder err(PrintStream err) { |
|
237 |
this.err = err; |
|
238 |
return this; |
|
239 |
} |
|
240 |
||
241 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
242 |
* Sets a generator of temp variable names for |
33362 | 243 |
* {@link jdk.jshell.VarSnippet} of |
244 |
* {@link jdk.jshell.Snippet.SubKind#TEMP_VAR_EXPRESSION_SUBKIND}. |
|
245 |
* <p> |
|
246 |
* Do not use this method unless you have explicit need for it. |
|
247 |
* <p> |
|
248 |
* The generator will be used for newly created VarSnippet |
|
249 |
* instances. The name of a variable is queried with |
|
250 |
* {@link jdk.jshell.VarSnippet#name()}. |
|
251 |
* <p> |
|
252 |
* The callback is sent during the processing of the snippet, the |
|
253 |
* JShell state is not stable. No calls whatsoever on the |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
254 |
* {@code JShell} instance may be made from the callback. |
33362 | 255 |
* <p> |
256 |
* The generated name must be unique within active snippets. |
|
257 |
* <p> |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
258 |
* The default behavior (if this is not set or {@code generator} |
33362 | 259 |
* is null) is to generate the name as a sequential number with a |
260 |
* prefixing dollar sign ("$"). |
|
261 |
* |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
262 |
* @param generator the {@code Supplier} to generate the temporary |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
263 |
* variable name string or {@code null} |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
264 |
* @return the {@code Builder} instance (for use in chained |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
265 |
* initialization) |
33362 | 266 |
*/ |
267 |
public Builder tempVariableNameGenerator(Supplier<String> generator) { |
|
268 |
this.tempVariableNameGenerator = generator; |
|
269 |
return this; |
|
270 |
} |
|
271 |
||
272 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
273 |
* Sets the generator of identifying names for Snippets. |
33362 | 274 |
* <p> |
275 |
* Do not use this method unless you have explicit need for it. |
|
276 |
* <p> |
|
277 |
* The generator will be used for newly created Snippet instances. The |
|
278 |
* identifying name (id) is accessed with |
|
279 |
* {@link jdk.jshell.Snippet#id()} and can be seen in the |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
280 |
* {@code StackTraceElement.getFileName()} for a |
33362 | 281 |
* {@link jdk.jshell.EvalException} and |
282 |
* {@link jdk.jshell.UnresolvedReferenceException}. |
|
283 |
* <p> |
|
284 |
* The inputs to the generator are the {@link jdk.jshell.Snippet} and an |
|
285 |
* integer. The integer will be the same for two Snippets which would |
|
286 |
* overwrite one-another, but otherwise is unique. |
|
287 |
* <p> |
|
288 |
* The callback is sent during the processing of the snippet and the |
|
289 |
* Snippet and the state as a whole are not stable. No calls to change |
|
290 |
* system state (including Snippet state) should be made. Queries of |
|
291 |
* Snippet may be made except to {@link jdk.jshell.Snippet#id()}. No |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
292 |
* calls on the {@code JShell} instance may be made from the |
33362 | 293 |
* callback, except to |
294 |
* {@link #status(jdk.jshell.Snippet) status(Snippet)}. |
|
295 |
* <p> |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
296 |
* The default behavior (if this is not set or {@code generator} |
33362 | 297 |
* is null) is to generate the id as the integer converted to a string. |
298 |
* |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
299 |
* @param generator the {@code BiFunction} to generate the id |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
300 |
* string or {@code null} |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
301 |
* @return the {@code Builder} instance (for use in chained |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
302 |
* initialization) |
33362 | 303 |
*/ |
304 |
public Builder idGenerator(BiFunction<Snippet, Integer, String> generator) { |
|
305 |
this.idGenerator = generator; |
|
306 |
return this; |
|
307 |
} |
|
308 |
||
309 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
310 |
* Sets additional VM options for launching the VM. |
37745
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
311 |
* |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
312 |
* @param options The options for the remote VM |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
313 |
* @return the {@code Builder} instance (for use in chained |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
314 |
* initialization) |
37745
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
315 |
*/ |
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
316 |
public Builder remoteVMOptions(String... options) { |
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
317 |
this.extraRemoteVMOptions.addAll(Arrays.asList(options)); |
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
318 |
return this; |
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
319 |
} |
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
320 |
|
4b6b59f8e327
8150382: JShell API: Allow setting remote JVM arguments
rfield
parents:
37644
diff
changeset
|
321 |
/** |
39369 | 322 |
* Adds compiler options. These additional options will be used on |
323 |
* parsing, analysis, and code generation calls to the compiler. |
|
324 |
* Options which interfere with results are not supported and have |
|
325 |
* undefined effects on JShell's operation. |
|
326 |
* |
|
327 |
* @param options the addition options for compiler invocations |
|
328 |
* @return the {@code Builder} instance (for use in chained |
|
329 |
* initialization) |
|
330 |
*/ |
|
331 |
public Builder compilerOptions(String... options) { |
|
332 |
this.extraCompilerOptions.addAll(Arrays.asList(options)); |
|
333 |
return this; |
|
334 |
} |
|
335 |
||
336 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
337 |
* Sets the custom engine for execution. Snippet execution will be |
42969
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
338 |
* provided by the {@link ExecutionControl} instance selected by the |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
339 |
* specified execution control spec. |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
340 |
* Use, at most, one of these overloaded {@code executionEngine} builder |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
341 |
* methods. |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
342 |
* |
42969
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
343 |
* @param executionControlSpec the execution control spec, |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
344 |
* which is documented in the {@link jdk.jshell.spi} |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
345 |
* package documentation. |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
346 |
* @return the {@code Builder} instance (for use in chained |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
347 |
* initialization) |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
348 |
*/ |
42969
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
349 |
public Builder executionEngine(String executionControlSpec) { |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
350 |
this.executionControlSpec = executionControlSpec; |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
351 |
return this; |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
352 |
} |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
353 |
|
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
354 |
/** |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
355 |
* Sets the custom engine for execution. Snippet execution will be |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
356 |
* provided by the specified {@link ExecutionControl} instance. |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
357 |
* Use, at most, one of these overloaded {@code executionEngine} builder |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
358 |
* methods. |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
359 |
* |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
360 |
* @param executionControlProvider the provider to supply the execution |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
361 |
* engine |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
362 |
* @param executionControlParameters the parameters to the provider, or |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
363 |
* {@code null} for default parameters |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
364 |
* @return the {@code Builder} instance (for use in chained |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
365 |
* initialization) |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
366 |
*/ |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
367 |
public Builder executionEngine(ExecutionControlProvider executionControlProvider, |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
368 |
Map<String,String> executionControlParameters) { |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
369 |
this.executionControlProvider = executionControlProvider; |
a48d4f74d322
8168615: JShell API: jdk.jshell.spi should be a pluggable ServiceLoader SPI
rfield
parents:
42272
diff
changeset
|
370 |
this.executionControlParameters = executionControlParameters; |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
371 |
return this; |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
372 |
} |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
373 |
|
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
374 |
/** |
43758 | 375 |
* Configure the {@code FileManager} to be used by compilation and |
376 |
* source analysis. |
|
377 |
* If not set or passed null, the compiler's standard file manager will |
|
378 |
* be used (identity mapping). |
|
379 |
* For use in special applications where the compiler's normal file |
|
380 |
* handling needs to be overridden. See the file manager APIs for more |
|
381 |
* information. |
|
382 |
* The file manager input enables forwarding file managers, if this |
|
383 |
* is not needed, the incoming file manager can be ignored (constant |
|
384 |
* function). |
|
385 |
* |
|
386 |
* @param mapping a function that given the compiler's standard file |
|
387 |
* manager, returns a file manager to use |
|
388 |
* @return the {@code Builder} instance (for use in chained |
|
389 |
* initialization) |
|
390 |
*/ |
|
391 |
public Builder fileManager(Function<StandardJavaFileManager, StandardJavaFileManager> mapping) { |
|
392 |
this.fileManagerMapping = mapping; |
|
393 |
return this; |
|
394 |
} |
|
395 |
||
396 |
/** |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
397 |
* Builds a JShell state engine. This is the entry-point to all JShell |
33362 | 398 |
* functionality. This creates a remote process for execution. It is |
399 |
* thus important to close the returned instance. |
|
400 |
* |
|
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
401 |
* @throws IllegalStateException if the {@code JShell} instance could not be created. |
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
402 |
* @return the state engine |
33362 | 403 |
*/ |
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
404 |
public JShell build() throws IllegalStateException { |
33362 | 405 |
return new JShell(this); |
406 |
} |
|
407 |
} |
|
408 |
||
409 |
// --- public API --- |
|
410 |
||
411 |
/** |
|
412 |
* Create a new JShell state engine. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
413 |
* That is, create an instance of {@code JShell}. |
33362 | 414 |
* <p> |
415 |
* Equivalent to {@link JShell#builder() JShell.builder()}{@link JShell.Builder#build() .build()}. |
|
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
416 |
* @throws IllegalStateException if the {@code JShell} instance could not be created. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
417 |
* @return an instance of {@code JShell}. |
33362 | 418 |
*/ |
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
419 |
public static JShell create() throws IllegalStateException { |
33362 | 420 |
return builder().build(); |
421 |
} |
|
422 |
||
423 |
/** |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
424 |
* Factory method for {@code JShell.Builder} which, in-turn, is used |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
425 |
* for creating instances of {@code JShell}. |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
426 |
* Create a default instance of {@code JShell} with |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
427 |
* {@code JShell.builder().build()}. For more construction options |
33362 | 428 |
* see {@link jdk.jshell.JShell.Builder}. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
429 |
* @return an instance of {@code Builder}. |
33362 | 430 |
* @see jdk.jshell.JShell.Builder |
431 |
*/ |
|
432 |
public static Builder builder() { |
|
433 |
return new Builder(); |
|
434 |
} |
|
435 |
||
436 |
/** |
|
437 |
* Access to source code analysis functionality. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
438 |
* An instance of {@code JShell} will always return the same |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
439 |
* {@code SourceCodeAnalysis} instance from |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
440 |
* {@code sourceCodeAnalysis()}. |
33362 | 441 |
* @return an instance of {@link SourceCodeAnalysis SourceCodeAnalysis} |
442 |
* which can be used for source analysis such as completion detection and |
|
443 |
* completion suggestions. |
|
444 |
*/ |
|
445 |
public SourceCodeAnalysis sourceCodeAnalysis() { |
|
446 |
if (sourceCodeAnalysis == null) { |
|
447 |
sourceCodeAnalysis = new SourceCodeAnalysisImpl(this); |
|
448 |
} |
|
449 |
return sourceCodeAnalysis; |
|
450 |
} |
|
451 |
||
452 |
/** |
|
453 |
* Evaluate the input String, including definition and/or execution, if |
|
454 |
* applicable. The input is checked for errors, unless the errors can be |
|
455 |
* deferred (as is the case with some unresolvedDependencies references), |
|
39370
437ba9bd2582
8159111: JShell API: Add access to wrappers and dependencies
rfield
parents:
39369
diff
changeset
|
456 |
* errors will abort evaluation. |
437ba9bd2582
8159111: JShell API: Add access to wrappers and dependencies
rfield
parents:
39369
diff
changeset
|
457 |
* <p> |
437ba9bd2582
8159111: JShell API: Add access to wrappers and dependencies
rfield
parents:
39369
diff
changeset
|
458 |
* The input should be |
33362 | 459 |
* exactly one complete snippet of source code, that is, one expression, |
460 |
* statement, variable declaration, method declaration, class declaration, |
|
461 |
* or import. |
|
462 |
* To break arbitrary input into individual complete snippets, use |
|
463 |
* {@link SourceCodeAnalysis#analyzeCompletion(String)}. |
|
464 |
* <p> |
|
465 |
* For imports, the import is added. Classes, interfaces. methods, |
|
466 |
* and variables are defined. The initializer of variables, statements, |
|
467 |
* and expressions are executed. |
|
468 |
* The modifiers public, protected, private, static, and final are not |
|
469 |
* allowed on op-level declarations and are ignored with a warning. |
|
470 |
* Synchronized, native, abstract, and default top-level methods are not |
|
471 |
* allowed and are errors. |
|
472 |
* If a previous definition of a declaration is overwritten then there will |
|
473 |
* be an event showing its status changed to OVERWRITTEN, this will not |
|
474 |
* occur for dropped, rejected, or already overwritten declarations. |
|
475 |
* <p> |
|
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
476 |
* If execution environment is out of process, as is the default case, then |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
477 |
* if the evaluated code |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
478 |
* causes the execution environment to terminate, this {@code JShell} |
33362 | 479 |
* instance will be closed but the calling process and VM remain valid. |
480 |
* @param input The input String to evaluate |
|
481 |
* @return the list of events directly or indirectly caused by this evaluation. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
482 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 483 |
* @see SourceCodeAnalysis#analyzeCompletion(String) |
484 |
* @see JShell#onShutdown(java.util.function.Consumer) |
|
485 |
*/ |
|
486 |
public List<SnippetEvent> eval(String input) throws IllegalStateException { |
|
36160
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
487 |
SourceCodeAnalysisImpl a = sourceCodeAnalysis; |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
488 |
if (a != null) { |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
489 |
a.suspendIndexing(); |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
490 |
} |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
491 |
try { |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
492 |
checkIfAlive(); |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
493 |
List<SnippetEvent> events = eval.eval(input); |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
494 |
events.forEach(this::notifyKeyStatusEvent); |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
495 |
return Collections.unmodifiableList(events); |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
496 |
} finally { |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
497 |
if (a != null) { |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
498 |
a.resumeIndexing(); |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
499 |
} |
f42d362d0d17
8131027: JShell API/tool: suggest imports for a class
jlahoda
parents:
33715
diff
changeset
|
500 |
} |
33362 | 501 |
} |
502 |
||
503 |
/** |
|
41514
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
504 |
* Remove a declaration from the state. That is, if the snippet is an |
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
505 |
* {@linkplain jdk.jshell.Snippet.Status#isActive() active} |
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
506 |
* {@linkplain jdk.jshell.PersistentSnippet persistent} snippet, remove the |
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
507 |
* snippet and update the JShell evaluation state accordingly. |
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
508 |
* For all active snippets, change the {@linkplain #status status} to |
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
509 |
* {@link jdk.jshell.Snippet.Status#DROPPED DROPPED}. |
33362 | 510 |
* @param snippet The snippet to remove |
511 |
* @return The list of events from updating declarations dependent on the |
|
512 |
* dropped snippet. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
513 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 514 |
* @throws IllegalArgumentException if the snippet is not associated with |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
515 |
* this {@code JShell} instance. |
33362 | 516 |
*/ |
41514
a75c2b869d8d
8167128: JShell: /drop of statement gives confusing output
rfield
parents:
40764
diff
changeset
|
517 |
public List<SnippetEvent> drop(Snippet snippet) throws IllegalStateException { |
33362 | 518 |
checkIfAlive(); |
519 |
checkValidSnippet(snippet); |
|
520 |
List<SnippetEvent> events = eval.drop(snippet); |
|
521 |
events.forEach(this::notifyKeyStatusEvent); |
|
522 |
return Collections.unmodifiableList(events); |
|
523 |
} |
|
524 |
||
525 |
/** |
|
526 |
* The specified path is added to the end of the classpath used in eval(). |
|
527 |
* Note that the unnamed package is not accessible from the package in which |
|
37004
ff77b7986967
8153243: make docs should generate JShell API docs
jlahoda
parents:
36990
diff
changeset
|
528 |
* {@link JShell#eval(String)} code is placed. |
33362 | 529 |
* @param path the path to add to the classpath. |
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
530 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 531 |
*/ |
532 |
public void addToClasspath(String path) { |
|
43758 | 533 |
checkIfAlive(); |
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
534 |
// Compiler |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
535 |
taskFactory.addToClasspath(path); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
536 |
// Runtime |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
537 |
try { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
538 |
executionControl().addToClasspath(path); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
539 |
} catch (ExecutionControlException ex) { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
540 |
debug(ex, "on addToClasspath(" + path + ")"); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
541 |
} |
33715
74b1bed86932
8141092: JShell: Completion hangs on identifier completion
jlahoda
parents:
33714
diff
changeset
|
542 |
if (sourceCodeAnalysis != null) { |
74b1bed86932
8141092: JShell: Completion hangs on identifier completion
jlahoda
parents:
33714
diff
changeset
|
543 |
sourceCodeAnalysis.classpathChanged(); |
74b1bed86932
8141092: JShell: Completion hangs on identifier completion
jlahoda
parents:
33714
diff
changeset
|
544 |
} |
33362 | 545 |
} |
546 |
||
547 |
/** |
|
548 |
* Attempt to stop currently running evaluation. When called while |
|
549 |
* the {@link #eval(java.lang.String) } method is running and the |
|
550 |
* user's code being executed, an attempt will be made to stop user's code. |
|
551 |
* Note that typically this method needs to be called from a different thread |
|
552 |
* than the one running the {@code eval} method. |
|
553 |
* <p> |
|
554 |
* If the {@link #eval(java.lang.String) } method is not running, does nothing. |
|
555 |
* <p> |
|
556 |
* The attempt to stop the user's code may fail in some case, which may include |
|
557 |
* when the execution is blocked on an I/O operation, or when the user's code is |
|
558 |
* catching the {@link ThreadDeath} exception. |
|
559 |
*/ |
|
560 |
public void stop() { |
|
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
561 |
if (executionControl != null) { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
562 |
try { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
563 |
executionControl.stop(); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
564 |
} catch (ExecutionControlException ex) { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
565 |
debug(ex, "on stop()"); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
566 |
} |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
567 |
} |
33362 | 568 |
} |
569 |
||
570 |
/** |
|
571 |
* Close this state engine. Frees resources. Should be called when this |
|
572 |
* state engine is no longer needed. |
|
573 |
*/ |
|
574 |
@Override |
|
575 |
public void close() { |
|
43757 | 576 |
closeDown(); |
33362 | 577 |
} |
578 |
||
579 |
/** |
|
580 |
* Return all snippets. |
|
581 |
* @return the snippets for all current snippets in id order. |
|
582 |
*/ |
|
40515
819fc588bd19
8164277: JShell API: Snippets are immutable and should be available for post-mortem analysis
rfield
parents:
40304
diff
changeset
|
583 |
public Stream<Snippet> snippets() { |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
584 |
return maps.snippetList().stream(); |
33362 | 585 |
} |
586 |
||
587 |
/** |
|
588 |
* Returns the active variable snippets. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
589 |
* This convenience method is equivalent to {@code snippets()} filtered for |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
590 |
* {@link jdk.jshell.Snippet.Status#isActive() status(snippet).isActive()} |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
591 |
* {@code && snippet.kind() == Kind.VARIABLE} |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
592 |
* and cast to {@code VarSnippet}. |
33362 | 593 |
* @return the active declared variables. |
594 |
*/ |
|
40515
819fc588bd19
8164277: JShell API: Snippets are immutable and should be available for post-mortem analysis
rfield
parents:
40304
diff
changeset
|
595 |
public Stream<VarSnippet> variables() { |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
596 |
return snippets() |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
597 |
.filter(sn -> status(sn).isActive() && sn.kind() == Snippet.Kind.VAR) |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
598 |
.map(sn -> (VarSnippet) sn); |
33362 | 599 |
} |
600 |
||
601 |
/** |
|
602 |
* Returns the active method snippets. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
603 |
* This convenience method is equivalent to {@code snippets()} filtered for |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
604 |
* {@link jdk.jshell.Snippet.Status#isActive() status(snippet).isActive()} |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
605 |
* {@code && snippet.kind() == Kind.METHOD} |
33362 | 606 |
* and cast to MethodSnippet. |
607 |
* @return the active declared methods. |
|
608 |
*/ |
|
40515
819fc588bd19
8164277: JShell API: Snippets are immutable and should be available for post-mortem analysis
rfield
parents:
40304
diff
changeset
|
609 |
public Stream<MethodSnippet> methods() { |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
610 |
return snippets() |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
611 |
.filter(sn -> status(sn).isActive() && sn.kind() == Snippet.Kind.METHOD) |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
612 |
.map(sn -> (MethodSnippet)sn); |
33362 | 613 |
} |
614 |
||
615 |
/** |
|
616 |
* Returns the active type declaration (class, interface, annotation type, and enum) snippets. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
617 |
* This convenience method is equivalent to {@code snippets()} filtered for |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
618 |
* {@link jdk.jshell.Snippet.Status#isActive() status(snippet).isActive()} |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
619 |
* {@code && snippet.kind() == Kind.TYPE_DECL} |
33362 | 620 |
* and cast to TypeDeclSnippet. |
621 |
* @return the active declared type declarations. |
|
622 |
*/ |
|
40515
819fc588bd19
8164277: JShell API: Snippets are immutable and should be available for post-mortem analysis
rfield
parents:
40304
diff
changeset
|
623 |
public Stream<TypeDeclSnippet> types() { |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
624 |
return snippets() |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
625 |
.filter(sn -> status(sn).isActive() && sn.kind() == Snippet.Kind.TYPE_DECL) |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
626 |
.map(sn -> (TypeDeclSnippet) sn); |
33362 | 627 |
} |
628 |
||
629 |
/** |
|
33714
8064f484590e
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
shinyafox
parents:
33362
diff
changeset
|
630 |
* Returns the active import snippets. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
631 |
* This convenience method is equivalent to {@code snippets()} filtered for |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
632 |
* {@link jdk.jshell.Snippet.Status#isActive() status(snippet).isActive()} |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
633 |
* {@code && snippet.kind() == Kind.IMPORT} |
33714
8064f484590e
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
shinyafox
parents:
33362
diff
changeset
|
634 |
* and cast to ImportSnippet. |
8064f484590e
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
shinyafox
parents:
33362
diff
changeset
|
635 |
* @return the active declared import declarations. |
8064f484590e
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
shinyafox
parents:
33362
diff
changeset
|
636 |
*/ |
40515
819fc588bd19
8164277: JShell API: Snippets are immutable and should be available for post-mortem analysis
rfield
parents:
40304
diff
changeset
|
637 |
public Stream<ImportSnippet> imports() { |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
638 |
return snippets() |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
639 |
.filter(sn -> status(sn).isActive() && sn.kind() == Snippet.Kind.IMPORT) |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
640 |
.map(sn -> (ImportSnippet) sn); |
33714
8064f484590e
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
shinyafox
parents:
33362
diff
changeset
|
641 |
} |
8064f484590e
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
shinyafox
parents:
33362
diff
changeset
|
642 |
|
8064f484590e
8142384: JShell tool: New command: /imports, /i which show the list of imported packages or classes, etc...
shinyafox
parents:
33362
diff
changeset
|
643 |
/** |
33362 | 644 |
* Return the status of the snippet. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
645 |
* This is updated either because of an explicit {@code eval()} call or |
33362 | 646 |
* an automatic update triggered by a dependency. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
647 |
* @param snippet the {@code Snippet} to look up |
33362 | 648 |
* @return the status corresponding to this snippet |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
649 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 650 |
* @throws IllegalArgumentException if the snippet is not associated with |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
651 |
* this {@code JShell} instance. |
33362 | 652 |
*/ |
653 |
public Status status(Snippet snippet) { |
|
654 |
return checkValidSnippet(snippet).status(); |
|
655 |
} |
|
656 |
||
657 |
/** |
|
658 |
* Return the diagnostics of the most recent evaluation of the snippet. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
659 |
* The evaluation can either because of an explicit {@code eval()} call or |
33362 | 660 |
* an automatic update triggered by a dependency. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
661 |
* @param snippet the {@code Snippet} to look up |
33362 | 662 |
* @return the diagnostics corresponding to this snippet. This does not |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
663 |
* include unresolvedDependencies references reported in {@code unresolvedDependencies()}. |
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
664 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 665 |
* @throws IllegalArgumentException if the snippet is not associated with |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
666 |
* this {@code JShell} instance. |
33362 | 667 |
*/ |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
668 |
public Stream<Diag> diagnostics(Snippet snippet) { |
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
669 |
return checkValidSnippet(snippet).diagnostics().stream(); |
33362 | 670 |
} |
671 |
||
672 |
/** |
|
673 |
* For {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} or |
|
674 |
* {@link jdk.jshell.Snippet.Status#RECOVERABLE_NOT_DEFINED RECOVERABLE_NOT_DEFINED} |
|
675 |
* declarations, the names of current unresolved dependencies for |
|
676 |
* the snippet. |
|
677 |
* The returned value of this method, for a given method may change when an |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
678 |
* {@code eval()} or {@code drop()} of another snippet causes |
33362 | 679 |
* an update of a dependency. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
680 |
* @param snippet the declaration {@code Snippet} to look up |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
681 |
* @return a stream of symbol names that are currently unresolvedDependencies. |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
682 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 683 |
* @throws IllegalArgumentException if the snippet is not associated with |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
684 |
* this {@code JShell} instance. |
33362 | 685 |
*/ |
40304
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
686 |
public Stream<String> unresolvedDependencies(DeclarationSnippet snippet) { |
0318f4e75c6d
8143964: JShell API: convert query responses to Stream instead of List
rfield
parents:
39807
diff
changeset
|
687 |
return checkValidSnippet(snippet).unresolved().stream(); |
33362 | 688 |
} |
689 |
||
690 |
/** |
|
691 |
* Get the current value of a variable. |
|
692 |
* @param snippet the variable Snippet whose value is queried. |
|
693 |
* @return the current value of the variable referenced by snippet. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
694 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 695 |
* @throws IllegalArgumentException if the snippet is not associated with |
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
696 |
* this {@code JShell} instance. |
33362 | 697 |
* @throws IllegalArgumentException if the variable's status is anything but |
698 |
* {@link jdk.jshell.Snippet.Status#VALID}. |
|
699 |
*/ |
|
700 |
public String varValue(VarSnippet snippet) throws IllegalStateException { |
|
701 |
checkIfAlive(); |
|
702 |
checkValidSnippet(snippet); |
|
703 |
if (snippet.status() != Status.VALID) { |
|
36990 | 704 |
throw new IllegalArgumentException( |
705 |
messageFormat("jshell.exc.var.not.valid", snippet, snippet.status())); |
|
33362 | 706 |
} |
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
707 |
String value; |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
708 |
try { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
709 |
value = executionControl().varValue(snippet.classFullName(), snippet.name()); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
710 |
} catch (EngineTerminationException ex) { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
711 |
throw new IllegalStateException(ex.getMessage()); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
712 |
} catch (ExecutionControlException ex) { |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
713 |
debug(ex, "In varValue()"); |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
714 |
return "[" + ex.getMessage() + "]"; |
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
715 |
} |
33362 | 716 |
return expunge(value); |
717 |
} |
|
718 |
||
719 |
/** |
|
720 |
* Register a callback to be called when the Status of a snippet changes. |
|
721 |
* Each call adds a new subscription. |
|
722 |
* @param listener Action to perform when the Status changes. |
|
723 |
* @return A token which can be used to {@linkplain JShell#unsubscribe unsubscribe} this subscription. |
|
38908
f0c186d76c8a
8139829: JShell API: No use of fields to return information from public types
rfield
parents:
38836
diff
changeset
|
724 |
* @throws IllegalStateException if this {@code JShell} instance is closed. |
33362 | 725 |
*/ |
726 |
public Subscription onSnippetEvent(Consumer<SnippetEvent> listener) |
|
727 |
throws IllegalStateException { |
|
728 |
return onX(keyStatusListeners, listener); |
|
729 |
} |
|
730 |
||
731 |
/** |
|
732 |
* Register a callback to be called when this JShell instance terminates. |
|
733 |
* This occurs either because the client process has ended (e.g. called System.exit(0)) |
|
734 |
* or the connection has been shutdown, as by close(). |
|
735 |
* Each call adds a new subscription. |
|
736 |
* @param listener Action to perform when the state terminates. |
|
737 |
* @return A token which can be used to {@linkplain JShell#unsubscribe unsubscribe} this subscription. |
|
738 |
* @throws IllegalStateException if this JShell instance is closed |
|
739 |
*/ |
|
740 |
public Subscription onShutdown(Consumer<JShell> listener) |
|
741 |
throws IllegalStateException { |
|
742 |
return onX(shutdownListeners, listener); |
|
743 |
} |
|
744 |
||
745 |
/** |
|
746 |
* Cancel a callback subscription. |
|
747 |
* @param token The token corresponding to the subscription to be unsubscribed. |
|
748 |
*/ |
|
749 |
public void unsubscribe(Subscription token) { |
|
750 |
synchronized (this) { |
|
751 |
token.remover.accept(token); |
|
752 |
} |
|
753 |
} |
|
754 |
||
755 |
/** |
|
756 |
* Subscription is a token for referring to subscriptions so they can |
|
757 |
* be {@linkplain JShell#unsubscribe unsubscribed}. |
|
758 |
*/ |
|
759 |
public class Subscription { |
|
760 |
||
761 |
Consumer<Subscription> remover; |
|
762 |
||
763 |
Subscription(Consumer<Subscription> remover) { |
|
764 |
this.remover = remover; |
|
765 |
} |
|
766 |
} |
|
767 |
||
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
768 |
/** |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
769 |
* Provide the environment for a execution engine. |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
770 |
*/ |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
771 |
class ExecutionEnvImpl implements ExecutionEnv { |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
772 |
|
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
773 |
@Override |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
774 |
public InputStream userIn() { |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
775 |
return in; |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
776 |
} |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
777 |
|
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
778 |
@Override |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
779 |
public PrintStream userOut() { |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
780 |
return out; |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
781 |
} |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
782 |
|
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
783 |
@Override |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
784 |
public PrintStream userErr() { |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
785 |
return err; |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
786 |
} |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
787 |
|
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
788 |
@Override |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
789 |
public List<String> extraRemoteVMOptions() { |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
790 |
return extraRemoteVMOptions; |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
791 |
} |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
792 |
|
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
793 |
@Override |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
794 |
public void closeDown() { |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
795 |
JShell.this.closeDown(); |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
796 |
} |
39807
ba0ff343d241
8160127: JShell API: extract abstract JDI and abstract streaming implementations of ExecutionControl
rfield
parents:
39370
diff
changeset
|
797 |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
798 |
} |
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
799 |
|
33362 | 800 |
// --- private / package-private implementation support --- |
42272
82e273c4f2b3
8169519: JShell: Handle start-up failures and hangs gracefully
rfield
parents:
41941
diff
changeset
|
801 |
|
33362 | 802 |
ExecutionControl executionControl() { |
803 |
return executionControl; |
|
804 |
} |
|
805 |
||
806 |
void debug(int flags, String format, Object... args) { |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
807 |
InternalDebugControl.debug(this, err, flags, format, args); |
33362 | 808 |
} |
809 |
||
810 |
void debug(Exception ex, String where) { |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
811 |
InternalDebugControl.debug(this, err, ex, where); |
33362 | 812 |
} |
813 |
||
814 |
/** |
|
815 |
* Generate the next key index, indicating a unique snippet signature. |
|
38535
4a25025e0b0d
8156101: JShell SPI: Provide a pluggable execution control SPI
rfield
parents:
37745
diff
changeset
|
816 |
* |
33362 | 817 |
* @return the next key index |
818 |
*/ |
|
819 |
int nextKeyIndex() { |
|
820 |
return nextKeyIndex++; |
|
821 |
} |
|
822 |
||
823 |
private synchronized <T> Subscription onX(Map<Subscription, Consumer<T>> map, Consumer<T> listener) |
|
824 |
throws IllegalStateException { |
|
825 |
Objects.requireNonNull(listener); |
|
826 |
checkIfAlive(); |
|
827 |
Subscription token = new Subscription(map::remove); |
|
828 |
map.put(token, listener); |
|
829 |
return token; |
|
830 |
} |
|
831 |
||
832 |
private synchronized void notifyKeyStatusEvent(SnippetEvent event) { |
|
833 |
keyStatusListeners.values().forEach(l -> l.accept(event)); |
|
834 |
} |
|
835 |
||
836 |
private synchronized void notifyShutdownEvent(JShell state) { |
|
837 |
shutdownListeners.values().forEach(l -> l.accept(state)); |
|
838 |
} |
|
839 |
||
840 |
void closeDown() { |
|
841 |
if (!closed) { |
|
842 |
// Send only once |
|
843 |
closed = true; |
|
38836
b09d1cfbf28c
8131029: JShell: recover from VMConnection launch failure
rfield
parents:
38535
diff
changeset
|
844 |
try { |
b09d1cfbf28c
8131029: JShell: recover from VMConnection launch failure
rfield
parents:
38535
diff
changeset
|
845 |
notifyShutdownEvent(this); |
b09d1cfbf28c
8131029: JShell: recover from VMConnection launch failure
rfield
parents:
38535
diff
changeset
|
846 |
} catch (Throwable thr) { |
b09d1cfbf28c
8131029: JShell: recover from VMConnection launch failure
rfield
parents:
38535
diff
changeset
|
847 |
// Don't care about dying exceptions |
b09d1cfbf28c
8131029: JShell: recover from VMConnection launch failure
rfield
parents:
38535
diff
changeset
|
848 |
} |
43757 | 849 |
try { |
850 |
executionControl().close(); |
|
851 |
} catch (Throwable ex) { |
|
852 |
// don't care about exceptions on close |
|
853 |
} |
|
854 |
if (sourceCodeAnalysis != null) { |
|
855 |
sourceCodeAnalysis.close(); |
|
856 |
} |
|
857 |
InternalDebugControl.release(this); |
|
33362 | 858 |
} |
859 |
} |
|
860 |
||
861 |
/** |
|
862 |
* Check if this JShell has been closed |
|
863 |
* @throws IllegalStateException if it is closed |
|
864 |
*/ |
|
865 |
private void checkIfAlive() throws IllegalStateException { |
|
866 |
if (closed) { |
|
36990 | 867 |
throw new IllegalStateException(messageFormat("jshell.exc.closed", this)); |
33362 | 868 |
} |
869 |
} |
|
870 |
||
871 |
/** |
|
872 |
* Check a Snippet parameter coming from the API user |
|
873 |
* @param sn the Snippet to check |
|
874 |
* @throws NullPointerException if Snippet parameter is null |
|
875 |
* @throws IllegalArgumentException if Snippet is not from this JShell |
|
876 |
* @return the input Snippet (for chained calls) |
|
877 |
*/ |
|
878 |
private Snippet checkValidSnippet(Snippet sn) { |
|
879 |
if (sn == null) { |
|
36990 | 880 |
throw new NullPointerException(messageFormat("jshell.exc.null")); |
33362 | 881 |
} else { |
882 |
if (sn.key().state() != this) { |
|
36990 | 883 |
throw new IllegalArgumentException(messageFormat("jshell.exc.alien")); |
33362 | 884 |
} |
885 |
return sn; |
|
886 |
} |
|
887 |
} |
|
888 |
||
36990 | 889 |
/** |
890 |
* Format using resource bundle look-up using MessageFormat |
|
891 |
* |
|
892 |
* @param key the resource key |
|
893 |
* @param args |
|
894 |
*/ |
|
895 |
String messageFormat(String key, Object... args) { |
|
896 |
if (outputRB == null) { |
|
897 |
try { |
|
898 |
outputRB = ResourceBundle.getBundle(L10N_RB_NAME); |
|
899 |
} catch (MissingResourceException mre) { |
|
900 |
throw new InternalError("Cannot find ResourceBundle: " + L10N_RB_NAME); |
|
901 |
} |
|
902 |
} |
|
903 |
String s; |
|
904 |
try { |
|
905 |
s = outputRB.getString(key); |
|
906 |
} catch (MissingResourceException mre) { |
|
907 |
throw new InternalError("Missing resource: " + key + " in " + L10N_RB_NAME); |
|
908 |
} |
|
909 |
return MessageFormat.format(s, args); |
|
910 |
} |
|
911 |
||
33362 | 912 |
} |