package li.template.compiler;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
/**
* JdkCompiler. (SPI, Singleton, ThreadSafe)
*
* @see httl.spi.parsers.AbstractParser#setCompiler(Compiler)
* @author Liang Fei (liangfei0201 AT gmail DOT com)
*/
public class DefaultCompiler {
private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
private final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
private final ClassLoaderImpl classLoader;
private final JavaFileManagerImpl javaFileManager;
private final List<String> options = new ArrayList<String>();
private final List<String> lintOptions = new ArrayList<String>();
public DefaultCompiler() {
if (compiler == null) {
throw new IllegalStateException("Can not get system java compiler. Please add jdk tools.jar to your classpath.");
}
StandardJavaFileManager manager = compiler.getStandardFileManager(diagnosticCollector, null, null);
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader instanceof URLClassLoader && (!loader.getClass().getName().equals("sun.misc.Launcher$AppClassLoader"))) {
try {
URLClassLoader urlClassLoader = (URLClassLoader) loader;
List<File> files = new ArrayList<File>();
for (URL url : urlClassLoader.getURLs()) {
files.add(new File(url.getFile()));
}
manager.setLocation(StandardLocation.CLASS_PATH, files);
} catch (IOException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoaderImpl>() {
public ClassLoaderImpl run() {
return new ClassLoaderImpl(loader);
}
});
javaFileManager = new JavaFileManagerImpl(manager, classLoader);
lintOptions.add("-Xlint:unchecked");
}
public Class<?> doCompile(String name, String sourceCode) throws Exception {
try {
return doCompile(name, sourceCode, options);
} catch (Exception e) {
if (e.getMessage().contains("-Xlint:unchecked")) {
try {
return doCompile(name, sourceCode, lintOptions);
} catch (Exception e2) {
throw e2;
}
}
throw e;
}
}
private Class<?> doCompile(String name, String sourceCode, List<String> options) throws Exception {
try {
return classLoader.findClass(name);
} catch (ClassNotFoundException e) {
int i = name.lastIndexOf('.');
String packageName = i < 0 ? "" : name.substring(0, i);
String className = i < 0 ? name : name.substring(i + 1);
JavaFileObjectImpl javaFileObject = new JavaFileObjectImpl(className, sourceCode);
javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName, className + ".java", javaFileObject);
Boolean result = compiler.getTask(null, javaFileManager, diagnosticCollector, options, null, Arrays.asList(new JavaFileObject[] { javaFileObject })).call();
if (result == null || !result.booleanValue()) {
throw new IllegalStateException("Compilation failed. class: " + name + ", diagnostics: " + diagnosticCollector.getDiagnostics());
}
return classLoader.loadClass(name);
}
}
}