package org.sakaiproject.util;
import java.io.File;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
/**
* Thin wrapper around the JDK's interface to javac.
*
* @author dmccallum@unicon.net
*
*/
public class Compiler {
private Object jdkCompiler;
boolean isJavaxCompiler = false;
public Compiler() {
refresh();
}
public boolean isUseable() {
return jdkCompiler != null;
}
public boolean refresh() {
try {
Class toolProvider = getClass().getClassLoader().loadClass("javax.tools.ToolProvider");
jdkCompiler = toolProvider.getMethod("getSystemJavaCompiler").invoke(null);
isJavaxCompiler = true;
} catch ( Exception e ) {
// fall back to trying for the com.sun compiler
throw new RuntimeException(e);
}
if ( jdkCompiler == null ) {
try {
jdkCompiler = loadClass("com.sun.tools.javac.Main");
} catch ( ClassNotFoundException e ) {
}
}
return isUseable();
}
public void compile(File srcFile, File outDir, PrintWriter log) {
if ( !(isUseable()) ) {
throw new IllegalStateException("Could not load JDK compiler");
}
if ( isJavaxCompiler ) {
compileWithJavaxCompiler(srcFile, outDir, log);
} else {
compileWithSunCompiler(srcFile, outDir, log);
}
}
private void compileWithSunCompiler(File srcFile, File outDir, PrintWriter log) {
try {
Method jdkCompile = ((Class)jdkCompiler).getMethod("compile", String[].class, PrintWriter.class);
String[] options = { "-g",
"-source",
"1.5",
"-target",
"1.5",
"-d",
outDir.getAbsolutePath(),
srcFile.getAbsolutePath()};
jdkCompile.invoke(null, options, log);
} catch ( NoSuchMethodException e ) {
throw new UnsupportedOperationException("Unable to locate JDK compile() method", e);
} catch ( IllegalAccessException e) {
throw new UnsupportedOperationException("Unable to invoke JDK compile() method", e);
} catch ( InvocationTargetException e ) {
throw new UnsupportedOperationException("Unable to invoke JDK compile() method", e);
}
}
private void compileWithJavaxCompiler(File srcFile, File outDir, PrintWriter log) {
try {
Class diagnosticListenerClass = loadClass("javax.tools.DiagnosticListener");
Object fileManager = jdkCompiler.getClass().getDeclaredMethod("getStandardFileManager",
diagnosticListenerClass, Locale.class, Charset.class).invoke(jdkCompiler, null, null, null);
Class fileManagerClass = loadClass("javax.tools.JavaFileManager");
List<String> options = Arrays.asList(new String[] { "-d", outDir.getAbsolutePath() });
Object compilationUnits =
fileManager.getClass().getDeclaredMethod("getJavaFileObjectsFromFiles", Iterable.class)
.invoke(fileManager, Arrays.asList(srcFile));
Method getTaskMethod =
jdkCompiler.getClass().getDeclaredMethod("getTask",
Writer.class, fileManagerClass, diagnosticListenerClass,
Iterable.class, Iterable.class, Iterable.class);
@SuppressWarnings("unchecked")
Callable<Boolean> compileTask = (Callable<Boolean>)
getTaskMethod.invoke(jdkCompiler, null, fileManager, null, options, null, compilationUnits);
if ( !(compileTask.call()) ) {
throw new RuntimeException("Compilation failed");
}
} catch ( Exception e ) {
throw new UnsupportedOperationException("Unable to execute JavaCompiler", e);
}
}
private Class loadClass(String name) throws ClassNotFoundException {
return getClass().getClassLoader().loadClass(name);
}
}