远程函数:新增支持 JavaScript 脚本,方便动态配置业务逻辑以及作为 Serveless 服务
This commit is contained in:
parent
64274fd3b5
commit
21df376a60
@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.github.Tencent</groupId>
|
||||
<artifactId>APIJSON</artifactId>
|
||||
<version>5.4.0</version>
|
||||
<version>5.5.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>APIJSONORM</name>
|
||||
|
@ -5,6 +5,7 @@ This source code is licensed under the Apache License Version 2.0.*/
|
||||
|
||||
package apijson.orm;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -12,7 +13,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.activation.UnsupportedDataTypeException;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
@ -27,11 +32,17 @@ import apijson.StringUtil;
|
||||
public class AbstractFunctionParser implements FunctionParser {
|
||||
// private static final String TAG = "AbstractFunctionParser";
|
||||
|
||||
public static final int TYPE_REMOTE_FUNCTION = 0;
|
||||
//public static final int TYPE_SQL_FUNCTION = 1;
|
||||
public static final int TYPE_SCRIPT_FUNCTION = 1;
|
||||
|
||||
// <methodName, JSONObject>
|
||||
// <isContain, <arguments:"array,key", tag:null, methods:null>>
|
||||
public static Map<String, JSONObject> FUNCTION_MAP;
|
||||
public static Map<String, JSONObject> SCRIPT_MAP;
|
||||
static {
|
||||
FUNCTION_MAP = new HashMap<>();
|
||||
SCRIPT_MAP = new HashMap<>();
|
||||
}
|
||||
|
||||
private RequestMethod method;
|
||||
@ -157,13 +168,19 @@ public class AbstractFunctionParser implements FunctionParser {
|
||||
throw new UnsupportedOperationException("不允许调用远程函数 " + fb.getMethod() + " !");
|
||||
}
|
||||
|
||||
int v = row.getIntValue("version");
|
||||
if (parser.getVersion() < v) {
|
||||
throw new UnsupportedOperationException("不允许 version = " + parser.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + v + " !");
|
||||
int type = row.getIntValue("type");
|
||||
if (type < TYPE_REMOTE_FUNCTION || type > TYPE_SCRIPT_FUNCTION) {
|
||||
throw new UnsupportedOperationException("type = " + type + " 不合法!必须是 [0, 1, 2] 中的一个 !");
|
||||
}
|
||||
String t = row.getString("tag");
|
||||
if (t != null && t.equals(parser.getTag()) == false) {
|
||||
throw new UnsupportedOperationException("不允许 tag = " + parser.getTag() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 tag = " + t + " !");
|
||||
|
||||
|
||||
int version = row.getIntValue("version");
|
||||
if (parser.getVersion() < version) {
|
||||
throw new UnsupportedOperationException("不允许 version = " + parser.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + version + " !");
|
||||
}
|
||||
String tag = row.getString("tag");
|
||||
if (tag != null && tag.equals(parser.getTag()) == false) {
|
||||
throw new UnsupportedOperationException("不允许 tag = " + parser.getTag() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 tag = " + tag + " !");
|
||||
}
|
||||
String[] methods = StringUtil.split(row.getString("methods"));
|
||||
List<String> ml = methods == null || methods.length <= 0 ? null : Arrays.asList(methods);
|
||||
@ -172,7 +189,7 @@ public class AbstractFunctionParser implements FunctionParser {
|
||||
}
|
||||
|
||||
try {
|
||||
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues());
|
||||
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues(), currentObject, type);
|
||||
} catch (Exception e) {
|
||||
if (e instanceof NoSuchMethodException) {
|
||||
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 不在后端工程的DemoFunction内!"
|
||||
@ -201,10 +218,107 @@ public class AbstractFunctionParser implements FunctionParser {
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
|
||||
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
||||
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
|
||||
return invoke(parser, methodName, parameterTypes, args, null, TYPE_REMOTE_FUNCTION);
|
||||
}
|
||||
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
||||
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, JSONObject currentObject, int type) throws Exception {
|
||||
if (type == TYPE_SCRIPT_FUNCTION) {
|
||||
return invokeScript(parser, methodName, parameterTypes, args, currentObject);
|
||||
}
|
||||
return parser.getClass().getMethod(methodName, parameterTypes).invoke(parser, args);
|
||||
}
|
||||
|
||||
public static Invocable INVOCABLE;
|
||||
public static ScriptEngine SCRIPT_ENGINE;
|
||||
static {
|
||||
try {
|
||||
System.setProperty("Dnashorn.args", "language=es6");
|
||||
System.setProperty("Dnashorn.args", "--language=es6");
|
||||
System.setProperty("-Dnashorn.args", "--language=es6");
|
||||
|
||||
/*获取执行JavaScript的执行引擎*/
|
||||
SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("javascript");
|
||||
INVOCABLE = (Invocable) SCRIPT_ENGINE;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName
|
||||
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, JSONObject currentObject) throws Exception {
|
||||
JSONObject row = SCRIPT_MAP.get(methodName);
|
||||
if (row == null) {
|
||||
throw new UnsupportedOperationException("调用远程函数脚本 " + methodName + " 不存在!");
|
||||
}
|
||||
|
||||
String script = row.getString("script");
|
||||
//SCRIPT_ENGINE.eval(script);
|
||||
//Object[] newArgs = args == null || args.length <= 0 ? null : new Object[args.length];
|
||||
|
||||
SCRIPT_ENGINE.eval(script);
|
||||
|
||||
// APIJSON 远程函数不应该支持
|
||||
//if (row.getBooleanValue("simple")) {
|
||||
// return SCRIPT_ENGINE.eval(script);
|
||||
//}
|
||||
|
||||
Object result;
|
||||
if (args == null || args.length <= 0) {
|
||||
result = INVOCABLE.invokeFunction(methodName);
|
||||
}
|
||||
else {
|
||||
//args[0] = JSON.toJSONString(args[0]); // Java 调 js 函数只支持传基本类型,改用 invokeMethod ?
|
||||
|
||||
//for (int i = 0; i < args.length; i++) {
|
||||
// Object a = currentObject == null ? null : currentObject.get(args[i]);
|
||||
// newArgs[i] = a == null || apijson.JSON.isBooleanOrNumberOrString(a) ? a : JSON.toJSONString(a);
|
||||
//}
|
||||
|
||||
// TODO 先试试这个
|
||||
result = INVOCABLE.invokeFunction(methodName, args);
|
||||
//result = INVOCABLE.invokeMethod(args[0], methodName, args);
|
||||
|
||||
//switch (newArgs.length) {
|
||||
// case 1:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0]);
|
||||
// break;
|
||||
// case 2:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1]);
|
||||
// break;
|
||||
// case 3:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2]);
|
||||
// break;
|
||||
// case 4:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3]);
|
||||
// break;
|
||||
// case 5:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4]);
|
||||
// break;
|
||||
// case 6:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5]);
|
||||
// break;
|
||||
// case 7:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6]);
|
||||
// break;
|
||||
// case 8:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6], newArgs[7]);
|
||||
// break;
|
||||
// case 9:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6], newArgs[7], newArgs[8]);
|
||||
// break;
|
||||
// case 10:
|
||||
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6], newArgs[7], newArgs[8], newArgs[9]);
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
System.out.println("invokeScript " + methodName + "(..) >> result = " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**解析函数
|
||||
* @param function
|
||||
* @param request
|
||||
|
@ -60,6 +60,7 @@ import apijson.orm.model.Column;
|
||||
import apijson.orm.model.Document;
|
||||
import apijson.orm.model.ExtendedProperty;
|
||||
import apijson.orm.model.Function;
|
||||
import apijson.orm.model.Script;
|
||||
import apijson.orm.model.PgAttribute;
|
||||
import apijson.orm.model.PgClass;
|
||||
import apijson.orm.model.Request;
|
||||
@ -151,6 +152,7 @@ public abstract class AbstractVerifier<T extends Object> implements Verifier<T>,
|
||||
|
||||
SYSTEM_ACCESS_MAP.put(Access.class.getSimpleName(), getAccessMap(Access.class.getAnnotation(MethodAccess.class)));
|
||||
SYSTEM_ACCESS_MAP.put(Function.class.getSimpleName(), getAccessMap(Function.class.getAnnotation(MethodAccess.class)));
|
||||
SYSTEM_ACCESS_MAP.put(Script.class.getSimpleName(), getAccessMap(Script.class.getAnnotation(MethodAccess.class)));
|
||||
SYSTEM_ACCESS_MAP.put(Request.class.getSimpleName(), getAccessMap(Request.class.getAnnotation(MethodAccess.class)));
|
||||
|
||||
if (Log.DEBUG) {
|
||||
|
15
APIJSONORM/src/main/java/apijson/orm/model/Script.java
Normal file
15
APIJSONORM/src/main/java/apijson/orm/model/Script.java
Normal file
@ -0,0 +1,15 @@
|
||||
/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
This source code is licensed under the Apache License Version 2.0.*/
|
||||
|
||||
|
||||
package apijson.orm.model;
|
||||
|
||||
import apijson.MethodAccess;
|
||||
|
||||
/**代码脚本
|
||||
* @author Lemon
|
||||
*/
|
||||
@MethodAccess(POST = {}, PUT = {}, DELETE = {})
|
||||
public class Script {
|
||||
}
|
Loading…
Reference in New Issue
Block a user