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}, its {@code Generator} is passed to 45 * {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator) }. 46 */ 47 public interface ExecutionControl { 48 49 /** 50 * Defines a functional interface for creating {@link ExecutionControl} 51 * instances. 52 */ 53 public interface Generator { 54 55 /** 56 * Generates an execution engine, given an execution environment. 57 * 58 * @param env the context in which the {@link ExecutionControl} is to 59 * be created 60 * @return the created instance 61 * @throws Throwable if problems occurred 62 */ 63 ExecutionControl generate(ExecutionEnv env) throws Throwable; 64 } 65 66 /** 67 * Attempts to load new classes. 68 * 69 * @param cbcs the class name and bytecodes to load 70 * @throws ClassInstallException exception occurred loading the classes, 71 * some or all were not loaded 72 * @throws NotImplementedException if not implemented 73 * @throws EngineTerminationException the execution engine has terminated 74 */ 75 void load(ClassBytecodes[] cbcs) 76 throws ClassInstallException, NotImplementedException, EngineTerminationException; 77 78 /** 79 * Attempts to redefine previously loaded classes. 80 * 81 * @param cbcs the class name and bytecodes to redefine 82 * @throws ClassInstallException exception occurred redefining the classes, 83 * some or all were not redefined 84 * @throws NotImplementedException if not implemented 85 * @throws EngineTerminationException the execution engine has terminated 86 */ 87 void redefine(ClassBytecodes[] cbcs) 88 throws ClassInstallException, NotImplementedException, EngineTerminationException; 89 90 /** 91 * Invokes an executable Snippet by calling a method on the specified 92 * wrapper class. The method must have no arguments and return String. 93 * 94 * @param className the class whose method should be invoked 95 * @param methodName the name of method to invoke 96 * @return the result of the execution or null if no result 97 * @throws UserException the invoke raised a user exception 98 * @throws ResolutionException the invoke attempted to directly or 99 * indirectly invoke an unresolved snippet 100 * @throws StoppedException if the {@code invoke()} was canceled by 101 * {@link ExecutionControl#stop} 102 * @throws EngineTerminationException the execution engine has terminated 103 * @throws InternalException an internal problem occurred 104 */ 105 String invoke(String className, String methodName) 106 throws RunException, EngineTerminationException, InternalException; 107 108 /** 109 * Returns the value of a variable. 110 * 111 * @param className the name of the wrapper class of the variable 112 * @param varName the name of the variable 113 * @return the value of the variable 114 * @throws UserException formatting the value raised a user exception 115 * @throws ResolutionException formatting the value attempted to directly or 116 * indirectly invoke an unresolved snippet 117 * @throws StoppedException if the formatting the value was canceled by 118 * {@link ExecutionControl#stop} 119 * @throws EngineTerminationException the execution engine has terminated 120 * @throws InternalException an internal problem occurred 121 */ 122 String varValue(String className, String varName) 123 throws RunException, EngineTerminationException, InternalException; 124 125 /** 126 * Adds the path to the execution class path. 127 * 128 * @param path the path to add 129 * @throws EngineTerminationException the execution engine has terminated 130 * @throws InternalException an internal problem occurred 131 */ 132 void addToClasspath(String path) 133 throws EngineTerminationException, InternalException; 134 135 /** 136 * Sets the execution class path to the specified path. 137 * 138 * @param path the path to add 139 * @throws EngineTerminationException the execution engine has terminated 140 * @throws InternalException an internal problem occurred 141 */ 142 void setClasspath(String path) 143 throws EngineTerminationException, InternalException; 144 145 /** 146 * Interrupts a running invoke. 147 * 148 * @throws EngineTerminationException the execution engine has terminated 149 * @throws InternalException an internal problem occurred 150 */ 151 void stop() 152 throws EngineTerminationException, InternalException; 153 154 /** 155 * Run a non-standard command (or a standard command from a newer version). 156 * 157 * @param command the non-standard command 158 * @param arg the commands argument 159 * @return the commands return value 160 * @throws UserException the command raised a user exception 161 * @throws ResolutionException the command attempted to directly or 162 * indirectly invoke an unresolved snippet 163 * @throws StoppedException if the command was canceled by 164 * {@link ExecutionControl#stop} 165 * @throws EngineTerminationException the execution engine has terminated 166 * @throws NotImplementedException if not implemented 167 * @throws InternalException an internal problem occurred 168 */ 169 Object extensionCommand(String command, Object arg) 170 throws RunException, EngineTerminationException, InternalException; 171 172 /** 173 * Shuts down this execution engine. Implementation should free all 174 * resources held by this execution engine. 175 * <p> 176 * No calls to methods on this interface should be made after close. 177 */ 178 void close(); 179 180 /** 181 * Bundles class name with class bytecodes. 182 */ 183 public static final class ClassBytecodes implements Serializable { 184 185 private static final long serialVersionUID = 0xC1A55B47EC0DE5L; 186 private final String name; 187 private final byte[] bytecodes; 188 189 /** 190 * Creates a name/bytecode pair. 191 * @param name the class name 192 * @param bytecodes the class bytecodes 193 */ 194 public ClassBytecodes(String name, byte[] bytecodes) { 195 this.name = name; 196 this.bytecodes = bytecodes; 197 } 198 199 /** 200 * The bytecodes for the class. 201 * 202 * @return the bytecodes 203 */ 204 public byte[] bytecodes() { 205 return bytecodes; 206 } 207 208 /** 209 * The class name. 210 * 211 * @return the class name 212 */ 213 public String name() { 214 return name; 215 } 216 } 217 218 /** 219 * The abstract base of all {@code ExecutionControl} exceptions. 220 */ 221 public static abstract class ExecutionControlException extends Exception { 222 223 private static final long serialVersionUID = 1L; 224 225 public ExecutionControlException(String message) { 226 super(message); 227 } 228 } 229 230 /** 231 * Unbidden execution engine termination has occurred. 232 */ 233 public static class EngineTerminationException extends ExecutionControlException { 234 235 private static final long serialVersionUID = 1L; 236 237 public EngineTerminationException(String message) { 238 super(message); 239 } 240 } 241 242 /** 243 * The command is not implemented. 244 */ 245 public static class NotImplementedException extends InternalException { 246 247 private static final long serialVersionUID = 1L; 248 249 public NotImplementedException(String message) { 250 super(message); 251 } 252 } 253 254 /** 255 * An internal problem has occurred. 256 */ 257 public static class InternalException extends ExecutionControlException { 258 259 private static final long serialVersionUID = 1L; 260 261 public InternalException(String message) { 262 super(message); 263 } 264 } 265 266 /** 267 * A class install (load or redefine) encountered a problem. 268 */ 269 public static class ClassInstallException extends ExecutionControlException { 270 271 private static final long serialVersionUID = 1L; 272 273 private final boolean[] installed; 274 275 public ClassInstallException(String message, boolean[] installed) { 276 super(message); 277 this.installed = installed; 278 } 279 280 /** 281 * Indicates which of the passed classes were successfully 282 * loaded/redefined. 283 * @return a one-to-one array with the {@link ClassBytecodes}{@code[]} 284 * array -- {@code true} if installed 285 */ 286 public boolean[] installed() { 287 return installed; 288 } 289 } 290 291 /** 292 * The abstract base of of exceptions specific to running user code. 293 */ 294 public static abstract class RunException extends ExecutionControlException { 295 296 private static final long serialVersionUID = 1L; 297 298 private RunException(String message) { 299 super(message); 300 } 301 } 302 303 /** 304 * A 'normal' user exception occurred. 305 */ 306 public static class UserException extends RunException { 307 308 private static final long serialVersionUID = 1L; 309 310 private final String causeExceptionClass; 311 312 public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) { 313 super(message); 314 this.causeExceptionClass = causeExceptionClass; 315 this.setStackTrace(stackElements); 316 } 317 318 /** 319 * Returns the class of the user exception. 320 * @return the name of the user exception class 321 */ 322 public String causeExceptionClass() { 323 return causeExceptionClass; 324 } 325 } 326 327 /** 328 * An exception indicating that a {@code DeclarationSnippet} with unresolved 329 * references has been encountered. 330 * <p> 331 * Contrast this with the initiating {@link SPIResolutionException} 332 * (a {@code RuntimeException}) which is embedded in generated corralled 333 * code. Also, contrast this with 334 * {@link jdk.jshell.UnresolvedReferenceException} the high-level 335 * exception (with {@code DeclarationSnippet} reference) provided in the 336 * main API. 337 */ 338 public static class ResolutionException extends RunException { 339 340 private static final long serialVersionUID = 1L; 341 342 private final int id; 343 344 /** 345 * Constructs an exception indicating that a {@code DeclarationSnippet} 346 * with unresolved references has been encountered. 347 * 348 * @param id An internal identifier of the specific method 349 * @param stackElements the stack trace 350 */ 351 public ResolutionException(int id, StackTraceElement[] stackElements) { 352 super("resolution exception: " + id); 353 this.id = id; 354 this.setStackTrace(stackElements); 355 } 356 357 /** 358 * Retrieves the internal identifier of the unresolved identifier. 359 * 360 * @return the internal identifier 361 */ 362 public int id() { 363 return id; 364 } 365 } 366 367 /** 368 * An exception indicating that an 369 * {@link ExecutionControl#invoke(java.lang.String, java.lang.String) } 370 * (or theoretically a 371 * {@link ExecutionControl#varValue(java.lang.String, java.lang.String) }) 372 * has been interrupted by a {@link ExecutionControl#stop() }. 373 */ 374 public static class StoppedException extends RunException { 375 376 private static final long serialVersionUID = 1L; 377 378 public StoppedException() { 379 super("stopped by stop()"); 380 } 381 } 382 383 }