Skip to content

Commit 21df376

Browse files
committed
远程函数:新增支持 JavaScript 脚本,方便动态配置业务逻辑以及作为 Serveless 服务
1 parent 64274fd commit 21df376

File tree

4 files changed

+148
-17
lines changed

4 files changed

+148
-17
lines changed

APIJSONORM/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>com.github.Tencent</groupId>
77
<artifactId>APIJSON</artifactId>
8-
<version>5.4.0</version>
8+
<version>5.5.0</version>
99
<packaging>jar</packaging>
1010

1111
<name>APIJSONORM</name>

APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java

Lines changed: 130 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@
55

66
package apijson.orm;
77

8+
import java.io.FileReader;
89
import java.lang.reflect.InvocationTargetException;
910
import java.util.Arrays;
1011
import java.util.HashMap;
1112
import java.util.List;
1213
import java.util.Map;
1314

1415
import javax.activation.UnsupportedDataTypeException;
16+
import javax.script.Invocable;
17+
import javax.script.ScriptEngine;
18+
import javax.script.ScriptEngineManager;
1519

20+
import com.alibaba.fastjson.JSON;
1621
import com.alibaba.fastjson.JSONArray;
1722
import com.alibaba.fastjson.JSONObject;
1823

@@ -27,11 +32,17 @@
2732
public class AbstractFunctionParser implements FunctionParser {
2833
// private static final String TAG = "AbstractFunctionParser";
2934

35+
public static final int TYPE_REMOTE_FUNCTION = 0;
36+
//public static final int TYPE_SQL_FUNCTION = 1;
37+
public static final int TYPE_SCRIPT_FUNCTION = 1;
38+
3039
// <methodName, JSONObject>
3140
// <isContain, <arguments:"array,key", tag:null, methods:null>>
3241
public static Map<String, JSONObject> FUNCTION_MAP;
42+
public static Map<String, JSONObject> SCRIPT_MAP;
3343
static {
3444
FUNCTION_MAP = new HashMap<>();
45+
SCRIPT_MAP = new HashMap<>();
3546
}
3647

3748
private RequestMethod method;
@@ -157,13 +168,19 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
157168
throw new UnsupportedOperationException("不允许调用远程函数 " + fb.getMethod() + " !");
158169
}
159170

