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

com.alibaba.tamper.process.script.jexl.JexlScriptExecutor Maven / Gradle / Ivy

The newest version!
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 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();
        engine = new ScriptJexlEngine();
        engine.setCache(cacheSize);
        engine.setSilent(true);
        engine.setFunctions(functions); // 注册functions
    }

    public ScriptContext genScriptContext(Map context) {
        return new JexlScriptContext(context);
    }

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

    /**
     * 
     * 1. 接受JexlScriptContext上下文
     * 2. script针对对应name下的script脚本
     * 
*/ 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> usedFunctions = null; public ScriptJexlEngine(){ super(null, null, null, null); usedFunctions = new ThreadLocal>() { protected Set initialValue() { return new HashSet(); // 线程安全,不全同步 } }; } 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 functions = usedFunctions.get(); for (Object function : functions) { if (function != null && DisposableScript.class.isAssignableFrom(function.getClass())) { ((DisposableScript) function).dispose();// 回调 } } } finally { usedFunctions.set(new HashSet());// 清空 } } }