/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java
509 строк
17 KB
Hannes Wallnöfer
8347123: Add missing @serial tags to other modules
17 фев 2025, 18:31
17 фев 2025, 18:31
3f0c137
Код
Авторство
О чём код?
/* * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * 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.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.ServiceLoader; import java.util.Set; /** * 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. * <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. * <p> * Methods defined in this interface should only be called by the core JShell * implementation. * * @since 9 */ public interface ExecutionControl extends AutoCloseable { /** * 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 NotImplementedException if not implemented * @throws EngineTerminationException the execution engine has terminated */ void load(ClassBytecodes[] cbcs) throws ClassInstallException, NotImplementedException, EngineTerminationException; /** * 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 NotImplementedException if not implemented * @throws EngineTerminationException the execution engine has terminated */ void redefine(ClassBytecodes[] cbcs) throws ClassInstallException, NotImplementedException, EngineTerminationException; /** * Invokes an executable Snippet by calling a method on the specified * wrapper class. The method must have no arguments and return String. * * @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; /** * 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 * @throws EngineTerminationException the execution engine has terminated * @throws InternalException an internal problem occurred */ void addToClasspath(String path) throws EngineTerminationException, InternalException; /** * Interrupts a running invoke. * * @throws EngineTerminationException the execution engine has terminated * @throws InternalException an internal problem occurred */ void stop() throws EngineTerminationException, InternalException; /** * Run a non-standard command (or a standard command from a newer version). * * @param command the non-standard command * @param arg the commands argument * @return the commands return value * @throws UserException the command raised a user exception * @throws ResolutionException the command attempted to directly or * indirectly invoke an unresolved snippet * @throws StoppedException if the command was canceled by * {@link ExecutionControl#stop} * @throws EngineTerminationException the execution engine has terminated * @throws NotImplementedException if not implemented * @throws InternalException an internal problem occurred */ Object extensionCommand(String command, Object arg) 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. */ @Override void close(); /** * Search for a provider, then create and return the * {@code ExecutionControl} instance. * * @param env the execution environment (provided by JShell) * @param name the name of provider * @param parameters the parameter map. * @return the execution engine * @throws Throwable an exception that occurred attempting to find or create * the execution engine. * @throws IllegalArgumentException if no ExecutionControlProvider has the * specified {@code name} and {@code parameters}. */ static ExecutionControl generate(ExecutionEnv env, String name, Map<String, String> parameters) throws Throwable { Set<String> keys = parameters == null ? Collections.emptySet() : parameters.keySet(); for (ExecutionControlProvider p : ServiceLoader.load(ExecutionControlProvider.class)) { if (p.name().equals(name) && p.defaultParameters().keySet().containsAll(keys)) { return p.generate(env, parameters); } } throw new IllegalArgumentException("No ExecutionControlProvider with name '" + name + "' and parameter keys: " + keys.toString()); } /** * Search for a provider, then create and return the * {@code ExecutionControl} instance. * * @param env the execution environment (provided by JShell) * @param spec the {@code ExecutionControl} spec, which is described in * the documentation of this * {@linkplain jdk.jshell.spi package documentation}. * @return the execution engine * @throws Throwable an exception that occurred attempting to find or create * the execution engine. * @throws IllegalArgumentException if no ExecutionControlProvider has the * specified {@code name} and {@code parameters}. * @throws IllegalArgumentException if {@code spec} is malformed */ static ExecutionControl generate(ExecutionEnv env, String spec) throws Throwable { class SpecReader { int len = spec.length(); int i = -1; char ch; SpecReader() { next(); } boolean more() { return i < len; } char current() { return ch; } final boolean next() { ++i; if (i < len) { ch = spec.charAt(i); return true; } i = len; return false; } void skipWhite() { while (more() && Character.isWhitespace(ch)) { next(); } } String readId() { skipWhite(); StringBuilder sb = new StringBuilder(); while (more() && Character.isJavaIdentifierPart(ch)) { sb.append(ch); next(); } skipWhite(); String id = sb.toString(); if (id.isEmpty()) { throw new IllegalArgumentException("Expected identifier in " + spec); } return id; } void expect(char exp) { skipWhite(); if (!more() || ch != exp) { throw new IllegalArgumentException("Expected '" + exp + "' in " + spec); } next(); skipWhite(); } String readValue() { expect('('); int parenDepth = 1; StringBuilder sb = new StringBuilder(); while (more()) { if (ch == ')') { --parenDepth; if (parenDepth == 0) { break; } } else if (ch == '(') { ++parenDepth; } sb.append(ch); next(); } expect(')'); return sb.toString(); } } Map<String, String> parameters = new HashMap<>(); SpecReader sr = new SpecReader(); String name = sr.readId(); if (sr.more()) { sr.expect(':'); while (sr.more()) { String key = sr.readId(); String value = sr.readValue(); parameters.put(key, value); if (sr.more()) { sr.expect(','); } } } return generate(env, name, parameters); } /** * Bundles class name with class bytecodes. */ public static final class ClassBytecodes implements Serializable { private static final long serialVersionUID = 0xC1A55B47EC0DE5L; /** @serial */ private final String name; /** @serial */ private final byte[] bytecodes; /** * Creates a name/bytecode pair. * @param name the class name * @param bytecodes the class bytecodes */ public ClassBytecodes(String name, byte[] bytecodes) { this.name = name; this.bytecodes = bytecodes; } /** * The bytecodes for the class. * * @return the bytecodes */ public byte[] bytecodes() { return bytecodes; } /** * The class name. * * @return the class name */ public String name() { return name; } } /** * The abstract base of all {@code ExecutionControl} exceptions. */ public abstract static class ExecutionControlException extends Exception { private static final long serialVersionUID = 1L; public ExecutionControlException(String message) { super(message); } } /** * Unbidden execution engine termination has occurred. */ public static class EngineTerminationException extends ExecutionControlException { private static final long serialVersionUID = 1L; public EngineTerminationException(String message) { super(message); } } /** * The command is not implemented. */ public static class NotImplementedException extends InternalException { private static final long serialVersionUID = 1L; public NotImplementedException(String message) { super(message); } } /** * An internal problem has occurred. */ public static class InternalException extends ExecutionControlException { private static final long serialVersionUID = 1L; public InternalException(String message) { super(message); } } /** * A class install (load or redefine) encountered a problem. */ public static class ClassInstallException extends ExecutionControlException { private static final long serialVersionUID = 1L; /** @serial */ private final boolean[] installed; public ClassInstallException(String message, boolean[] installed) { super(message); this.installed = installed; } /** * Indicates which of the passed classes were successfully * loaded/redefined. * @return a one-to-one array with the {@link ClassBytecodes}{@code[]} * array -- {@code true} if installed */ public boolean[] installed() { return installed; } } /** * The abstract base of of exceptions specific to running user code. */ public abstract static class RunException extends ExecutionControlException { private static final long serialVersionUID = 1L; private RunException(String message) { super(message); } } /** * A 'normal' user exception occurred. */ public static class UserException extends RunException { private static final long serialVersionUID = 1L; /** @serial */ private final String causeExceptionClass; @SuppressWarnings("this-escape") public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) { super(message); this.causeExceptionClass = causeExceptionClass; this.setStackTrace(stackElements); } /** * Returns the class of the user exception. * @return the name of the user exception class */ public String causeExceptionClass() { return causeExceptionClass; } } /** * An exception indicating that a {@code DeclarationSnippet} with unresolved * references has been encountered. * <p> * Contrast this with the initiating {@link SPIResolutionException} * (a {@code RuntimeException}) which is embedded in generated corralled * code. Also, contrast this with * {@link jdk.jshell.UnresolvedReferenceException} the high-level * exception (with {@code DeclarationSnippet} reference) provided in the * main API. */ public static class ResolutionException extends RunException { private static final long serialVersionUID = 1L; /** @serial */ private final int id; /** * Constructs an exception indicating that a {@code DeclarationSnippet} * with unresolved references has been encountered. * * @param id An internal identifier of the specific method * @param stackElements the stack trace */ @SuppressWarnings("this-escape") public ResolutionException(int id, StackTraceElement[] stackElements) { super("resolution exception: " + id); this.id = id; this.setStackTrace(stackElements); } /** * Retrieves the internal identifier of the unresolved identifier. * * @return the internal identifier */ public int id() { return id; } } /** * An exception indicating that an * {@link ExecutionControl#invoke(java.lang.String, java.lang.String) } * (or theoretically a * {@link ExecutionControl#varValue(java.lang.String, java.lang.String) }) * has been interrupted by a {@link ExecutionControl#stop() }. */ public static class StoppedException extends RunException { private static final long serialVersionUID = 1L; public StoppedException() { super("stopped by stop()"); } } }