28 import jdk.jshell.spi.ExecutionControl; |
28 import jdk.jshell.spi.ExecutionControl; |
29 import java.io.ByteArrayInputStream; |
29 import java.io.ByteArrayInputStream; |
30 import java.io.InputStream; |
30 import java.io.InputStream; |
31 import java.io.InterruptedIOException; |
31 import java.io.InterruptedIOException; |
32 import java.io.PrintStream; |
32 import java.io.PrintStream; |
|
33 import java.net.InetAddress; |
33 import java.text.MessageFormat; |
34 import java.text.MessageFormat; |
34 import java.util.ArrayList; |
35 import java.util.ArrayList; |
35 import java.util.Arrays; |
36 import java.util.Arrays; |
36 import java.util.Collections; |
37 import java.util.Collections; |
37 import java.util.HashMap; |
38 import java.util.HashMap; |
90 final PrintStream err; |
91 final PrintStream err; |
91 final Supplier<String> tempVariableNameGenerator; |
92 final Supplier<String> tempVariableNameGenerator; |
92 final BiFunction<Snippet, Integer, String> idGenerator; |
93 final BiFunction<Snippet, Integer, String> idGenerator; |
93 final List<String> extraRemoteVMOptions; |
94 final List<String> extraRemoteVMOptions; |
94 final List<String> extraCompilerOptions; |
95 final List<String> extraCompilerOptions; |
95 final ExecutionControl.Generator executionControlGenerator; |
|
96 |
96 |
97 private int nextKeyIndex = 1; |
97 private int nextKeyIndex = 1; |
98 |
98 |
99 final Eval eval; |
99 final Eval eval; |
100 final ClassTracker classTracker; |
100 final ClassTracker classTracker; |
101 private final Map<Subscription, Consumer<JShell>> shutdownListeners = new HashMap<>(); |
101 private final Map<Subscription, Consumer<JShell>> shutdownListeners = new HashMap<>(); |
102 private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>(); |
102 private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>(); |
103 private boolean closed = false; |
103 private boolean closed = false; |
104 |
104 |
105 private ExecutionControl executionControl = null; |
105 private final ExecutionControl executionControl; |
106 private SourceCodeAnalysisImpl sourceCodeAnalysis = null; |
106 private SourceCodeAnalysisImpl sourceCodeAnalysis = null; |
107 |
107 |
108 private static final String L10N_RB_NAME = "jdk.jshell.resources.l10n"; |
108 private static final String L10N_RB_NAME = "jdk.jshell.resources.l10n"; |
109 private static ResourceBundle outputRB = null; |
109 private static ResourceBundle outputRB = null; |
110 |
110 |
111 JShell(Builder b) { |
111 JShell(Builder b) throws IllegalStateException { |
112 this.in = b.in; |
112 this.in = b.in; |
113 this.out = b.out; |
113 this.out = b.out; |
114 this.err = b.err; |
114 this.err = b.err; |
115 this.tempVariableNameGenerator = b.tempVariableNameGenerator; |
115 this.tempVariableNameGenerator = b.tempVariableNameGenerator; |
116 this.idGenerator = b.idGenerator; |
116 this.idGenerator = b.idGenerator; |
117 this.extraRemoteVMOptions = b.extraRemoteVMOptions; |
117 this.extraRemoteVMOptions = b.extraRemoteVMOptions; |
118 this.extraCompilerOptions = b.extraCompilerOptions; |
118 this.extraCompilerOptions = b.extraCompilerOptions; |
119 this.executionControlGenerator = b.executionControlGenerator==null |
119 ExecutionControl.Generator executionControlGenerator = b.executionControlGenerator==null |
120 ? failOverExecutionControlGenerator(JdiDefaultExecutionControl.launch(), |
120 ? failOverExecutionControlGenerator( |
121 JdiDefaultExecutionControl.listen("localhost"), |
121 JdiDefaultExecutionControl.listen(InetAddress.getLoopbackAddress().getHostAddress()), |
122 JdiDefaultExecutionControl.listen(null)) |
122 JdiDefaultExecutionControl.launch(), |
|
123 JdiDefaultExecutionControl.listen(null) |
|
124 ) |
123 : b.executionControlGenerator; |
125 : b.executionControlGenerator; |
|
126 try { |
|
127 executionControl = executionControlGenerator.generate(new ExecutionEnvImpl()); |
|
128 } catch (Throwable ex) { |
|
129 throw new IllegalStateException("Launching JShell execution engine threw: " + ex.getMessage(), ex); |
|
130 } |
124 |
131 |
125 this.maps = new SnippetMaps(this); |
132 this.maps = new SnippetMaps(this); |
126 this.keyMap = new KeyMap(this); |
133 this.keyMap = new KeyMap(this); |
127 this.outerMap = new OuterWrapMap(this); |
134 this.outerMap = new OuterWrapMap(this); |
128 this.taskFactory = new TaskFactory(this); |
135 this.taskFactory = new TaskFactory(this); |
329 /** |
336 /** |
330 * Builds a JShell state engine. This is the entry-point to all JShell |
337 * Builds a JShell state engine. This is the entry-point to all JShell |
331 * functionality. This creates a remote process for execution. It is |
338 * functionality. This creates a remote process for execution. It is |
332 * thus important to close the returned instance. |
339 * thus important to close the returned instance. |
333 * |
340 * |
|
341 * @throws IllegalStateException if the {@code JShell} instance could not be created. |
334 * @return the state engine |
342 * @return the state engine |
335 */ |
343 */ |
336 public JShell build() { |
344 public JShell build() throws IllegalStateException { |
337 return new JShell(this); |
345 return new JShell(this); |
338 } |
346 } |
339 } |
347 } |
340 |
348 |
341 // --- public API --- |
349 // --- public API --- |
343 /** |
351 /** |
344 * Create a new JShell state engine. |
352 * Create a new JShell state engine. |
345 * That is, create an instance of {@code JShell}. |
353 * That is, create an instance of {@code JShell}. |
346 * <p> |
354 * <p> |
347 * Equivalent to {@link JShell#builder() JShell.builder()}{@link JShell.Builder#build() .build()}. |
355 * Equivalent to {@link JShell#builder() JShell.builder()}{@link JShell.Builder#build() .build()}. |
|
356 * @throws IllegalStateException if the {@code JShell} instance could not be created. |
348 * @return an instance of {@code JShell}. |
357 * @return an instance of {@code JShell}. |
349 */ |
358 */ |
350 public static JShell create() { |
359 public static JShell create() throws IllegalStateException { |
351 return builder().build(); |
360 return builder().build(); |
352 } |
361 } |
353 |
362 |
354 /** |
363 /** |
355 * Factory method for {@code JShell.Builder} which, in-turn, is used |
364 * Factory method for {@code JShell.Builder} which, in-turn, is used |
456 /** |
465 /** |
457 * The specified path is added to the end of the classpath used in eval(). |
466 * The specified path is added to the end of the classpath used in eval(). |
458 * Note that the unnamed package is not accessible from the package in which |
467 * Note that the unnamed package is not accessible from the package in which |
459 * {@link JShell#eval(String)} code is placed. |
468 * {@link JShell#eval(String)} code is placed. |
460 * @param path the path to add to the classpath. |
469 * @param path the path to add to the classpath. |
|
470 * @throws IllegalStateException if this {@code JShell} instance is closed. |
461 */ |
471 */ |
462 public void addToClasspath(String path) { |
472 public void addToClasspath(String path) { |
463 // Compiler |
473 // Compiler |
464 taskFactory.addToClasspath(path); |
474 taskFactory.addToClasspath(path); |
465 // Runtime |
475 // Runtime |
731 } |
745 } |
732 |
746 |
733 } |
747 } |
734 |
748 |
735 // --- private / package-private implementation support --- |
749 // --- private / package-private implementation support --- |
|
750 |
736 ExecutionControl executionControl() { |
751 ExecutionControl executionControl() { |
737 if (executionControl == null) { |
|
738 try { |
|
739 executionControl = executionControlGenerator.generate(new ExecutionEnvImpl()); |
|
740 } catch (Throwable ex) { |
|
741 throw new InternalError("Launching execution engine threw: " + ex.getMessage(), ex); |
|
742 } |
|
743 } |
|
744 return executionControl; |
752 return executionControl; |
745 } |
753 } |
746 |
754 |
747 void debug(int flags, String format, Object... args) { |
755 void debug(int flags, String format, Object... args) { |
748 InternalDebugControl.debug(this, err, flags, format, args); |
756 InternalDebugControl.debug(this, err, flags, format, args); |