1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 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 package jdk.jshell.spi; 26 27 import java.io.Serializable; 28 29 /** 30 * This interface specifies the functionality that must provided to implement a 31 * pluggable JShell execution engine. 32 * <p> 33 * The audience for this Service Provider Interface is engineers wishing to 34 * implement their own version of the execution engine in support of the JShell 35 * API. 36 * <p> 37 * A Snippet is compiled into code wrapped in a 'wrapper class'. The execution 38 * engine is used by the core JShell implementation to load and, for executable 39 * Snippets, execute the Snippet. 40 * <p> 41 * Methods defined in this interface should only be called by the core JShell 42 * implementation. 43 * <p> 44 * To install an {@code ExecutionControl}, it's {@code Generator} is passed to 45 * {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator) }. 46 */ 47 public interface ExecutionControl { 48 49 public interface Generator { 50 ExecutionControl generate(ExecutionEnv env) throws Throwable; 51 } 52 53 /** 54 * Attempts to load new classes. 55 * 56 * @param cbcs the class name and bytecodes to load 57 * @throws ClassInstallException exception occurred loading the classes, 58 * some or all were not loaded 59 * @throws EngineTerminationException the execution engine has terminated 60 */ 61 void load(ClassBytecodes[] cbcs) 62 throws ClassInstallException, EngineTerminationException; 63 64 /** 65 * Attempts to redefine previously loaded classes. 66 * 67 * @param cbcs the class name and bytecodes to redefine 68 * @throws ClassInstallException exception occurred redefining the classes, 69 * some or all were not redefined 70 * @throws EngineTerminationException the execution engine has terminated 71 */ 72 void redefine(ClassBytecodes[] cbcs) 73 throws ClassInstallException, EngineTerminationException; 74 75 /** 76 * Invokes an executable Snippet by calling a method on the specified 77 * wrapper class. The method must have no arguments and return String. 78 * 79 * @param className the class whose method should be invoked 80 * @param methodName the name of method to invoke 81 * @return the result of the execution or null if no result 82 * @throws UserException the invoke raised a user exception 83 * @throws ResolutionException the invoke attempted to directly or 84 * indirectly invoke an unresolved snippet 85 * @throws StoppedException if the {@code invoke()} was canceled by 86 * {@link ExecutionControl#stop} 87 * @throws EngineTerminationException the execution engine has terminated 88 * @throws InternalException an internal problem occurred 89 */ 90 String invoke(String className, String methodName) 91 throws RunException, 92 EngineTerminationException, InternalException; 93 94 /** 95 * Returns the value of a variable. 96 * 97 * @param className the name of the wrapper class of the variable 98 * @param varName the name of the variable 99 * @return the value of the variable 100 * @throws UserException formatting the value raised a user exception 101 * @throws ResolutionException formatting the value attempted to directly or 102 * indirectly invoke an unresolved snippet 103 * @throws StoppedException if the formatting the value was canceled by 104 * {@link ExecutionControl#stop} 105 * @throws EngineTerminationException the execution engine has terminated 106 * @throws InternalException an internal problem occurred 107 */ 108 String varValue(String className, String varName) 109 throws RunException, 110 EngineTerminationException, InternalException; 111 112 /** 113 * Adds the path to the execution class path. 114 * 115 * @param path the path to add 116 * @throws EngineTerminationException the execution engine has terminated 117 * @throws InternalException an internal problem occurred 118 */ 119 void addToClasspath(String path) 120 throws EngineTerminationException, InternalException; 121 122 /** 123 * Sets the execution class path to the specified path. 124 * 125 * @param path the path to add 126 * @throws EngineTerminationException the execution engine has terminated 127 * @throws InternalException an internal problem occurred 128 */ 129 void setClasspath(String path) 130 throws EngineTerminationException, InternalException; 131 132 /** 133 * Interrupts a running invoke. 134 * 135 * @throws EngineTerminationException the execution engine has terminated 136 * @throws InternalException an internal problem occurred 137 */ 138 void stop() 139 throws EngineTerminationException, InternalException; 140 141 /** 142 * Shuts down this execution engine. Implementation should free all 143 * resources held by this execution engine. 144 * <p> 145 * No calls to methods on this interface should be made after close. 146 */ 147 void close(); 148 149 public static final class ClassBytecodes implements Serializable { 150 151 private static final long serialVersionUID = 1L; 152 153 public ClassBytecodes(String name, byte[] bytecodes) { 154 this.name = name; 155 this.bytecodes = bytecodes; 156 } 157 public final String name; 158 public final byte[] bytecodes; 159 } 160 161 @SuppressWarnings("serial") 162 public static abstract class ExecutionControlException extends Exception { 163 164 public ExecutionControlException(String message) { 165 super(message); 166 } 167 } 168 169 /** 170 * Unbidden execution engine termination has occurred. 171 */ 172 @SuppressWarnings("serial") 173 public static class EngineTerminationException extends ExecutionControlException { 174 175 public EngineTerminationException(String message) { 176 super(message); 177 System.err.printf("EngineTerminationException: %s\n", message); 178 } 179 } 180 181 @SuppressWarnings("serial") 182 public static class InternalException extends ExecutionControlException { 183 184 public InternalException(String message) { 185 super(message); 186 } 187 } 188 189 @SuppressWarnings("serial") 190 public static class ClassInstallException extends ExecutionControlException { 191 192 private final boolean[] installed; 193 194 public ClassInstallException(String message, boolean[] installed) { 195 super(message); 196 this.installed = installed; 197 } 198 199 public boolean[] installed() { 200 return installed; 201 } 202 } 203 204 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 205 public static abstract class RunException extends ExecutionControlException { 206 207 private RunException(String message) { 208 super(message); 209 } 210 } 211 212 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 213 public static class UserException extends RunException { 214 215 private final String causeExceptionClass; 216 217 public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) { 218 super(message); 219 this.causeExceptionClass = causeExceptionClass; 220 this.setStackTrace(stackElements); 221 } 222 223 public String causeExceptionClass() { 224 return causeExceptionClass; 225 } 226 } 227 228 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 229 public static class ResolutionException extends RunException { 230 231 private final int id; 232 233 /** 234 * Constructs an exception indicating that a 235 * {@code DeclarationSnippet} with unresolved references has been 236 * encountered. The throw of this exception is generated into the body 237 * of a 238 * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} 239 * method. 240 * 241 * @param id An internal identifier of the specific method 242 * @param stackElements the stack trace 243 */ 244 public ResolutionException(int id, StackTraceElement[] stackElements) { 245 super("resolution exception: " + id); 246 this.id = id; 247 this.setStackTrace(stackElements); 248 } 249 250 /** 251 * Retrieves the internal identifier of the unresolved identifier. 252 * 253 * @return the internal identifier 254 */ 255 public int id() { 256 return id; 257 } 258 } 259 260 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 261 public static class StoppedException extends RunException { 262 263 public StoppedException() { 264 super("stopped by stop()"); 265 } 266 } 267 268 }