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

com.gitee.beiding.template_excel.Js Maven / Gradle / Ivy

package com.gitee.beiding.template_excel;

import javax.script.*;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Js {

    private static class JsHolder {
        private ScriptEngine engine;
        private Bindings bindings;
    }

    private static List functions = new ArrayList<>();

    private static List initializedFunctions;

    private static ThreadLocal jsHolderThreadLocal = new ThreadLocal<>();

    //创建定长的队列
    private static BlockingQueue jsHolders = new ArrayBlockingQueue<>(Config.getCoreJsWorkerNumber());

    //在每次执行完成之后使用该方法Js
    static void recycle() {
        JsHolder jsHolder = jsHolderThreadLocal.get();
        if (jsHolder != null) {
            jsHolders.offer(jsHolder);
            jsHolderThreadLocal.remove();
        }
    }


    private static JsHolder init() {

        JsHolder jsHolder = jsHolderThreadLocal.get();

        if (jsHolder == null) {
            jsHolder = jsHolders.poll();
            if (jsHolder == null) {
                if (initializedFunctions == null) {
                    synchronized (Js.class) {
                        if (initializedFunctions == null) {
                            initializedFunctions = functions;
                        }
                    }
                }

                //放入线程占位
                ScriptEngineManager manager = new ScriptEngineManager();
                ScriptEngine engine = manager.getEngineByName("nashorn");
                Bindings bindings = engine.getBindings(ScriptContext.GLOBAL_SCOPE);

                jsHolder = new JsHolder();
                jsHolder.engine = engine;
                jsHolder.bindings = bindings;
                jsHolderThreadLocal.set(jsHolder);

                //初始化脚本
                try {
                    set("console", new Console());
                    set("_java", new Java());
                    InputStream stream = Js.class.getClassLoader().getResource("init.js").openConnection().getInputStream();
                    String read = FileUtils.read(stream);
                    engine.eval(read);

                    for (String function : initializedFunctions) {
                        exe(function);
                    }

                } catch (Exception e) {
                    throw new Error(e);
                }
            } else {
                //绑定值
                jsHolderThreadLocal.set(jsHolder);
            }
        }

        return jsHolder;

    }

    //不能直接执行某些代码,防止引擎内部声明污染
    static Object exe(String js) throws ScriptException {
        try {
            // System.out.println(js);
            return init().engine.eval(js);
        } catch (Exception e) {
            throw e;
        }

    }


    public static void defineCommand(String s) {

        synchronized (Js.class) {
            if (functions == null) {
                throw new RuntimeException("请在Js使用前定义函数");
            }
        }

        String d1 = s.trim();

        if (!d1.startsWith("function")) {
            throw new RuntimeException("指令定义无效,必须以function开头");
        }

        String d2 = d1.substring(8).trim();

        System.out.println(d2);

        if (!d2.startsWith("$")) {
            throw new RuntimeException("指令名称必须以'$'开头");
        }

        functions.add(s);
    }


    public static Object call(String method, Object... p) {
        try {
            return ((Invocable) init().engine).invokeFunction(method, p);
        } catch (ScriptException | NoSuchMethodException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Object set(String k, Object v) {
        return init().bindings.put(k, v);
    }


    public static Object put(String k, Object v) {
        return init().bindings.put(k, v);
    }

    /**
     * 由于引擎是线程隔离的,调用该方法定义的函数只对晚于调用该方法初始化的引擎才是有效的
     *
     * @param s 定义的函数
     */

    //定义一个函数
    public static void defineFunction(String s) {

        synchronized (Js.class) {
            if (functions == null) {
                throw new RuntimeException("请在Js使用前定义函数");
            }
        }


        String d1 = s.trim();

        if (!d1.startsWith("function")) {
            throw new RuntimeException("指令定义无效,必须以function开头");
        }

        String d2 = d1.trim();

        if (d2.startsWith("$")) {
            throw new RuntimeException("函数名称不能以'$'开头");
        }

        functions.add(FunctionUtils.handleCacheableFunction(s));
    }

    public static Object remove(String k) {
        return init().bindings.remove(k);
    }

    public static Object get(String k) {
        return init().bindings.get(k);
    }

    public static void putAll(Map all) {
        init().bindings.putAll(all);
    }

    //提供控制台相关的功能
    public static class Console {
        public void log(String obj) {
            System.out.println(call("objToString", obj));
        }

        public void log() {
            System.out.println();
        }
    }

    //提供缓存操作
    private static class CacheTree {

        private static class Node {
            private Map subMap;
            private Object value;
        }

        //TODO  第一级参数
        private Map subMap;

        private Object value;

        void set(Object[] args, Object data) {
            if (args.length == 0) {
                value = data;
                return;
            }

            if (subMap == null) {
                subMap = new HashMap<>();
            }

            //从第一级参数开始递归
            Map sm = subMap;

            Node node = null;

            //一直找到最后一级参数
            for (Object key : args) {
                node = sm.computeIfAbsent(key, k -> new Node());
                if (node.subMap == null) {
                    node.subMap = new HashMap<>();
                }
                sm = node.subMap;
            }

            node.value = data;

        }

        Object get(Object[] args) {
            if (args.length == 0) {
                return value;
            }
            if (subMap == null) {
                return null;
            }
            Map sm = subMap;

            Node node = null;

            //一直找到最后一级参数
            for (Object key : args) {
                node = sm.get(key);
                if (node == null || node.subMap == null) {
                    return null;
                }
                sm = node.subMap;
            }

            return node.value;
        }

    }

    //对js提供java底层的操作
    public static class Java {

        //缓存数
        private Map treeMap = new HashMap<>();

        public void cachePut(String name, Object[] args, Object data) {
            CacheTree cacheTree = treeMap.computeIfAbsent(name, k -> new CacheTree());
            cacheTree.set(args, data);
        }

        public Object cacheGet(String name, Object[] args) {

            CacheTree cacheTree = treeMap.get(name);
            if (cacheTree == null) {
                return null;
            }

            return cacheTree.get(args);
        }

        //清空现有缓存
        public void clearCache() {
            treeMap = new HashMap<>();

            //辅助gc
            System.gc();

        }

        public int createIndex(Integer n, int index) {

            if (n == null) {
                return index;
            }

            return n + index;
        }

    }


}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy