Package com.alibaba.tamper.process.script.jexl

Source Code of com.alibaba.tamper.process.script.jexl.JexlScriptContext

package com.alibaba.tamper.process.script.jexl;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.Interpreter;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.apache.commons.jexl2.parser.JexlNode;

import com.alibaba.tamper.process.script.ScriptContext;
import com.alibaba.tamper.process.script.ScriptExecutor;
import com.alibaba.tamper.process.script.lifecyle.DisposableScript;
import com.alibaba.tamper.process.script.lifecyle.InitializingScript;

/**
* Jexl的script实现
*
* @author jianghang 2011-5-25 下午08:08:45
*/
public class JexlScriptExecutor implements ScriptExecutor {

    private static final int    DEFAULT_CACHE_SIZE = 1000;
    private ScriptJexlEngine    engine;
    private Map<String, Object> functions;
    private int                 cacheSize          = DEFAULT_CACHE_SIZE;

    public JexlScriptExecutor(){
        initialize();
    }

    /**
     * 初始化function
     */
    public void initialize() {
        if (cacheSize <= 0) {// 不考虑cacheSize为0的情况,强制使用LRU cache机制
            cacheSize = DEFAULT_CACHE_SIZE;
        }

        functions = new HashMap<String, Object>();
        engine = new ScriptJexlEngine();
        engine.setCache(cacheSize);
        engine.setSilent(true);
        engine.setFunctions(functions); // 注册functions
    }

    public ScriptContext genScriptContext(Map<String, Object> context) {
        return new JexlScriptContext(context);
    }

    public Object evaluate(Map<String, Object> context, String script) {
        return evaluate(genScriptContext(context), script);
    }

    /**
     * <pre>
     * 1. 接受JexlScriptContext上下文
     * 2. script针对对应name下的script脚本
     * </pre>
     */
    public Object evaluate(ScriptContext context, String script) {
        Expression expr = engine.createExpression(script);
        return expr.evaluate((JexlContext) context);
    }

    // ============================ setter / getter ============================

    public void setCacheSize(int cacheSize) {
        this.cacheSize = cacheSize;
    }

    public void addFunction(String name, Object obj) {
        this.functions.put(name, obj);
    }

    public void disposeFunctions() {
        engine.disposeUsedFunctions();
    }

}

/**
* 定义为Jexl context
*
* @author jianghang 2011-5-25 下午07:57:59
*/
class JexlScriptContext extends MapContext implements ScriptContext {

    public JexlScriptContext(Map map){
        super(map);
    }
}

/**
* 扩展jexl的实现,提供{@linkplain InitializingScript},{@linkplain DisposableScript}的管理
*/
class ScriptJexlEngine extends JexlEngine {

    // 记录script执行过程中使用过的function
    private ThreadLocal<Set<Object>> usedFunctions = null;

    public ScriptJexlEngine(){
        super(null, null, null, null);
        usedFunctions = new ThreadLocal<Set<Object>>() {

            protected Set<Object> initialValue() {
                return new HashSet<Object>(); // 线程安全,不全同步
            }
        };
    }

    protected Interpreter createInterpreter(JexlContext context) {
        if (context == null) {
            context = EMPTY_CONTEXT;
        }
        return new ScriptInterpreter(this, context);
    }

    class ScriptInterpreter extends Interpreter {

        public ScriptInterpreter(JexlEngine jexl, JexlContext aContext){
            super(jexl, aContext);
        }

        protected Object resolveNamespace(String prefix, JexlNode node) {
            Object result = super.resolveNamespace(prefix, node);
            if (result != null) {
                boolean contains = usedFunctions.get().add(result);// 添加到使用记录中
                if (contains && InitializingScript.class.isAssignableFrom(result.getClass())) {// 第一次添加
                    ((InitializingScript) result).initial();// 回调
                }
            }
            return result;
        }
    }

    public void disposeUsedFunctions() {
        try {
            Set<Object> functions = usedFunctions.get();
            for (Object function : functions) {
                if (function != null && DisposableScript.class.isAssignableFrom(function.getClass())) {
                    ((DisposableScript) function).dispose();// 回调
                }
            }
        } finally {
            usedFunctions.set(new HashSet<Object>());// 清空
        }
    }

}
TOP

Related Classes of com.alibaba.tamper.process.script.jexl.JexlScriptContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.