package com.jarvis.cache.script;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;

import org.apache.log4j.Logger;

import com.jarvis.cache.CacheUtil;

/**
 * 解析JavaScript表达式
 * @author jiayu.qiu
 */
public class JavaScriptParser implements IScriptParser {

    private static final Logger logger=Logger.getLogger(JavaScriptParser.class);

    private static final ScriptEngineManager manager=new ScriptEngineManager();

    private final ConcurrentHashMap<String, CompiledScript> expCache=new ConcurrentHashMap<String, CompiledScript>();

    private static final StringBuffer funcs=new StringBuffer();

    private static int versionCode;
    static {
        try {
            registerFunction(HASH, CacheUtil.class.getDeclaredMethod("getUniqueHashStr", new Class[]{Object.class}));
            registerFunction(EMPTY, CacheUtil.class.getDeclaredMethod("isEmpty", new Class[]{Object.class}));
        } catch(Exception e) {
            logger.error(e.getMessage(), e);
        }
        String javaVersion=System.getProperty("java.version");
        int ind=0;
        for(int i=0; i < 2; i++) {
            ind=javaVersion.indexOf(".", ind);
            ind++;
        }
        javaVersion=javaVersion.substring(0, ind);
        javaVersion=javaVersion.replaceAll("\\.", "");
        versionCode=Integer.parseInt(javaVersion);
    }

    /**
     * 如果使用的是JDK大于1.8版本的，则用 nashorn，否则用javascript
     */
    private static final ScriptEngine engine=manager.getEngineByName(versionCode > 18 ? "nashorn" : "javascript");

    private static void registerFunction(String name, Method method) {
        try {
            String clsName=method.getDeclaringClass().getName();
            String methodName=method.getName();
            funcs.append("function " + name + "(obj){return " + clsName + "." + methodName + "(obj);}");
        } catch(Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    @Override
    public void addFunction(String name, Method method) {
        registerFunction(name, method);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getElValue(String exp, Object[] arguments, Object retVal, boolean hasRetVal, Class<T> valueType) throws Exception {
        Bindings bindings=new SimpleBindings();
        bindings.put(ARGS, arguments);
        if(hasRetVal) {
            bindings.put(RET_VAL, retVal);
        }
        CompiledScript script=expCache.get(exp);
        if(null != script) {
            return (T)script.eval(bindings);
        }
        if(engine instanceof Compilable) {
            Compilable compEngine=(Compilable)engine;
            script=compEngine.compile(funcs + exp);
            expCache.put(exp, script);
            return (T)script.eval(bindings);
        } else {
            return (T)engine.eval(funcs + exp, bindings);
        }
    }

}

@@ -603,39 +603,32 @@
 %0D%0A%0D%0A    private 
-static 
 final ScriptEngi
@@ -790,16 +790,18 @@
 Script%3E(
+64
 );%0D%0A%0D%0A  
@@ -806,31 +806,24 @@
     private 
-static 
 final String
@@ -899,354 +899,131 @@
 e;%0D%0A
-    static %7B%0D%0A        try %7B%0D%0A            registerFunction(HASH, CacheUtil.class.getDeclaredMethod(%22getUniqueHashStr%22, new Class%5B%5D%7BObject.class%7D));%0D%0A            registerFunction(EMPTY, CacheUtil.class.getDeclaredMethod(%22isEmpty%22, new Class%5B%5D%7BObject.class%7D));%0D%0A        %7D catch(Exception e) %7B%0D%0A            logger.error(e.getMessage(), e);%0D%0A        %7D
+%0D%0A    /**%0D%0A     * %E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8%E7%9A%84%E6%98%AFJDK%E5%A4%A7%E4%BA%8E1.8%E7%89%88%E6%9C%AC%E7%9A%84%EF%BC%8C%E5%88%99%E7%94%A8 nashorn%EF%BC%8C%E5%90%A6%E5%88%99%E7%94%A8javascript%0D%0A     */%0D%0A    private final ScriptEngine engine;%0D%0A    static %7B
 %0D%0A  
@@ -1396,110 +1396,44 @@
     
-/**%0D%0A     * %E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8%E7%9A%84%E6%98%AFJDK%E5%A4%A7%E4%BA%8E1.8%E7%89%88%E6%9C%AC%E7%9A%84%EF%BC%8C%E5%88%99%E7%94%A8 nashorn%EF%BC%8C%E5%90%A6%E5%88%99%E7%94%A8javas
+public JavaS
 cript
-%0D%0A     */%0D%0A    private static final ScriptEngine
+Parser() %7B%0D%0A       
  eng
@@ -1511,42 +1511,375 @@
 );%0D%0A
-%0D%0A    private static void register
+        try %7B%0D%0A            addFunction(HASH, CacheUtil.class.getDeclaredMethod(%22getUniqueHashStr%22, new Class%5B%5D%7BObject.class%7D));%0D%0A            addFunction(EMPTY, CacheUtil.class.getDeclaredMethod(%22isEmpty%22, new Class%5B%5D%7BObject.class%7D));%0D%0A        %7D catch(Exception e) %7B%0D%0A            logger.error(e.getMessage(), e);%0D%0A        %7D%0D%0A    %7D%0D%0A%0D%0A    @Override%0D%0A    public void add
 Func
@@ -2252,132 +2252,8 @@
 %0D%0A%0D%0A
-    @Override%0D%0A    public void addFunction(String name, Method method) %7B%0D%0A        registerFunction(name, method);%0D%0A    %7D%0D%0A%0D%0A
     

优化JavaScriptParser 代码结构