org.zodiac.script.engine.java.JavaEngine Maven / Gradle / Ivy
package org.zodiac.script.engine.java;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zodiac.commons.crypto.Md5;
import org.zodiac.commons.util.Classes;
import org.zodiac.commons.util.Colls;
import org.zodiac.commons.util.FileUtil;
import org.zodiac.commons.util.Strings;
import org.zodiac.script.engine.ExecuteResult;
import org.zodiac.script.engine.ListenerSupportEngine;
import org.zodiac.script.engine.ScriptContext;
import javax.script.ScriptException;
import javax.tools.*;
import java.io.File;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class JavaEngine extends ListenerSupportEngine {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
private String savePath = null;
private String classpath = "";
private Map cache = Colls.concurrentMap();
private URL[] loaderUrl;
public JavaEngine() throws Exception {
savePath = System.getProperty("java.io.tmpdir").concat("/org/hsweb/java/engine/");
new File(savePath + "src").mkdirs();
new File(savePath + "bin").mkdirs();
classpath = System.getProperty("java.class.path");
loaderUrl = new URL[] {new File(savePath + "bin").toURI().toURL()};
}
@Override
public void init(String... contents) throws Exception {
}
public String getClassName(String code) {
String name = Strings.firstMatch("class\\s+([\\w\\d$_]+)s*", code);
if (name == null)
return name;
return name.substring(5, name.length()).trim();
}
public String getPackage(String code) {
String name = Strings.firstMatch("package\\s+([\\w\\d$.]+)s*", code);
if (name == null)
return name;
return name.substring(7, name.length()).trim();
}
@Override
public boolean compile(String id, String code) throws Exception {
String name = getClassName(code);
String packageName = getPackage(code);
if (Strings.isNotEmpty(packageName)) {
name = packageName + "." + name;
}
try {
// 企图覆盖非动态编译的类
Class.forName(name);
throw new UnsupportedOperationException("class " + name + " is exists!");
} catch (ClassNotFoundException e) {
}
String fileName = savePath + "src/" + name.replace('.', '/') + ".java";
File file = new File(fileName);
if (file.exists())
file.delete();
FileUtil.write(code, fileName);
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector diagnostics = new DiagnosticCollector<>();
List jfiles = Colls.list();
StandardJavaFileManager fm = compiler.getStandardFileManager(null, Locale.CHINA, Charset.forName("UTF-8"));
jfiles.add(new CharSequenceJavaFileObject(savePath, name, code));
List options = Colls.list();
options.add("-d");
options.add(savePath + "bin");
options.add("-cp");
options.add(classpath);
if (logger.isDebugEnabled()) {
logger.debug("javac [{}] -> {}", fileName, options.stream().reduce((s, s2) -> s + " " + s2).get());
logger.debug(code);
}
JavaCompiler.CompilationTask task = compiler.getTask(null, fm, diagnostics, options, null, jfiles);
boolean success = task.call();
if (success) {
DynamicClassLoader dynamicClassLoader =
new DynamicClassLoader(loaderUrl, JavaEngine.class.getClassLoader());
Class> clazz = dynamicClassLoader.loadClass(name);
Executor executor = null;
if (Classes.instanceOf(clazz, Executor.class)) {
executor = (Executor)clazz.newInstance();
}
JavaCodeContext context = new JavaCodeContext(id, Md5.md5Hex(code), clazz, executor);
cache.put(id, context);
dynamicClassLoader.close();
return clazz != null;
} else {
StringBuilder builder = new StringBuilder();
for (Diagnostic> diagnostic : diagnostics.getDiagnostics()) {
builder.append(diagnostic).append("\n");
}
throw new ScriptException(builder.toString());
}
}
@Override
public ExecuteResult execute(String id) {
return execute(id, Colls.map());
}
@Override
public ExecuteResult execute(String id, Map param) {
long startTime = System.currentTimeMillis();
ExecuteResult result = new ExecuteResult();
JavaCodeContext context = cache.get(id);
try {
if (context != null) {
doListenerBefore(context);
Executor executor = context.getExecutor();
Class clazz = context.getCodeClass();
if (executor != null) {
Map var = Colls.map(param);
var.putAll(getGlobalVariable());
result.setResult(executor.execute(var));
result.setSuccess(true);
} else {
result.setSuccess(true);
result.setResult(clazz);
}
} else {
result.setSuccess(false);
result.setResult(null);
result.setMessage(String.format("class(%s): %s not found!", id, "java"));
}
} catch (Exception e) {
result.setException(e);
}
result.setUseTime(System.currentTimeMillis() - startTime);
doListenerAfter(context, result);
return result;
}
@Override
public boolean remove(String id) {
return cache.remove(id) != null;
}
@Override
public boolean compiled(String id) {
return cache.containsKey(id);
}
@Override
public ScriptContext getContext(String id) {
return cache.get(id);
}
protected class JavaCodeContext extends ScriptContext {
private Class codeClass;
private Executor executor;
public JavaCodeContext(String id, String md5, Class codeClass, Executor executor) {
super(id, md5);
this.codeClass = codeClass;
this.executor = executor;
}
public Class getCodeClass() {
return codeClass;
}
public Executor getExecutor() {
return executor;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy