package jdk.nashorn.internal.runtime;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.security.Permissions;
import java.security.SecureClassLoader;
abstract class NashornLoader extends SecureClassLoader {
protected static final String OBJECTS_PKG = "jdk.nashorn.internal.objects";
protected static final String RUNTIME_PKG = "jdk.nashorn.internal.runtime";
protected static final String RUNTIME_ARRAYS_PKG = "jdk.nashorn.internal.runtime.arrays";
protected static final String RUNTIME_LINKER_PKG = "jdk.nashorn.internal.runtime.linker";
protected static final String SCRIPTS_PKG = "jdk.nashorn.internal.scripts";
protected static final String OBJECTS_PKG_INTERNAL = "jdk/nashorn/internal/objects";
protected static final String RUNTIME_PKG_INTERNAL = "jdk/nashorn/internal/runtime";
protected static final String RUNTIME_ARRAYS_PKG_INTERNAL = "jdk/nashorn/internal/runtime/arrays";
protected static final String RUNTIME_LINKER_PKG_INTERNAL = "jdk/nashorn/internal/runtime/linker";
protected static final String SCRIPTS_PKG_INTERNAL = "jdk/nashorn/internal/scripts";
static final Module NASHORN_MODULE = Context.class.getModule();
private static final Permission[] SCRIPT_PERMISSIONS;
private static final String MODULE_MANIPULATOR_NAME = SCRIPTS_PKG + ".ModuleGraphManipulator";
private static final byte[] MODULE_MANIPULATOR_BYTES = readModuleManipulatorBytes();
static {
SCRIPT_PERMISSIONS = new Permission[] {
new RuntimePermission("accessClassInPackage." + RUNTIME_PKG),
new RuntimePermission("accessClassInPackage." + RUNTIME_LINKER_PKG),
new RuntimePermission("accessClassInPackage." + OBJECTS_PKG),
new RuntimePermission("accessClassInPackage." + SCRIPTS_PKG),
new RuntimePermission("accessClassInPackage." + RUNTIME_ARRAYS_PKG)
};
}
private Method addModuleExport;
NashornLoader(final ClassLoader parent) {
super(parent);
}
void loadModuleManipulator() {
final Class<?> clazz = defineClass(MODULE_MANIPULATOR_NAME,
MODULE_MANIPULATOR_BYTES, 0, MODULE_MANIPULATOR_BYTES.length);
try {
Class.forName(MODULE_MANIPULATOR_NAME, true, this);
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
final PrivilegedAction<Void> pa = () -> {
try {
addModuleExport = clazz.getDeclaredMethod("addExport", Module.class);
addModuleExport.setAccessible(true);
} catch (final NoSuchMethodException | SecurityException ex) {
throw new RuntimeException(ex);
}
return null;
};
AccessController.doPrivileged(pa);
}
final void addModuleExport(final Module to) {
try {
addModuleExport.invoke(null, to);
} catch (final IllegalAccessException |
IllegalArgumentException |
InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
protected static void checkPackageAccess(final String name) {
final int i = name.lastIndexOf('.');
if (i != -1) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
final String pkgName = name.substring(0, i);
switch (pkgName) {
case RUNTIME_PKG:
case RUNTIME_ARRAYS_PKG:
case RUNTIME_LINKER_PKG:
case OBJECTS_PKG:
case SCRIPTS_PKG:
break;
default:
sm.checkPackageAccess(pkgName);
}
}
}
}
@Override
protected PermissionCollection getPermissions(final CodeSource codesource) {
final Permissions permCollection = new Permissions();
for (final Permission perm : SCRIPT_PERMISSIONS) {
permCollection.add(perm);
}
return permCollection;
}
static ClassLoader createClassLoader(final String classPath, final ClassLoader parent) {
final URL[] urls = pathToURLs(classPath);
return URLClassLoader.newInstance(urls, parent);
}
private static URL[] pathToURLs(final String path) {
final String[] components = path.split(File.pathSeparator);
URL[] urls = new URL[components.length];
int count = 0;
while(count < components.length) {
final URL url = fileToURL(new File(components[count]));
if (url != null) {
urls[count++] = url;
}
}
if (urls.length != count) {
final URL[] tmp = new URL[count];
System.arraycopy(urls, 0, tmp, 0, count);
urls = tmp;
}
return urls;
}
private static URL fileToURL(final File file) {
String name;
try {
name = file.getCanonicalPath();
} catch (final IOException e) {
name = file.getAbsolutePath();
}
name = name.replace(File.separatorChar, '/');
if (!name.startsWith("/")) {
name = "/" + name;
}
if (!file.isFile()) {
name += "/";
}
try {
return new URL("file", "", name);
} catch (final MalformedURLException e) {
throw new IllegalArgumentException("file");
}
}
private static byte[] readModuleManipulatorBytes() {
final PrivilegedAction<byte[]> pa = () -> {
final String res = "/"+ MODULE_MANIPULATOR_NAME.replace('.', '/') + ".class";
try (InputStream in = NashornLoader.class.getResourceAsStream(res)) {
return in.readAllBytes();
} catch (final IOException exp) {
throw new UncheckedIOException(exp);
}
};
return AccessController.doPrivileged(pa);
}
}