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.spi; 27 28 import java.util.Collection; 29 import jdk.jshell.JShellException; 30 31 /** 32 * This interface specifies the functionality that must provided to implement 33 * a pluggable JShell execution engine. 34 * <p> 35 * The audience for this Service Provider Interface is engineers 36 * wishing to implement their own version of the execution engine in support 37 * of the JShell API. This is NOT a part of the JShell API. 38 * <p> 39 * A Snippet is compiled into code wrapped in a 'wrapper class'. The execution 40 * engine is used by the core JShell implementation to load and, for 41 * executable Snippets, execute the Snippet. 42 * <p> 43 * Methods defined in this interface should only be called by the core JShell 44 * implementation. 45 * <p> 46 * To install an instance of ExecutionControl, it is passed to 47 * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl) }. 48 */ 49 public interface ExecutionControl { 50 51 /** 52 * Represents the current status of a class in the execution engine. 53 */ 54 public enum ClassStatus { 55 /** 56 * Class is not known to the execution engine (not loaded). 57 */ 58 UNKNOWN, 59 60 /** 61 * Class is loaded, but the loaded/redefined bytes do not match those 62 * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }. 63 */ 64 NOT_CURRENT, 65 66 /** 67 * Class is loaded and loaded/redefined bytes match those 68 * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }. 69 */ 70 CURRENT 71 }; 72 73 /** 74 * Initializes the instance. No methods in this interface can be called 75 * before this. 76 * 77 * @param env the execution environment information provided by JShell 78 * @throws Exception if the instance is unable to initialize 79 */ 80 void start(ExecutionEnv env) throws Exception; 81 82 /** 83 * Shuts down this execution engine. Implementation should free all 84 * resources held by this execution engine. 85 * <p> 86 * No calls to methods on this interface should be made after close. 87 */ 88 void close(); 89 90 /** 91 * Adds the path to the execution class path. 92 * 93 * @param path the path to add 94 * @return true if successful 95 */ 96 boolean addToClasspath(String path); 97 98 /** 99 * Invokes an executable Snippet by calling a method on the specified 100 * wrapper class. The method must have no arguments and return String. 101 * 102 * @param classname the class whose method should be invoked 103 * @param methodname the name of method to invoke 104 * @return the result of the execution or null if no result 105 * @throws JShellException if a user exception if thrown, 106 * {@link jdk.jshell.EvalException EvalException} will be thrown; if an 107 * unresolved reference is encountered, 108 * {@link jdk.jshell.UnresolvedReferenceException UnresolvedReferenceException} 109 * will be thrown 110 */ 111 String invoke(String classname, String methodname) throws JShellException; 112 113 /** 114 * Attempts to load new classes. Class bytes are retrieved from 115 * {@link ExecutionEnv#getClassBytes(java.lang.String) } 116 * 117 * @param classes list of class names to load 118 * @return true if load succeeded 119 */ 120 boolean load(Collection<String> classes); 121 122 /** 123 * Attempts to redefine previously loaded classes. Class bytes are retrieved 124 * from {@link ExecutionEnv#getClassBytes(java.lang.String) } 125 * 126 * @param classes list of class names to redefine 127 * @return true if redefine succeeded 128 */ 129 boolean redefine(Collection<String> classes); 130 131 /** 132 * Queries if the class is loaded and the class bytes are current. 133 * 134 * @param classname name of the wrapper class to query 135 * @return {@code UNKNOWN} if the class is not loaded; {@code CURRENT} if 136 * the loaded/redefined bytes are equal to the most recent bytes for this 137 * wrapper class; otherwise {@code NOT_CURRENT} 138 */ 139 ClassStatus getClassStatus(String classname); 140 141 /** 142 * Interrupt a running invoke. 143 */ 144 void stop(); 145 146 /** 147 * Returns the value of a variable. 148 * 149 * @param classname the name of the wrapper class of the variable 150 * @param varname the name of the variable 151 * @return the value of the variable 152 */ 153 String varValue(String classname, String varname); 154 } | 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 NotImplementedException if not implemented 60 * @throws EngineTerminationException the execution engine has terminated 61 */ 62 void load(ClassBytecodes[] cbcs) 63 throws ClassInstallException, NotImplementedException, EngineTerminationException; 64 65 /** 66 * Attempts to redefine previously loaded classes. 67 * 68 * @param cbcs the class name and bytecodes to redefine 69 * @throws ClassInstallException exception occurred redefining the classes, 70 * some or all were not redefined 71 * @throws NotImplementedException if not implemented 72 * @throws EngineTerminationException the execution engine has terminated 73 */ 74 void redefine(ClassBytecodes[] cbcs) 75 throws ClassInstallException, NotImplementedException, EngineTerminationException; 76 77 /** 78 * Invokes an executable Snippet by calling a method on the specified 79 * wrapper class. The method must have no arguments and return String. 80 * 81 * @param className the class whose method should be invoked 82 * @param methodName the name of method to invoke 83 * @return the result of the execution or null if no result 84 * @throws UserException the invoke raised a user exception 85 * @throws ResolutionException the invoke attempted to directly or 86 * indirectly invoke an unresolved snippet 87 * @throws StoppedException if the {@code invoke()} was canceled by 88 * {@link ExecutionControl#stop} 89 * @throws EngineTerminationException the execution engine has terminated 90 * @throws InternalException an internal problem occurred 91 */ 92 String invoke(String className, String methodName) 93 throws RunException, EngineTerminationException, InternalException; 94 95 /** 96 * Returns the value of a variable. 97 * 98 * @param className the name of the wrapper class of the variable 99 * @param varName the name of the variable 100 * @return the value of the variable 101 * @throws UserException formatting the value raised a user exception 102 * @throws ResolutionException formatting the value attempted to directly or 103 * indirectly invoke an unresolved snippet 104 * @throws StoppedException if the formatting the value was canceled by 105 * {@link ExecutionControl#stop} 106 * @throws EngineTerminationException the execution engine has terminated 107 * @throws InternalException an internal problem occurred 108 */ 109 String varValue(String className, String varName) 110 throws RunException, 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 * Run a non-standard command (or a standard command from a newer version). 143 * 144 * @param command the non-standard command 145 * @param arg the commands argument 146 * @return the commands return value 147 * @throws UserException the command raised a user exception 148 * @throws ResolutionException the command attempted to directly or 149 * indirectly invoke an unresolved snippet 150 * @throws StoppedException if the command was canceled by 151 * {@link ExecutionControl#stop} 152 * @throws EngineTerminationException the execution engine has terminated 153 * @throws NotImplementedException if not implemented 154 * @throws InternalException an internal problem occurred 155 */ 156 Object extensionCommand(String command, Object arg) 157 throws RunException, EngineTerminationException, InternalException; 158 159 /** 160 * Shuts down this execution engine. Implementation should free all 161 * resources held by this execution engine. 162 * <p> 163 * No calls to methods on this interface should be made after close. 164 */ 165 void close(); 166 167 public static final class ClassBytecodes implements Serializable { 168 169 private static final long serialVersionUID = 1L; 170 171 public ClassBytecodes(String name, byte[] bytecodes) { 172 this.name = name; 173 this.bytecodes = bytecodes; 174 } 175 public final String name; 176 public final byte[] bytecodes; 177 } 178 179 @SuppressWarnings("serial") 180 public static abstract class ExecutionControlException extends Exception { 181 182 public ExecutionControlException(String message) { 183 super(message); 184 } 185 } 186 187 /** 188 * Unbidden execution engine termination has occurred. 189 */ 190 @SuppressWarnings("serial") 191 public static class EngineTerminationException extends ExecutionControlException { 192 193 public EngineTerminationException(String message) { 194 super(message); 195 } 196 } 197 198 @SuppressWarnings("serial") 199 public static class NotImplementedException extends InternalException { 200 201 public NotImplementedException(String message) { 202 super(message); 203 } 204 } 205 206 @SuppressWarnings("serial") 207 public static class InternalException extends ExecutionControlException { 208 209 public InternalException(String message) { 210 super(message); 211 } 212 } 213 214 @SuppressWarnings("serial") 215 public static class ClassInstallException extends ExecutionControlException { 216 217 private final boolean[] installed; 218 219 public ClassInstallException(String message, boolean[] installed) { 220 super(message); 221 this.installed = installed; 222 } 223 224 public boolean[] installed() { 225 return installed; 226 } 227 } 228 229 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 230 public static abstract class RunException extends ExecutionControlException { 231 232 private RunException(String message) { 233 super(message); 234 } 235 } 236 237 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 238 public static class UserException extends RunException { 239 240 private final String causeExceptionClass; 241 242 public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) { 243 super(message); 244 this.causeExceptionClass = causeExceptionClass; 245 this.setStackTrace(stackElements); 246 } 247 248 public String causeExceptionClass() { 249 return causeExceptionClass; 250 } 251 } 252 253 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 254 public static class ResolutionException extends RunException { 255 256 private final int id; 257 258 /** 259 * Constructs an exception indicating that a 260 * {@code DeclarationSnippet} with unresolved references has been 261 * encountered. The throw of this exception is generated into the body 262 * of a 263 * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} 264 * method. 265 * 266 * @param id An internal identifier of the specific method 267 * @param stackElements the stack trace 268 */ 269 public ResolutionException(int id, StackTraceElement[] stackElements) { 270 super("resolution exception: " + id); 271 this.id = id; 272 this.setStackTrace(stackElements); 273 } 274 275 /** 276 * Retrieves the internal identifier of the unresolved identifier. 277 * 278 * @return the internal identifier 279 */ 280 public int id() { 281 return id; 282 } 283 } 284 285 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 286 public static class StoppedException extends RunException { 287 288 public StoppedException() { 289 super("stopped by stop()"); 290 } 291 } 292 293 } |