All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.script.engine.java.JavaEngine Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
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