160-
int v = row.getIntValue("version");
161-
if (parser.getVersion() < v) {
162-
throw new UnsupportedOperationException("不允许 version = " + parser.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + v + " !");
171+
int type = row.getIntValue("type");
172+
if (type < TYPE_REMOTE_FUNCTION || type > TYPE_SCRIPT_FUNCTION) {
173+
throw new UnsupportedOperationException("type = " + type + " 不合法!必须是 [0, 1, 2] 中的一个 !");
174+
}
175+
176+
177+
int version = row.getIntValue("version");
178+
if (parser.getVersion() < version) {
179+
throw new UnsupportedOperationException("不允许 version = " + parser.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + version + " !");
163180
}
164-
String t = row.getString("tag");
165-
if (t != null && t.equals(parser.getTag()) == false) {
166-
throw new UnsupportedOperationException("不允许 tag = " + parser.getTag() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 tag = " + t + " !");
181+
String tag = row.getString("tag");
182+
if (tag != null && tag.equals(parser.getTag()) == false) {
183+
throw new UnsupportedOperationException("不允许 tag = " + parser.getTag() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 tag = " + tag + " !");
167184
}
168185
String[] methods = StringUtil.split(row.getString("methods"));
169186
List<String> ml = methods == null || methods.length <= 0 ? null : Arrays.asList(methods);
@@ -172,7 +189,7 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
172189
}
173190

174191
try {
175-
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues());
192+
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues(), currentObject, type);
176193
} catch (Exception e) {
177194
if (e instanceof NoSuchMethodException) {
178195
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 不在后端工程的DemoFunction内!"
@@ -201,17 +218,114 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
201218
* @param args
202219
* @return
203220
*/
204-
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
205-
return parser.getClass().getMethod(methodName, parameterTypes).invoke(parser, args);
221+
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
222+
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
223+
return invoke(parser, methodName, parameterTypes, args, null, TYPE_REMOTE_FUNCTION);
224+
}
225+
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
226+
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, JSONObject currentObject, int type) throws Exception {
227+
if (type == TYPE_SCRIPT_FUNCTION) {
228+
return invokeScript(parser, methodName, parameterTypes, args, currentObject);
229+
}
230+
return parser.getClass().getMethod(methodName, parameterTypes).invoke(parser, args);
206231
}
207232

208-
/**解析函数
209-
* @param function
210-
* @param request
211-
* @param isSQLFunction
212-
* @return
213-
* @throws Exception
214-
*/
233+
public static Invocable INVOCABLE;
234+
public static ScriptEngine SCRIPT_ENGINE;
235+
static {
236+
try {
237+
System.setProperty("Dnashorn.args", "language=es6");
238+
System.setProperty("Dnashorn.args", "--language=es6");
239+
System.setProperty("-Dnashorn.args", "--language=es6");
240+
241+
/*获取执行JavaScript的执行引擎*/
242+
SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("javascript");
243+
INVOCABLE = (Invocable) SCRIPT_ENGINE;
244+
} catch (Exception e) {
245+
e.printStackTrace();
246+
}
247+
}
248+
249+
public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName
250+
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, JSONObject currentObject) throws Exception {
251+
JSONObject row = SCRIPT_MAP.get(methodName);
252+
if (row == null) {
253+
throw new UnsupportedOperationException("调用远程函数脚本 " + methodName + " 不存在!");
254+
}
255+
256+
String script = row.getString("script");
257+
//SCRIPT_ENGINE.eval(script);
258+
//Object[] newArgs = args == null || args.length <= 0 ? null : new Object[args.length];
259+
260+
SCRIPT_ENGINE.eval(script);
261+
262+
// APIJSON 远程函数不应该支持
263+
//if (row.getBooleanValue("simple")) {
264+
// return SCRIPT_ENGINE.eval(script);
265+
//}
266+
267+
Object result;
268+
if (args == null || args.length <= 0) {
269+
result = INVOCABLE.invokeFunction(methodName);
270+
}
271+
else {
272+
//args[0] = JSON.toJSONString(args[0]); // Java 调 js 函数只支持传基本类型,改用 invokeMethod ?
273+
274+
//for (int i = 0; i < args.length; i++) {
275+
// Object a = currentObject == null ? null : currentObject.get(args[i]);
276+
// newArgs[i] = a == null || apijson.JSON.isBooleanOrNumberOrString(a) ? a : JSON.toJSONString(a);
277+
//}
278+
279+
// TODO 先试试这个
280+
result = INVOCABLE.invokeFunction(methodName, args);
281+
//result = INVOCABLE.invokeMethod(args[0], methodName, args);
282+
283+
//switch (newArgs.length) {
284+
// case 1:
285+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0]);
286+
// break;
287+
// case 2:
288+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1]);
289+
// break;
290+
// case 3:
291+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2]);
292+
// break;
293+
// case 4:
294+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3]);
295+
// break;
296+
// case 5:
297+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4]);
298+
// break;
299+
// case 6:
300+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5]);
301+
// break;
302+
// case 7:
303+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6]);
304+
// break;
305+
// case 8:
306+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6], newArgs[7]);
307+
// break;
308+
// case 9:
309+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6], newArgs[7], newArgs[8]);
310+
// break;
311+
// case 10:
312+
// result = INVOCABLE.invokeFunction(methodName, newArgs[0], newArgs[1], newArgs[2], newArgs[3], newArgs[4], newArgs[5], newArgs[6], newArgs[7], newArgs[8], newArgs[9]);
313+
// break;
314+
//}
315+
}
316+
317+
System.out.println("invokeScript " + methodName + "(..) >> result = " + result);
318+
return result;
319+
}
320+
321+
322+
/**解析函数
323+
* @param function
324+
* @param request
325+
* @param isSQLFunction
326+
* @return
327+
* @throws Exception
328+
*/
215329
@NotNull
216330
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction) throws Exception {
217331

APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import apijson.orm.model.Document;
6161
import apijson.orm.model.ExtendedProperty;
6262
import apijson.orm.model.Function;
63+
import apijson.orm.model.Script;
6364
import apijson.orm.model.PgAttribute;
6465
import apijson.orm.model.PgClass;
6566
import apijson.orm.model.Request;
@@ -151,6 +152,7 @@ public abstract class AbstractVerifier<T extends Object> implements Verifier<T>,
151152

152153
SYSTEM_ACCESS_MAP.put(Access.class.getSimpleName(), getAccessMap(Access.class.getAnnotation(MethodAccess.class)));
153154
SYSTEM_ACCESS_MAP.put(Function.class.getSimpleName(), getAccessMap(Function.class.getAnnotation(MethodAccess.class)));
155+
SYSTEM_ACCESS_MAP.put(Script.class.getSimpleName(), getAccessMap(Script.class.getAnnotation(MethodAccess.class)));
154156
SYSTEM_ACCESS_MAP.put(Request.class.getSimpleName(), getAccessMap(Request.class.getAnnotation(MethodAccess.class)));
155157

156158
if (Log.DEBUG) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
2+
3+
This source code is licensed under the Apache License Version 2.0.*/
4+
5+
6+
package apijson.orm.model;
7+
8+
import apijson.MethodAccess;
9+
10+
/**代码脚本
11+
* @author Lemon
12+
*/
13+
@MethodAccess(POST = {}, PUT = {}, DELETE = {})
14+
public class Script {
15+
}

0 commit comments

Comments
 (0)