美文网首页码农的世界
Java ScriptEngine 经验分享 - 3.jpyth

Java ScriptEngine 经验分享 - 3.jpyth

作者: 草编椅 | 来源:发表于2019-10-13 12:45 被阅读0次
一、即然是和Java的ScriptEngine搞到一块儿,那当然是要互通的!

互通,就要能把java类型注入到jpython引擎里,或被获取。
目前有两种方式注入

  • 方式1,在脚本里引用(这个网站资料好找)
from java.lang import System
  • 方式2,引擎对象上注入(这个难找点)
//注入实例
_eng.put("__JTEAPI", new __JTEAPI_CLZ());

//注入类
_eng.put("XContext", XContext.class);
_eng.put("ONode", ONode.class);
二、整到一起后,多份python代码,总要互调的

可以设计一个类似node.js的接口require,用于加载外部代码

//设计一个require接口(只讲意图,实现此处不讲)
sb.append("def require(path):\n" +
        "    __JTEAPI.require(path)\n" +
        "    return __global['lib'][path]\n\n");

_eng.eval(sb.toString());
三、或者 我们还要搞下mvc,那来个视图支持

modelAndView在Spring里很经典了,此处做为一个接口,整合视图和模型。通过扩展,可以整合一些主流模板引擎(比如:Freemarker)。

//设计一个modelAndView接口
sb.append("def modelAndView(tml,mod):\n" +
        "    return __JTEAPI.modelAndView(tml,mod)\n\n");

_eng.eval(sb.toString());
四、jpython引擎返回的值是java通用类型

比如我们对它json化,可以用标准的json框架处理
或者使用java类型检测做些处理,比如:

Object tmp = _eng_call.invokeFunction("API_" + name2, ctx);

if (tmp == null) {
    return null;
} else {
    if (outString) {
        if (tmp instanceof Number || tmp instanceof String || tmp instanceof Boolean){
            return tmp.toString();
        }else{
            return NodeUtil.fromObj(tmp).toJson();
        }
    }else{
        return tmp;
    }
}
附:一份完整的适配示例

此示例为嵌入式FaaS引擎 SolonJT 的一个执行器的适配

public class PythonJtExecutor implements IJtExecutor {
    private static final ThData<StringBuilder> _tlBuilder = new ThData(new StringBuilder(1024 * 5));
    private static final String _lock = "";
    private static PythonJtExecutor _g;

    public static PythonJtExecutor singleton() {
        if (_g == null) {
            synchronized (_lock) {
                if (_g == null) {
                    _g = new PythonJtExecutor();
                }
            }
        }

        return _g;
    }


    private final ScriptEngine _eng;
    private final Invocable    _eng_call;
    private final Set<String>  _loaded_names;

    private PythonJtExecutor() {
        _loaded_names = Collections.synchronizedSet(new HashSet<>());

        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        _eng = scriptEngineManager.getEngineByName("python");
        _eng_call = (Invocable) _eng;

        XApp.global().shared().forEach((k, v) -> {
            sharedSet(k, v);
        });

        XApp.global().onSharedAdd((k, v) -> {
            sharedSet(k, v);
        });

        sharedSet("__JTEAPI", new __JTEAPI_CLZ());

        sharedSet("XContext", XContext.class);
        sharedSet("ONode", ONode.class);

        sharedSet("Datetime", Datetime.class);
        sharedSet("Timecount", Timecount.class);
        sharedSet("Timespan", Timespan.class);

        try {
            StringBuilder sb = new StringBuilder();

            sb.append("__global = {'lib':{}}\n\n");

            sb.append("def modelAndView(tml,mod):\n" +
                    "    return __JTEAPI.modelAndView(tml,mod)\n\n");

            sb.append("def require(path):\n" +
                    "    __JTEAPI.require(path)\n" +
                    "    return __global['lib'][path]\n\n");

            _eng.eval(sb.toString());

        } catch (Exception ex) {
            ex.printStackTrace();
        }


    }

    public void sharedSet(String name, Object val) {
        _eng.put(name, val);
    }

    //
    // IJtEngine 接口
    //
    @Override
    public String language() {
        return "python";
    }

    @Override
    public boolean isLoaded(String name2) {
        return _loaded_names.contains(name2);
    }

    @Override
    public boolean preLoad(String name2, AFileModel file) throws Exception {
        if (isLoaded(name2) == false) {
            _loaded_names.add(name2);

            _eng.eval(compilerAsFun(name2, file));
        }

        return true;
    }

    @Override
    public void del(String name) {
        String name2 = name.replace(".", "_").replace("*","_");
        _loaded_names.remove(name2);
        _loaded_names.remove(name2 + "__lib");
    }

    @Override
    public void delAll() {
        _loaded_names.clear();
    }

    @Override
    public Object exec(String name, AFileModel file, XContext ctx, Map<String, Object> model, boolean outString) throws Exception {
        String name2 = name.replace(".", "_").replace("*","_");

        preLoad(name2, file);

        Object tmp = _eng_call.invokeFunction("API_" + name2, ctx);

        if (tmp == null) {
            return null;
        } else {
            if (outString) {
                if (tmp instanceof Number || tmp instanceof String || tmp instanceof Boolean){
                    return tmp.toString();
                }else{
                    return NodeUtil.fromObj(tmp).toJson();
                }
            }else{
                return tmp;
            }
        }
    }


    //////////////////////////////////////////////////////////////////


    /**
     * 编译为函数代码
     */
    public String compilerAsFun(String name, AFileModel file) {
        StringBuilder sb = _tlBuilder.get();
        sb.setLength(0);

        String[] lines = file.content.split("\n");


        if (name.endsWith("__lib")) {
            sb.append("class API_").append(name).append(":\n");

            for (int i = 0, len = lines.length; i < len; i++) {
                sb.append("    ").append(lines[i]).append("\n");
            }
            sb.append("\n\n");

            sb.append("__global['lib']['")
                    .append(file.path)
                    .append("']=")
                    .append("API_")
                    .append(name)
                    .append("()");

        } else {
            sb.append("def API_").append(name).append("(ctx):\n");
            for (int i = 0, len = lines.length; i < len; i++) {
                sb.append("    ").append(lines[i]).append("\n");
            }
        }


        return sb.toString();
    }
}

public class __JTEAPI_CLZ {
    public String require(String path) throws Exception {
        String name = path.replace("/", "__");
        String name2 = name.replace(".", "_") + "__lib";

        AFileModel file = ExecutorFactory.fileGet(path);

        PythonJtExecutor.singleton().preLoad(name2, file);

        return name2;
    }

    public Object modelAndView(String path, Map<String, Object> model) throws Exception {
        String path2 = path;//AFileUtil.path2(path);//不用转为*
        String name = path2.replace("/", "__");

        AFileModel file = ExecutorFactory.fileGet(path2);

        if (file.file_id > 0) {
            return ExecutorFactory.call(name, file, XContext.current(), model, true);
        } else {
            return "";
        }
    }
}

使用效果

lib = require('/ext_exes_python/demo1_clz')

obj = {'a':1,'b':'hello world!','c':ctx.path(),'d':lib.d()}

return obj

相关文章

网友评论

    本文标题:Java ScriptEngine 经验分享 - 3.jpyth

    本文链接:https://www.haomeiwen.com/subject/rebhmctx.html