src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java
Print this page
@@ -20,135 +20,249 @@
*
* 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.Collection;
-import jdk.jshell.JShellException;
+import java.io.Serializable;
/**
- * This interface specifies the functionality that must provided to implement
- * a pluggable JShell execution engine.
+ * This interface specifies the functionality that must provided to implement a
+ * pluggable JShell execution engine.
* <p>
- * The audience for this Service Provider Interface is engineers
- * wishing to implement their own version of the execution engine in support
- * of the JShell API. This is NOT a part of the JShell API.
+ * The audience for this Service Provider Interface is engineers wishing to
+ * implement their own version of the execution engine in support of the JShell
+ * API.
* <p>
* A Snippet is compiled into code wrapped in a 'wrapper class'. The execution
- * engine is used by the core JShell implementation to load and, for
- * executable Snippets, execute the Snippet.
+ * engine is used by the core JShell implementation to load and, for executable
+ * Snippets, execute the Snippet.
* <p>
* Methods defined in this interface should only be called by the core JShell
* implementation.
* <p>
- * To install an instance of ExecutionControl, it is passed to
- * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl) }.
+ * To install an {@code ExecutionControl}, it's {@code Generator} is passed to
+ * {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator) }.
*/
public interface ExecutionControl {
- /**
- * Represents the current status of a class in the execution engine.
- */
- public enum ClassStatus {
- /**
- * Class is not known to the execution engine (not loaded).
- */
- UNKNOWN,
+ public interface Generator {
+ ExecutionControl generate(ExecutionEnv env) throws Throwable;
+ }
/**
- * Class is loaded, but the loaded/redefined bytes do not match those
- * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }.
+ * Attempts to load new classes.
+ *
+ * @param cbcs the class name and bytecodes to load
+ * @throws ClassInstallException exception occurred loading the classes,
+ * some or all were not loaded
+ * @throws EngineTerminationException the execution engine has terminated
*/
- NOT_CURRENT,
+ void load(ClassBytecodes[] cbcs)
+ throws ClassInstallException, EngineTerminationException;
/**
- * Class is loaded and loaded/redefined bytes match those
- * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }.
+ * Attempts to redefine previously loaded classes.
+ *
+ * @param cbcs the class name and bytecodes to redefine
+ * @throws ClassInstallException exception occurred redefining the classes,
+ * some or all were not redefined
+ * @throws EngineTerminationException the execution engine has terminated
*/
- CURRENT
- };
+ void redefine(ClassBytecodes[] cbcs)
+ throws ClassInstallException, EngineTerminationException;
/**
- * Initializes the instance. No methods in this interface can be called
- * before this.
+ * Invokes an executable Snippet by calling a method on the specified
+ * wrapper class. The method must have no arguments and return String.
*
- * @param env the execution environment information provided by JShell
- * @throws Exception if the instance is unable to initialize
- */
- void start(ExecutionEnv env) throws Exception;
+ * @param className the class whose method should be invoked
+ * @param methodName the name of method to invoke
+ * @return the result of the execution or null if no result
+ * @throws UserException the invoke raised a user exception
+ * @throws ResolutionException the invoke attempted to directly or
+ * indirectly invoke an unresolved snippet
+ * @throws StoppedException if the {@code invoke()} was canceled by
+ * {@link ExecutionControl#stop}
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ String invoke(String className, String methodName)
+ throws RunException,
+ EngineTerminationException, InternalException;
/**
- * Shuts down this execution engine. Implementation should free all
- * resources held by this execution engine.
- * <p>
- * No calls to methods on this interface should be made after close.
- */
- void close();
+ * Returns the value of a variable.
+ *
+ * @param className the name of the wrapper class of the variable
+ * @param varName the name of the variable
+ * @return the value of the variable
+ * @throws UserException formatting the value raised a user exception
+ * @throws ResolutionException formatting the value attempted to directly or
+ * indirectly invoke an unresolved snippet
+ * @throws StoppedException if the formatting the value was canceled by
+ * {@link ExecutionControl#stop}
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ String varValue(String className, String varName)
+ throws RunException,
+ EngineTerminationException, InternalException;
/**
* Adds the path to the execution class path.
*
* @param path the path to add
- * @return true if successful
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
*/
- boolean addToClasspath(String path);
+ void addToClasspath(String path)
+ throws EngineTerminationException, InternalException;
/**
- * Invokes an executable Snippet by calling a method on the specified
- * wrapper class. The method must have no arguments and return String.
+ * Sets the execution class path to the specified path.
*
- * @param classname the class whose method should be invoked
- * @param methodname the name of method to invoke
- * @return the result of the execution or null if no result
- * @throws JShellException if a user exception if thrown,
- * {@link jdk.jshell.EvalException EvalException} will be thrown; if an
- * unresolved reference is encountered,
- * {@link jdk.jshell.UnresolvedReferenceException UnresolvedReferenceException}
- * will be thrown
+ * @param path the path to add
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
*/
- String invoke(String classname, String methodname) throws JShellException;
+ void setClasspath(String path)
+ throws EngineTerminationException, InternalException;
/**
- * Attempts to load new classes. Class bytes are retrieved from
- * {@link ExecutionEnv#getClassBytes(java.lang.String) }
+ * Interrupts a running invoke.
*
- * @param classes list of class names to load
- * @return true if load succeeded
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
*/
- boolean load(Collection<String> classes);
+ void stop()
+ throws EngineTerminationException, InternalException;
/**
- * Attempts to redefine previously loaded classes. Class bytes are retrieved
- * from {@link ExecutionEnv#getClassBytes(java.lang.String) }
- *
- * @param classes list of class names to redefine
- * @return true if redefine succeeded
+ * Shuts down this execution engine. Implementation should free all
+ * resources held by this execution engine.
+ * <p>
+ * No calls to methods on this interface should be made after close.
*/
- boolean redefine(Collection<String> classes);
+ void close();
+
+ public static final class ClassBytecodes implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public ClassBytecodes(String name, byte[] bytecodes) {
+ this.name = name;
+ this.bytecodes = bytecodes;
+ }
+ public final String name;
+ public final byte[] bytecodes;
+ }
+
+ @SuppressWarnings("serial")
+ public static abstract class ExecutionControlException extends Exception {
+
+ public ExecutionControlException(String message) {
+ super(message);
+ }
+ }
/**
- * Queries if the class is loaded and the class bytes are current.
- *
- * @param classname name of the wrapper class to query
- * @return {@code UNKNOWN} if the class is not loaded; {@code CURRENT} if
- * the loaded/redefined bytes are equal to the most recent bytes for this
- * wrapper class; otherwise {@code NOT_CURRENT}
+ * Unbidden execution engine termination has occurred.
*/
- ClassStatus getClassStatus(String classname);
+ @SuppressWarnings("serial")
+ public static class EngineTerminationException extends ExecutionControlException {
+
+ public EngineTerminationException(String message) {
+ super(message);
+ System.err.printf("EngineTerminationException: %s\n", message);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class InternalException extends ExecutionControlException {
+
+ public InternalException(String message) {
+ super(message);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class ClassInstallException extends ExecutionControlException {
+
+ private final boolean[] installed;
+
+ public ClassInstallException(String message, boolean[] installed) {
+ super(message);
+ this.installed = installed;
+ }
+
+ public boolean[] installed() {
+ return installed;
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static abstract class RunException extends ExecutionControlException {
+
+ private RunException(String message) {
+ super(message);
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static class UserException extends RunException {
+
+ private final String causeExceptionClass;
+
+ public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) {
+ super(message);
+ this.causeExceptionClass = causeExceptionClass;
+ this.setStackTrace(stackElements);
+ }
+
+ public String causeExceptionClass() {
+ return causeExceptionClass;
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static class ResolutionException extends RunException {
+
+ private final int id;
/**
- * Interrupt a running invoke.
+ * Constructs an exception indicating that a
+ * {@code DeclarationSnippet} with unresolved references has been
+ * encountered. The throw of this exception is generated into the body
+ * of a
+ * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED}
+ * method.
+ *
+ * @param id An internal identifier of the specific method
+ * @param stackElements the stack trace
*/
- void stop();
+ public ResolutionException(int id, StackTraceElement[] stackElements) {
+ super("resolution exception: " + id);
+ this.id = id;
+ this.setStackTrace(stackElements);
+ }
/**
- * Returns the value of a variable.
+ * Retrieves the internal identifier of the unresolved identifier.
*
- * @param classname the name of the wrapper class of the variable
- * @param varname the name of the variable
- * @return the value of the variable
+ * @return the internal identifier
*/
- String varValue(String classname, String varname);
+ public int id() {
+ return id;
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static class StoppedException extends RunException {
+
+ public StoppedException() {
+ super("stopped by stop()");
+ }
+ }
+
}