Class LocalContextExecutionControlProvider
- All Implemented Interfaces:
ExecutionControlProvider
LocalExecutionControlProvider, but with additional support for handling certain
class path and class loading issues.
When executing JShell locally, it is often desirable that any classes visible to the thread that starts JShell should also be visible to any scripts and command inputs given to that JShell instance.
Unfortunately, this doesn't always happen automatically when using the standard "local"
execution provided by LocalExecutionControl.
When executing JShell locally, there are two class path/loading issues to worry about:
- When JShell compiles source snippets, what classes are available on the "source class path"? That is, what class names can you refer to by name in your scripts or snippets?
- When a compiled script or snippet is loaded as a Java class file by the execution engine, what classes are available on the "binary class path" when resolving symbolic references?
The standard LocalExecutionControl requires non-standard classes to be explicitly added
via the --class-path command line flag. Moreover, the ClassLoader that is uses delegates
to the system class loader, which means that in certain more complex class loading scenarios (for example,
when running as a servlet in the Tomcat web container), compiled snippets classes will fail to load
due to resolution errors.
This class tries to workaround these issues as follows:
- To address the "binary class path", this class uses a
ClassLoaderthat delegates to the current thread's context class loader instead of the system class loader. This should fix linking problems in complex class loading scenarios. - To address the "souce class path", this class introspects the current thread's context class
loader and its parents (recursively), attempting to glean what's on the class path. This works
for any
ClassLoaderthat are instances ofURLClassLoader. However, Java's standard application class loader is not, so items on the JVM application class path are missed by this strategy. To include the application class loader, hacky instrospection relying on illegal accesses is attempted (failures are silently ignored). To ensure these efforts succeed, the following flag must be added to JVM startup:--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED. Note there is also another ugly workaround, which is to write JShell code that only accesses classes on the application class path via reflection.
To utilize this class, include the flags returned by modifyJShellFlags()
as parameters to JShell startup.
This provider uses a MemoryLoaderDelegate.
- See Also:
-
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic voidaddToClassPath(List<String> commandLine, List<String> components) Utility method to modify the given JShell command line flags to add/augment the--class-pathflag(s) to (also) include the given classpath components.protected LocalExecutionControlprotected org.dellroad.stuff.java.MemoryClassLoaderprotected MemoryLoaderDelegatecreateMemoryLoaderDelegate(org.dellroad.stuff.java.MemoryClassLoader memoryLoader) generate(ExecutionEnv env, Map<String, String> params) static StringgetExecutionFlag(List<String> flags) Get the execution provider name specified via the--executionflag, if any.static voidmodifyJShellFlags(ClassLoader loader, List<String> flags) Modify a list of JShell tool command line flags to enable use of this class.name()static voidsetExecutionFlag(List<String> flags, String providerName) Modify a list of JShell tool command line flags to force the use of the named execution provider, overriding any previous.
-
Field Details
-
NAME
- See Also:
-
-
Constructor Details
-
LocalContextExecutionControlProvider
public LocalContextExecutionControlProvider()
-
-
Method Details
-
modifyJShellFlags
Modify a list of JShell tool command line flags to enable use of this class.- Parameters:
loader- loader to copy from, or null for the current thread's context class loaderflags- modifiable list of command line flags- Throws:
IllegalArgumentException- ifflagsis null
-
getExecutionFlag
Get the execution provider name specified via the--executionflag, if any.- Parameters:
flags- list of command line flags- Returns:
- execution provider name configured via
--executionflag, or null if none - Throws:
IllegalArgumentException- ifflagsis null- See Also:
-
setExecutionFlag
Modify a list of JShell tool command line flags to force the use of the named execution provider, overriding any previous.- Parameters:
flags- modifiable list of command line flagsproviderName- execution provider name- Throws:
IllegalArgumentException- ifflagsis null- See Also:
-
addToClassPath
Utility method to modify the given JShell command line flags to add/augment the--class-pathflag(s) to (also) include the given classpath components.- Parameters:
commandLine- jshell command line, possibly including exisiting--class-pathflag(s)components- new classpath components to add tocommandLine- Throws:
IllegalArgumentException- if either parameter is null
-
name
- Specified by:
namein interfaceExecutionControlProvider
-
defaultParameters
- Specified by:
defaultParametersin interfaceExecutionControlProvider
-
generate
- Specified by:
generatein interfaceExecutionControlProvider
-
createMemoryLoaderDelegate
protected MemoryLoaderDelegate createMemoryLoaderDelegate(org.dellroad.stuff.java.MemoryClassLoader memoryLoader) -
createMemoryClassLoader
protected org.dellroad.stuff.java.MemoryClassLoader createMemoryClassLoader() -
createLocalExecutionControl
-