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

org.voovan.tools.compiler.function.DynamicFunction Maven / Gradle / Ivy

There is a newer version: 4.3.8
Show newest version
package org.voovan.tools.compiler.function;

import org.voovan.Global;
import org.voovan.tools.*;
import org.voovan.tools.buffer.ByteBufferChannel;
import org.voovan.tools.collection.MultiMap;
import org.voovan.tools.compiler.DynamicCompiler;
import org.voovan.tools.compiler.DynamicCompilerManager;
import org.voovan.tools.log.Logger;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.voovan.tools.TString.TOKEN_PREFIX;
import static org.voovan.tools.TString.TOKEN_SUFFIX;

/**
 * 动态函数管理类
 *      为了安全问题,默认不外部包导入功能,如果需要可以使用 setEnableImportInCode 方法设置
 *
 * @author: helyho
 * Voovan Framework.
 * WebSite: https://github.com/helyho/Voovan
 * Licence: Apache v2 License
 */
public class DynamicFunction {
    private static String CODE_TEMPLATE = new String(TFile.loadResource("org/voovan/tools/compiler/function/CodeTemplate.vct"));

    static {
        CODE_TEMPLATE = CODE_TEMPLATE.replace("<",TOKEN_PREFIX).replace(">",TOKEN_SUFFIX);
    }

    //导入类预置
    private List importClasses;

    //参数预置
    private MultiMap args;
    private String argCode;

    //是否支持代码中的导入
    private boolean enableImportInCode;


    //动态编译相关的对象
    private String packageName;
    private String name;
    private String className;
    private String importCode;
    private String bodyCode;
    private String code;
    private String javaCode;
    private Class clazz;


    private File codeFile;
    private String fileCharset;
    private long lastFileTimeStamp;

    private boolean needCompile;

    private String importFunctionCode;
    private ArrayList importFunctions;

    public FunctionInterface objectForCall;



    /**
     * 构造函数
     *
     * @param name 命名的名称
     * @param code 用户代码
     */
    public DynamicFunction(String name, String code) {
        init();
        this.name = name;
        this.code = code;
        DynamicCompilerManager.addFunction(this);
    }

    /**
     * 构造函数
     *
     * @param file    用户代码路径
     * @param charset 用户代码编码
     * @throws UnsupportedEncodingException 字符集异常
     */
    public DynamicFunction(File file, String charset) throws UnsupportedEncodingException {
        init();
        String fileName = TFile.getFileName(file.getPath());
        this.name = fileName.substring(0, fileName.lastIndexOf("."));
        this.codeFile = file;
        this.fileCharset = charset;
        this.lastFileTimeStamp = file.lastModified();
        DynamicCompilerManager.addFunction(this);
    }

    /**
     * 初始化
     */
    private void init() {
        this.packageName = "org.voovan.tools.compiler.temporary;\r\n";
        this.name = null;
        this.argCode = null;
        this.importCode = "";
        this.bodyCode = "";
        this.code = null;
        this.javaCode = "";
        this.clazz = null;
        this.codeFile = null;

        needCompile = true;
        enableImportInCode = false;

        this.importClasses = new ArrayList();
        this.args = new MultiMap();

        this.importFunctionCode = "";
        this.importFunctions = new ArrayList();
    }

    /**
     * 获取包名
     *      默认:org.voovan.tools.compiler.temporary
     * @return  包名
     */
    public String getPackageName() {
        return packageName;
    }

    /**
     * 设置包名
     *      默认:org.voovan.tools.compiler.temporary
     * @param packageName 包名
     */
    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    /**
     * 获得命名的名称
     *       用于标定这个动态编译的函数
     *
     * @return 命名的名称
     */
    public String getName() {
        return this.name;
    }

    /**
     * 设置命名的名称
     *
     * @param name 命名的名称
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取是否支持代码中的 import
     * @return true:支持代码中的 import, false: 不支持代码中的 import
     */
    public boolean isEnableImportInCode() {
        return enableImportInCode;
    }

    /**
     * 设置是否支持代码中 import
     * @param enableImportInCode true:支持代码中的 import, false:不支持代码中的 import
     */
    public void enableImportInCode(boolean enableImportInCode) {
        this.enableImportInCode = enableImportInCode;
    }

    /**
     * 获取用户代码
     * @return 用户代码
     */
    public String getCode() {
        if (codeFile != null) {
            try {
                this.code = new String(TFile.loadFile(this.codeFile), this.fileCharset);
            } catch (UnsupportedEncodingException e) {
                Logger.error("Load file " + this.codeFile.getPath() + " error", e);
            }
        }

        return code;
    }

    /**
     * 设置脚本代码
     *
     * @param code 脚本代码
     */
    public void setCode(String code) {
        if (codeFile == null) {
            this.code = code;
            needCompile = true;
        } else {
            throw new RuntimeException("This function used code in file, Can't invoke this method.");
        }
    }

    /**
     * 得到实际编译的类名称
     *
     * @return 实际编译的类名称
     */
    public String getClassName() {
        return className;
    }

    /**
     * 获得编译后的 Class 对象
     *
     * @return 实际编译的类对象
     */
    public Class getClazz() {
        return clazz;
    }

    /**
     * 增加一个调用参数
     *
     * @param argIndex  调用参数的索引
     * @param argClazz  调用参数的类
     * @param argName      调用参数的名称
     */
    public void addPrepareArg(int argIndex, Class argClazz, String argName) {
        args.putValues(argIndex, argClazz, argName);
    }

    /**
     * 移除一个调用参数
     *
     * @param argIndex 调用参数的索引
     */
    public void removePrepareArg(int argIndex) {
        args.remove(argIndex);
    }

    /**
     * 增加预置到处类
     * @param clazz 导入类对象
     */
    public void addImport(Class clazz){
        this.importClasses.add(clazz);
    }

    /**
     * 移除预置导入类
     * @param clazz 导入类对象
     */
    public void removeImport(Class clazz){
        this.importClasses.remove(clazz);
    }


    /**
     * 生成预置导入代码
     */
    private void genImports(){
        this.importCode = "";

        for(Class importClass : importClasses) {
            this.importCode = this.importCode + "import " + importClass.getCanonicalName() + ";\r\n";
        }

        this.importCode = this.importCode + TFile.getLineSeparator();
    }


    /**
     * 增加一个导入函数
     * @param name 动态函数名称
     */
    public void addImportFunction(String name){
        importFunctions.add(name);
        if(!importClasses.contains(DynamicCompilerManager.class)) {
            importClasses.add(DynamicCompilerManager.class);
        }
    }

    /**
     * 获取导入函数集合
     * @return List导入函数集合
     */
    public List getImportFunctionx(){
        return importFunctions;
    }

    /**
     * 清空导入函数集合
     */
    public void clearImportFunctions(){
        importFunctions.clear();
        importClasses.remove(DynamicCompilerManager.class);
    }

    private void genImportFunction(){
        for(String dynamicFunctionName : importFunctions){
            importFunctionCode = importFunctionCode + "private static Object "+dynamicFunctionName+"(Object ... args) throws Exception { \r\n "+
                    "        return DynamicCompilerManager.callFunction(\""+dynamicFunctionName+"\", args); \r\n" +
                    "    } \r\n" ;
        }
    }

    /**
     * 生成编译时混淆的类名
     */
    private void genClassName() {
        this.className = this.name + "_VDF_" + Global.UNIQUE_ID.nextString();
    }

    /**
     * 生成可调用参数
     */
    private void genArgCode() {
        this.argCode = "";
        for (Map.Entry> prepareArg : args.entrySet()) {
            int argIndex = prepareArg.getKey();
            Class argClazz = (Class)args.getValue(argIndex, 0);
            String argName = (String)args.getValue(argIndex, 1);
            this.argCode = this.argCode + "        " + argClazz.getCanonicalName() + " " + argName +           //生成代码类型 java.lang.String aaa
                    " = ("+argClazz.getCanonicalName()+") args[" + argIndex + "];" + TFile.getLineSeparator();  // 生成代码类似 = (java.lang.String)args[i];
        }
        this.argCode = this.argCode.trim() + "\r\n";
    }

    /**
     * 解析用户代码
     */
    private void parseCode() {
        if (this.codeFile != null) {
            this.code = getCode();
        }

        if (this.code == null) {
            throw new NullPointerException("Function code is null.");
        }

        if (!this.code.contains("return ")) {
            this.code = this.code + "\r\n       return null;";
        }

        this.bodyCode = "";
        ByteBufferChannel byteBufferChannel = new ByteBufferChannel();
        byteBufferChannel.writeEnd(ByteBuffer.wrap(this.code.getBytes()));
        while (true) {
            String lineCode = byteBufferChannel.readLine();
            if (lineCode == null) {
                break;
            }
            if (lineCode.trim().startsWith("import ")) {
                if(enableImportInCode) {
                    this.importCode = importCode + lineCode;
                }
            } else {
                this.bodyCode = bodyCode + lineCode;
            }
        }

        this.bodyCode = TString.indent(this.bodyCode, 8).trim();
        byteBufferChannel.release();
    }

    /**
     * 生成代码
     *
     * @return 生成 java 代码;
     */
    private String genCode() {

        genImports();
        genImportFunction();
        genClassName();
        genArgCode();
        parseCode();

        this.javaCode = TString.tokenReplace(CODE_TEMPLATE, TObject.asMap(
                "PACKAGE",          packageName,          //包名
                "IMPORT",           importCode,           //解析获得
                "IMPORTFUNCTION",   importFunctionCode,   //生成导入函数的映射函数
                "CLASSNAME",        className,            //类名
                "PREPARE_ARG",      argCode,              //参数
                "CODE",             bodyCode              //解析获得
        ));

        return this.javaCode;
    }

    /**
     * 编译用户代码
     *
     * @throws ReflectiveOperationException 反射异常
     */
    public void compileCode() throws ReflectiveOperationException {
        if (this.clazz != null && codeFile != null) {
            checkFileChanged();
        }

        if (this.clazz == null || this.needCompile) {
            genCode();

            DynamicCompiler compiler = new DynamicCompiler();
            if (compiler.compileCode(this.javaCode)) {
                this.clazz = compiler.getClazz();
                this.className = this.clazz.getCanonicalName();
                this.needCompile = false;
                this.objectForCall = (FunctionInterface) clazz.newInstance();
            } else {
                Logger.simple(code);
                throw new ReflectiveOperationException("Compile code error.");
            }
        }
    }


    /**
     * 测试文件是否变更
     */
    private void checkFileChanged() {
        if (lastFileTimeStamp != this.codeFile.lastModified()) {
            this.lastFileTimeStamp = this.codeFile.lastModified();
            needCompile = true;
        }

    }

    /**
     * 执行动态函数
     *
     * @param args 调用参数
     * @param   范型
     * @return 返回的类型
     * @throws Exception 反射异常
     */
    public  T call(Object... args) throws Exception {
        compileCode();
        return (T)objectForCall.execute(args);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy