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

org.voovan.tools.compiler.clazz.DynamicClass Maven / Gradle / Ivy

package org.voovan.tools.compiler.clazz;

import org.voovan.Global;
import org.voovan.tools.TFile;
import org.voovan.tools.TObject;
import org.voovan.tools.TString;
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;

/**
 * 动态类管理类
 *
 * @author: helyho
 * Voovan Framework.
 * WebSite: https://github.com/helyho/Voovan
 * Licence: Apache v2 License
 */
public class DynamicClass {

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

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

    private boolean needCompile;


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

    /**
     * 构造函数
     *       默认使用文件名作为命名
     * @param file    脚本文件路径
     * @param charset 脚本文件编码
     * @throws UnsupportedEncodingException 字符集异常
     */
    public DynamicClass(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.addClazz(this);

    }

    /**
     * 初始化
     */
    private void init() {
        this.name = null;
        this.code = null;
        this.clazz = Object.class;
        this.codeFile = null;
        this.needCompile = true;

        needCompile = true;

    }

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

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

    /**
     * 获取源代码
     * @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);
            }
        }

         codeClassName = DynamicCompiler.getClassNameFromCode(this.code);
         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() {

        if (this.clazz != Object.class && codeFile != null) {
            checkFileChanged();
        }

        if (this.clazz == Object.class || needCompile) {
            try {
                compileCode();
            } catch (ReflectiveOperationException e) {
                e.printStackTrace();
                this.clazz = null;
            }
        }

        return clazz;
    }

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

    /**
     * 生成代码
     *
     * @return 生成 java 代码;
     */
    private String genCode() {
        getCode();
        String javaCode = TString.fastReplaceAll(code, "class +" + codeClassName, "class {{CLASSNAME}}");
        genClassName();

        this.javaCode = TString.tokenReplace(javaCode, TObject.asMap(
                "CLASSNAME", className //类名
        ));

        return this.javaCode;
    }

    /**
     * 编译用户代码
     *
     * @throws ReflectiveOperationException 反射异常
     */
    public void compileCode() throws ReflectiveOperationException {

        if (this.clazz != Object.class && codeFile != null) {
            checkFileChanged();
        }

        if (this.clazz == Object.class || needCompile) {
            synchronized (this.clazz) {
                genCode();

                DynamicCompiler compiler = new DynamicCompiler();
                if (compiler.compileCode(this.javaCode)) {
                    this.clazz = compiler.getClazz();
                    this.className = this.clazz.getCanonicalName();
                    needCompile = false;
                } 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;
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy