All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dellroad.jct.jshell.MemoryLoaderDelegate Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version

/*
 * Copyright (C) 2023 Archie L. Cobbs. All rights reserved.
 */

package org.dellroad.jct.jshell;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import jdk.jshell.execution.LoaderDelegate;
import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
import jdk.jshell.spi.ExecutionControl.ClassInstallException;
import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
import jdk.jshell.spi.ExecutionControl.InternalException;

import org.dellroad.stuff.java.MemoryClassLoader;

/**
 * A JShell {@link LoaderDelegate} that uses a {@link MemoryClassLoader}.
 *
 * 

* This class accepts {@code --class-path} components that refer to JAR file contents using the {@code jar:} URL syntax, * e.g., {@code jar:file:/some/dir/foo.jar!/BOOT-INF/lib/bar.jar}. However, this is only partially useful because * (a) you can't build a classpath with components that contain colon characters, and (b) the jshell tool rejects * classpath components that aren't real files. */ public class MemoryLoaderDelegate implements LoaderDelegate { private static final String JAR_FILE_PREFIX = "jar:file:"; private final HashMap> classMap = new HashMap<>(); private final MemoryClassLoader loader; // Constructors /** * Default constructor. * *

* Uses the current thread's context loader as the parent loader for a newly created {@link MemoryClassLoader}. */ public MemoryLoaderDelegate() { this(new MemoryClassLoader()); } /** * Primary constructor. * * @param loader associated class loader * @throws IllegalArgumentException if {@code loader} is null */ public MemoryLoaderDelegate(MemoryClassLoader loader) { if (loader == null) throw new IllegalArgumentException("null loader"); this.loader = loader; } /** * Get the {@link MemoryClassLoader} associated with this instance. * * @return associated class loader */ public MemoryClassLoader getClassLoader() { return this.loader; } // LoaderDelegate @Override public void addToClasspath(String path) throws EngineTerminationException, InternalException { if (path == null) throw new IllegalArgumentException("null path"); try { for (String component : this.splitClassPath(path)) { this.loader.addURL(component.startsWith(JAR_FILE_PREFIX) ? new URL(component) : new File(component).toURI().toURL()); } } catch (Exception e) { throw this.wrapCause(e, new InternalException(e.getMessage())); } } @Override public void classesRedefined(ClassBytecodes[] classes) { if (classes == null) throw new IllegalArgumentException("null classes"); for (ClassBytecodes c : classes) this.loader.putClass(c.name(), c.bytecodes()); } @Override public Class findClass(String className) throws ClassNotFoundException { if (className == null) throw new IllegalArgumentException("null className"); final Class cl = this.classMap.get(className); if (cl == null) throw new ClassNotFoundException("class \"" + className + "\" not found"); return cl; } @Override public void load(ClassBytecodes[] classes) throws ClassInstallException, EngineTerminationException { if (classes == null) throw new IllegalArgumentException("null classes"); int numLoaded = 0; try { for (ClassBytecodes c : classes) this.loader.putClass(c.name(), c.bytecodes()); for (ClassBytecodes c : classes) { final Class cl = this.loader.loadClass(c.name()); this.classMap.put(c.name(), cl); numLoaded++; cl.getDeclaredMethods(); } } catch (Throwable t) { final boolean[] loaded = new boolean[classes.length]; Arrays.fill(loaded, 0, numLoaded, true); throw this.wrapCause(t, new ClassInstallException(t.getMessage(), loaded)); } } // Internal Methods private T2 wrapCause(T t, T2 t2) { t2.initCause(t); return t2; } private List splitClassPath(String path) { final ArrayList components = new ArrayList<>(); for (int start = 0; start < path.length(); ) { int look = start; if (path.substring(start).startsWith(JAR_FILE_PREFIX)) look += JAR_FILE_PREFIX.length(); final int sep = path.indexOf(File.pathSeparatorChar, look); final int stop = sep != -1 ? sep : path.length(); final String component = path.substring(start, stop); if (!component.isEmpty()) components.add(component); start = Math.max(stop, sep + 1); } return components; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy