/**
* @author liaochuntao
*/
@Slf4j
@Component
@Scope("singleton")
public final class CompilerPool{
// 获取机器的可用的CPU核心数
private final static int COMPILER_POOL_SIZE = Runtime.getRuntime().availableProcessors();
private final static ConcurrentLinkedQueue COMPILER_POOL = new ConcurrentLinkedQueue<>();
private final static ClassLoader parentClassloader = CompilerPool.class.getClassLoader();
static {
for (int i = 0; i < COMPILER_POOL_SIZE; i ++) {
COMPILER_POOL.add(new TensorJavaCompiler());
}
}
public CompilerResult work(String javaName, String javaSourceCode){
TensorJavaCompiler compiler = COMPILER_POOL.poll();
if (compiler == null) {
return new CompilerResult();
}
return compiler.buildTask(javaName, javaSourceCode).compile(new CompilerResult());
}
private final static class TensorJavaCompiler{
private volatile boolean isRunning;
private JavaCompiler compiler;
private DiagnosticCollector diagnostics;
private String javaName;
private JavaCompiler.CompilationTask task;
private TensorClassLoader classLoader;
private String classpath;
private ClassFileManager fileManager;
private TensorJavaCompiler(){
isRunning = false;
compiler = ToolProvider.getSystemJavaCompiler();
diagnostics = new DiagnosticCollector<>();
classLoader = new TensorClassLoader(parentClassloader);
fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnostics, null, null));
buildClassPath();
}
// 构建classpath地址
void buildClassPath(){
this.classpath = null;
StringBuilder sb = new StringBuilder();
for (URL url : this.classLoader.getURLs()) {
String p = url.getFile();
sb.append(p).append(File.pathSeparator);
}
this.classpath = sb.toString();
}
// 构建JavaCompiler.CompilationTask对象
TensorJavaCompiler buildTask(String name, String source){
javaName = name;
List fileObjects = new ArrayList<>();
fileObjects.add(new JavaSourceObject(javaName, source));
List options = new ArrayList<>();
options.add("-encoding");
options.add("UTF-8");
options.add("-classpath");
options.add(this.classpath);
task = compiler.getTask(null, fileManager, diagnostics, options, null, fileObjects);
return this;
}
CompilerResult compile(CompilerResult result){
isRunning = true;
String compilerErr = "";
// task.call()开启了编译
if (task.call()) {
try {
// 此处更改System.out流的输出位置,以获取代码中的System.out\err等流的输出信息
PrintStream old = System.out;
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
PrintStream print = new PrintStream(bos);
System.setOut(print);
JavaClassObject classObject = fileManager.getJavaClassObject();
Class cls = classLoader.loadClass(javaName, classObject);
result.setResult(cls.getDeclaredMethod("main", String[].class).invoke(null, new Object[]{null}));
//恢复System流的原输出位置
System.setOut(old);
result.setPrintMsg(bos.toString());
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
log.error("compiler exception is ", e);
}
} else {
// 如果编译失败,获取错误信息
String compilerErr = "";
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
compilerErr += compilePrint(diagnostic);
}
result.setCompilerErr(compilerErr);
}
result.setTimeout(false);
release();
return result;
}
public boolean isRunning(){
return isRunning;
}
private void release(){
isRunning = false;
COMPILER_POOL.add(this);
}
private String compilePrint(Diagnostic diagnostic){
StringBuffer res = new StringBuffer();
res.append("Code:[").append(diagnostic.getCode()).append("]\n");
res.append("Kind:[").append(diagnostic.getKind()).append("]\n");
res.append("Position:[").append(diagnostic.getPosition()).append("]\n");
res.append("Start Position:[").append(diagnostic.getStartPosition()).append("]\n");
res.append("End Position:[").append(diagnostic.getEndPosition()).append("]\n");
res.append("Source:[").append(diagnostic.getSource()).append("]\n");
res.append("Message:[").append(diagnostic.getMessage(null)).append("]\n");
res.append("LineNumber:[").append(diagnostic.getLineNumber()).append("]\n");
res.append("ColumnNumber:[").append(diagnostic.getColumnNumber()).append("]\n");
return res.toString();
}
}
}