Refactor CompilerRunnerUtil

Eliminate code duplication, add NotNull, make everything private, etc
This commit is contained in:
Alexander Udalov
2014-12-15 12:47:02 +03:00
parent b8328f9190
commit 45c6d486fc
2 changed files with 63 additions and 62 deletions
@@ -54,7 +54,7 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
@SuppressWarnings("UnusedDeclaration") // Used via reflection in CompilerRunnerUtil#invokeExecMethod @SuppressWarnings("UnusedDeclaration") // Used via reflection in CompilerRunnerUtil#invokeExecMethod
@NotNull @NotNull
public ExitCode execAndOutputHtml(@NotNull PrintStream errStream, @NotNull Services services, @NotNull String... args) { public ExitCode execAndOutputXml(@NotNull PrintStream errStream, @NotNull Services services, @NotNull String... args) {
return exec(errStream, services, MessageRenderer.XML, args); return exec(errStream, services, MessageRenderer.XML, args);
} }
@@ -26,13 +26,11 @@ import org.jetbrains.jet.utils.KotlinPaths;
import java.io.*; import java.io.*;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.ArrayList; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_LOCATION; import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
@@ -42,100 +40,103 @@ public class CompilerRunnerUtil {
private static SoftReference<ClassLoader> ourClassLoaderRef = new SoftReference<ClassLoader>(null); private static SoftReference<ClassLoader> ourClassLoaderRef = new SoftReference<ClassLoader>(null);
public static List<File> kompilerClasspath(KotlinPaths paths, MessageCollector messageCollector) { @Nullable
private static File getLibPath(@NotNull KotlinPaths paths, @NotNull MessageCollector messageCollector) {
File libs = paths.getLibPath(); File libs = paths.getLibPath();
if (libs.exists() && !libs.isFile()) return libs;
if (!libs.exists() || libs.isFile()) { messageCollector.report(
messageCollector.report(ERROR, "Broken compiler at '" + libs.getAbsolutePath() + "'. Make sure plugin is properly installed", NO_LOCATION); ERROR,
return Collections.emptyList(); "Broken compiler at '" + libs.getAbsolutePath() + "'. Make sure plugin is properly installed",
} NO_LOCATION
);
ArrayList<File> answer = new ArrayList<File>(); return null;
answer.add(new File(libs, "kotlin-compiler.jar"));
answer.add(new File(libs, "kotlin-runtime.jar"));
return answer;
} }
@NotNull @NotNull
public static ClassLoader getOrCreatePreloader( private static List<File> compilerClasspath(@NotNull File libs) {
@NotNull KotlinPaths paths, return Arrays.asList(
new File(libs, "kotlin-compiler.jar"),
new File(libs, "kotlin-runtime.jar")
);
}
@NotNull
private static ClassLoader createPreloader(
@NotNull File libPath,
@Nullable ClassLoader parentClassLoader, @Nullable ClassLoader parentClassLoader,
@Nullable ClassCondition classToLoadByParent, @Nullable ClassCondition classToLoadByParent
@NotNull MessageCollector messageCollector ) throws IOException {
) { return ClassPreloadingUtils.preloadClasses(
ClassLoader answer = ourClassLoaderRef.get(); compilerClasspath(libPath), /* estimatedClassNumber = */ 4096, parentClassLoader, classToLoadByParent
if (answer == null) { );
try {
int estimatedClassNumber = 4096;
answer = ClassPreloadingUtils.preloadClasses(kompilerClasspath(paths, messageCollector), estimatedClassNumber, parentClassLoader, classToLoadByParent);
}
catch (IOException e) {
throw new RuntimeException(e);
}
ourClassLoaderRef = new SoftReference<ClassLoader>(answer);
}
return answer;
} }
public static ClassLoader getOrCreateClassLoader(KotlinPaths paths, MessageCollector messageCollector) { @NotNull
ClassLoader answer = ourClassLoaderRef.get(); private static URLClassLoader createClassLoader(@NotNull File libPath) throws MalformedURLException {
if (answer == null) { List<File> jars = compilerClasspath(libPath);
answer = createClassLoader(paths, messageCollector);
ourClassLoaderRef = new SoftReference<ClassLoader>(answer);
}
return answer;
}
private static URLClassLoader createClassLoader(KotlinPaths paths, MessageCollector messageCollector) {
List<File> jars = kompilerClasspath(paths, messageCollector);
URL[] urls = new URL[jars.size()]; URL[] urls = new URL[jars.size()];
for (int i = 0; i < urls.length; i++) { for (int i = 0; i < urls.length; i++) {
try { urls[i] = jars.get(i).toURI().toURL();
urls[i] = jars.get(i).toURI().toURL();
}
catch (MalformedURLException e) {
throw new RuntimeException(e); // Checked exceptions are great! I love them, and I love brilliant library designers too!
}
} }
return new URLClassLoader(urls, null); return new URLClassLoader(urls, null);
} }
static void handleProcessTermination(int exitCode, MessageCollector messageCollector) { private static void handleProcessTermination(int exitCode, @NotNull MessageCollector messageCollector) {
if (exitCode != 0 && exitCode != 1) { if (exitCode != 0 && exitCode != 1) {
messageCollector.report(ERROR, "Compiler terminated with exit code: " + exitCode, NO_LOCATION); messageCollector.report(ERROR, "Compiler terminated with exit code: " + exitCode, NO_LOCATION);
} }
} }
public static int getReturnCodeFromObject(Object rc) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { public static int getReturnCodeFromObject(@Nullable Object rc) throws Exception {
if ("org.jetbrains.jet.cli.common.ExitCode".equals(rc.getClass().getCanonicalName())) { if (rc == null) {
return (Integer)rc.getClass().getMethod("getCode").invoke(rc); return /* ExitCode.INTERNAL_ERROR */ 2;
}
else if ("org.jetbrains.jet.cli.common.ExitCode".equals(rc.getClass().getCanonicalName())) {
return (Integer) rc.getClass().getMethod("getCode").invoke(rc);
} }
else { else {
throw new IllegalStateException("Unexpected return: " + rc); throw new IllegalStateException("Unexpected return: " + rc);
} }
} }
@Nullable
public static Object invokeExecMethod( public static Object invokeExecMethod(
String compilerClassName, String[] arguments, CompilerEnvironment environment, @NotNull String compilerClassName,
MessageCollector messageCollector, PrintStream out, boolean usePreloader @NotNull String[] arguments,
@NotNull CompilerEnvironment environment,
@NotNull MessageCollector messageCollector,
@NotNull PrintStream out,
boolean usePreloader
) throws Exception { ) throws Exception {
ClassLoader loader = usePreloader File libPath = getLibPath(environment.getKotlinPaths(), messageCollector);
? getOrCreatePreloader(environment.getKotlinPaths(), environment.getParentClassLoader(), if (libPath == null) return null;
environment.getClassesToLoadByParent(), messageCollector)
: getOrCreateClassLoader(environment.getKotlinPaths(), messageCollector);
Class<?> kompiler = Class.forName(compilerClassName, true, loader); ClassLoader classLoader = ourClassLoaderRef.get();
if (classLoader == null) {
classLoader = usePreloader
? createPreloader(libPath, environment.getParentClassLoader(), environment.getClassesToLoadByParent())
: createClassLoader(libPath);
ourClassLoaderRef = new SoftReference<ClassLoader>(classLoader);
}
Class<?> kompiler = Class.forName(compilerClassName, true, classLoader);
Method exec = kompiler.getMethod( Method exec = kompiler.getMethod(
"execAndOutputHtml", "execAndOutputXml",
PrintStream.class, PrintStream.class,
Class.forName("org.jetbrains.jet.config.Services", true, loader), String[].class); Class.forName("org.jetbrains.jet.config.Services", true, classLoader),
String[].class
);
return exec.invoke(kompiler.newInstance(), out, environment.getServices(), arguments); return exec.invoke(kompiler.newInstance(), out, environment.getServices(), arguments);
} }
public static void outputCompilerMessagesAndHandleExitCode(@NotNull MessageCollector messageCollector, public static void outputCompilerMessagesAndHandleExitCode(
@NotNull MessageCollector messageCollector,
@NotNull OutputItemsCollector outputItemsCollector, @NotNull OutputItemsCollector outputItemsCollector,
@NotNull Function<PrintStream, Integer> compilerRun) { @NotNull Function<PrintStream, Integer> compilerRun
) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintStream out = new PrintStream(outputStream); PrintStream out = new PrintStream(outputStream);