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 }