一、即然是和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
网友评论