package com.oracle.graalvm.locator;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import org.graalvm.home.HomeFinder;
import com.oracle.truffle.api.TruffleOptions;
import com.oracle.truffle.api.impl.TruffleLocator;
public final class GraalVMLocator extends TruffleLocator
implements Callable<ClassLoader> {
private static final boolean LOCATOR_TRACE = Boolean.parseBoolean(System.getProperty("truffle.class.path.trace", "false"));
private static URLClassLoader loader;
public GraalVMLocator() {
}
private static void setGraalVMProperties(HomeFinder homeFinder) {
Path homePath = homeFinder.getHomeFolder();
if (homePath != null) {
String home = homePath.toString();
if (System.getProperty("org.graalvm.home") == null) {
System.setProperty("org.graalvm.home", home);
}
}
String version = homeFinder.getVersion();
System.setProperty("org.graalvm.version", version);
for (Map.Entry<String, Path> languageHome : homeFinder.getLanguageHomes().entrySet()) {
setLanguageHomeProperty(languageHome.getKey(), languageHome.getValue());
}
for (Map.Entry<String, Path> toolHome : homeFinder.getToolHomes().entrySet()) {
setToolHomeProperty(toolHome.getKey(), toolHome.getValue());
}
}
private static void setLanguageHomeProperty(String languageId, Path languageLocation) {
if (Files.isDirectory(languageLocation)) {
final String homeFolderKey = "org.graalvm.language." + languageId + ".home";
if (System.getProperty(homeFolderKey) == null) {
System.setProperty(homeFolderKey, languageLocation.toString());
}
final String legacyHomeFolderKey = languageId + ".home";
if (System.getProperty(legacyHomeFolderKey) == null) {
System.setProperty(legacyHomeFolderKey, languageLocation.toString());
}
}
}
private static void setToolHomeProperty(String toolId, Path toolLocation) {
if (Files.isDirectory(toolLocation)) {
final String homeFolderKey = "org.graalvm.tool." + toolId + ".home";
if (System.getProperty(homeFolderKey) == null) {
System.setProperty(homeFolderKey, toolLocation.toString());
}
final String legacyHomeFolderKey = toolId + ".home";
if (System.getProperty(legacyHomeFolderKey) == null) {
System.setProperty(legacyHomeFolderKey, toolLocation.toString());
}
}
}
private static List<URL> collectClassPath(HomeFinder homeFinder) {
List<URL> classPath = new ArrayList<>();
collectLanguageJars(homeFinder.getLanguageHomes(), classPath);
collectLanguageJars(homeFinder.getToolHomes(), classPath);
String append = System.getProperty("truffle.class.path.append");
if (append != null) {
String[] files = append.split(System.getProperty("path.separator"));
for (String file : files) {
addJarOrDir(classPath, Paths.get(file));
}
}
if (LOCATOR_TRACE) {
PrintStream out = System.out;
out.println("Setting up Truffle GuestLanguageTools classpath:");
for (URL url : classPath) {
out.println(url);
}
}
return classPath;
}
public static ClassLoader getLanguagesLoader() {
if (loader == null) {
HomeFinder homeFinder = HomeFinder.getInstance();
if (homeFinder == null) {
throw new IllegalStateException("No HomeFinder instance.");
}
setGraalVMProperties(homeFinder);
if (!TruffleOptions.AOT) {
final List<URL> classPath = collectClassPath(homeFinder);
loader = new GuestLangToolsLoader(classPath.toArray(new URL[0]), JDKServices.getLocatorBaseClassLoader(GraalVMLocator.class));
}
}
return loader;
}
private static class GuestLangToolsLoader extends URLClassLoader {
GuestLangToolsLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
}
private static void collectLanguageJars(Map<String, Path> homes, List<URL> classPath) {
for (Map.Entry<String, Path> languageHome : homes.entrySet()) {
final Path languageLocation = languageHome.getValue();
if (Files.isDirectory(languageLocation)) {
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(languageLocation)) {
for (Path file : dirStream) {
addJar(classPath, file);
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
} else {
addJar(classPath, languageLocation);
}
}
}
private static void addJarOrDir(List<URL> classPath, Path file) {
if (Files.isDirectory(file)) {
try {
classPath.add(file.toUri().toURL());
} catch (MalformedURLException ex) {
throw new IllegalStateException(ex);
}
} else {
addJar(classPath, file);
}
}
private static void addJar(List<URL> classPath, Path jar) {
Path filename = jar.getFileName();
if (filename != null && filename.toString().endsWith(".jar") && Files.exists(jar)) {
try {
classPath.add(jar.toUri().toURL());
} catch (MalformedURLException ex) {
throw new IllegalStateException(ex);
}
}
}
@Override
public void locate(Response response) {
if (!"true".equals(System.getProperty("graalvm.locatorDisabled"))) {
final ClassLoader cl = getLanguagesLoader();
if (cl != null) {
response.registerClassLoader(cl);
}
}
}
@Override
public ClassLoader call() throws Exception {
return getLanguagesLoader();
}
}