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.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jarvis.cache.CacheUtil; /** * 解析JavaScript表达式 * @author jiayu.qiu */ public class JavaScriptParser extends AbstractScriptParser { private static final Logger logger=LoggerFactory.getLogger(JavaScriptParser.class); private final ScriptEngineManager manager=new ScriptEngineManager(); private final ConcurrentHashMap<String, CompiledScript> expCache=new ConcurrentHashMap<String, CompiledScript>(); private final StringBuffer funcs=new StringBuffer(); private static int versionCode; /** * 如果使用的是JDK大于1.8版本的,则用 nashorn,否则用javascript */ private final ScriptEngine engine; static { 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); } public JavaScriptParser() { engine=manager.getEngineByName(versionCode >= 18 ? "nashorn" : "javascript"); try { addFunction(HASH, CacheUtil.class.getDeclaredMethod("getUniqueHashStr", new Class[]{Object.class})); addFunction(EMPTY, CacheUtil.class.getDeclaredMethod("isEmpty", new Class[]{Object.class})); } catch(Exception e) { logger.error(e.getMessage(), e); } } @Override public void addFunction(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); } } @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); } } }