Skip to content

Commit dd37279

Browse files
committed
远程函数:支持 JavaScript 外的更多脚本语言,例如 Python, Ruby, Lua, PHP 等
1 parent f71b084 commit dd37279

1 file changed

Lines changed: 49 additions & 31 deletions

File tree

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

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
package apijson.orm;
77

8-
import java.io.FileReader;
8+
import com.alibaba.fastjson.JSONObject;
9+
import com.alibaba.fastjson.parser.ParserConfig;
10+
import com.alibaba.fastjson.util.TypeUtils;
11+
912
import java.lang.invoke.WrongMethodTypeException;
1013
import java.lang.reflect.InvocationTargetException;
1114
import java.lang.reflect.Method;
@@ -20,12 +23,6 @@
2023
import javax.script.ScriptEngine;
2124
import javax.script.ScriptEngineManager;
2225

23-
import com.alibaba.fastjson.JSON;
24-
import com.alibaba.fastjson.JSONArray;
25-
import com.alibaba.fastjson.JSONObject;
26-
import com.alibaba.fastjson.parser.ParserConfig;
27-
import com.alibaba.fastjson.util.TypeUtils;
28-
2926
import apijson.Log;
3027
import apijson.NotNull;
3128
import apijson.RequestMethod;
@@ -48,10 +45,6 @@ public class AbstractFunctionParser implements FunctionParser {
4845
*/
4946
public static boolean ENABLE_SCRIPT_FUNCTION = true;
5047

51-
public static final int TYPE_REMOTE_FUNCTION = 0;
52-
//public static final int TYPE_SQL_FUNCTION = 1;
53-
public static final int TYPE_SCRIPT_FUNCTION = 1;
54-
5548
// <methodName, JSONObject>
5649
// <isContain, <arguments:"array,key", tag:null, methods:null>>
5750
public static Map<String, JSONObject> FUNCTION_MAP;
@@ -198,15 +191,27 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
198191
throw new UnsupportedOperationException("不允许调用远程函数 " + fb.getMethod() + " !");
199192
}
200193

201-
int type = row.getIntValue("type");
202-
if (type < TYPE_REMOTE_FUNCTION || type > TYPE_SCRIPT_FUNCTION) {
203-
throw new UnsupportedOperationException("type = " + type + " 不合法!必须是 [0, 1] 中的一个 !");
204-
}
205-
if (ENABLE_SCRIPT_FUNCTION == false && type == TYPE_SCRIPT_FUNCTION) {
206-
throw new UnsupportedOperationException("type = " + type + " 不合法!AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION" +
194+
String language = row.getString("language");
195+
String lang = "java".equalsIgnoreCase(language) ? null : language;
196+
197+
if (ENABLE_SCRIPT_FUNCTION == false && lang != null) {
198+
throw new UnsupportedOperationException("language = " + language + " 不合法!AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION" +
207199
" == false 时不支持远程函数中的脚本形式!如需支持则设置 AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION = true !");
208200
}
201+
ScriptEngine engine = lang == null ? null : SCRIPT_ENGINE_MAP.get(lang);
202+
if (lang != null) {
203+
if (engine == null) {
204+
engine = new ScriptEngineManager().getEngineByName(lang);
205+
}
206+
if (engine == null) {
207+
engine = new ScriptEngineManager(null).getEngineByName(lang);
208+
}
209+
if (engine == null) {
210+
throw new ClassNotFoundException("找不到脚本语言 " + language + " 对应的执行引擎!请先依赖相关库并在后端 ScriptEngineManager 中注册!");
211+
}
209212

213+
SCRIPT_ENGINE_MAP.put(lang, engine);
214+
}
210215

211216
int version = row.getIntValue("version");
212217
if (parser.getVersion() < version) {
@@ -223,14 +228,15 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
223228
}
224229

225230
try {
226-
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues(), row.getString("returnType"), currentObject, type);
231+
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues(), row.getString("returnType"), currentObject, engine);
227232
}
228233
catch (Exception e) {
229234
if (e instanceof NoSuchMethodException) {
230-
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 不在后端工程的DemoFunction内!"
235+
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数 " + getFunction(fb.getMethod(), fb.getKeys())
236+
+ " 不在后端 " + parser.getClass().getName() + " 内,也不在父类中!如果需要则先新增对应方法!"
231237
+ "\n请检查函数名和参数数量是否与已定义的函数一致!"
232238
+ "\n且必须为 function(key0,key1,...) 这种单函数格式!"
233-
+ "\nfunction必须符合Java函数命名,key是用于在request内取值的键!"
239+
+ "\nfunction 必须符合 Java 函数命名,key 是用于在 curObj 内取值的键!"
234240
+ "\n调用时不要有空格!" + (Log.DEBUG ? e.getMessage() : ""));
235241
}
236242
if (e instanceof InvocationTargetException) {
@@ -252,12 +258,12 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
252258
* @param methodName
253259
* @param parameterTypes
254260
* @param args
255-
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[], String, JSONObject, int)}
261+
* @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[], String, JSONObject, ScriptEngine)}
256262
* @throws Exception
257263
*/
258264
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
259265
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args) throws Exception {
260-
return invoke(parser, methodName, parameterTypes, args, null, null, TYPE_REMOTE_FUNCTION);
266+
return invoke(parser, methodName, parameterTypes, args, null, null, null);
261267
}
262268
/**反射调用
263269
* @param parser
@@ -266,15 +272,15 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
266272
* @param args
267273
* @param returnType
268274
* @param currentObject
269-
* @param type
275+
* @param engine
270276
* @return
271277
* @throws Exception
272278
*/
273279
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName
274280
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType
275-
, JSONObject currentObject, int type) throws Exception {
276-
if (type == TYPE_SCRIPT_FUNCTION) {
277-
return invokeScript(parser, methodName, parameterTypes, args, returnType, currentObject);
281+
, JSONObject currentObject, ScriptEngine engine) throws Exception {
282+
if (engine != null) {
283+
return invokeScript(parser, methodName, parameterTypes, args, returnType, currentObject, engine);
278284
}
279285

280286
Method m = parser.getClass().getMethod(methodName, parameterTypes); // 不用判空,拿不到就会抛异常
@@ -299,6 +305,7 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
299305

300306
public static Invocable INVOCABLE;
301307
public static ScriptEngine SCRIPT_ENGINE;
308+
public static Map<String, ScriptEngine> SCRIPT_ENGINE_MAP;
302309
static {
303310
try {
304311
System.setProperty("Dnashorn.args", "language=es6");
@@ -308,6 +315,11 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
308315
/*获取执行JavaScript的执行引擎*/
309316
SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("javascript");
310317
INVOCABLE = (Invocable) SCRIPT_ENGINE;
318+
319+
SCRIPT_ENGINE_MAP = new HashMap<>();
320+
SCRIPT_ENGINE_MAP.put("JavaScript", SCRIPT_ENGINE);
321+
SCRIPT_ENGINE_MAP.put("javascript", SCRIPT_ENGINE);
322+
SCRIPT_ENGINE_MAP.put("js", SCRIPT_ENGINE);
311323
}
312324
catch (Exception e) {
313325
e.printStackTrace();
@@ -325,14 +337,18 @@ public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull Str
325337
* @throws Exception
326338
*/
327339
public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName
328-
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject) throws Exception {
340+
, @NotNull Class<?>[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject, ScriptEngine engine) throws Exception {
329341
JSONObject row = SCRIPT_MAP.get(methodName);
330342
if (row == null) {
331-
throw new UnsupportedOperationException("调用远程函数脚本 " + methodName + " 不存在!");
343+
throw new UnsupportedOperationException("调用的远程函数脚本 " + methodName + " 不存在!");
332344
}
333345

334346
String script = row.getString("script");
335-
SCRIPT_ENGINE.eval(script); // 必要,未执行导致下方 INVOCABLE.invokeFunction 报错 NoSuchMethod
347+
348+
if (engine == null) {
349+
engine = SCRIPT_ENGINE;
350+
}
351+
engine.eval(script); // 必要,未执行导致下方 INVOCABLE.invokeFunction 报错 NoSuchMethod
336352

337353
//Object[] newArgs = args == null || args.length <= 0 ? null : new Object[args.length];
338354

@@ -341,9 +357,11 @@ public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNu
341357
// return SCRIPT_ENGINE.eval(script);
342358
//}
343359

360+
Invocable invocable = engine instanceof Invocable ? (Invocable) engine : null;
361+
344362
Object result;
345363
if (args == null || args.length <= 0) {
346-
result = INVOCABLE.invokeFunction(methodName);
364+
result = invocable.invokeFunction(methodName);
347365
}
348366
else {
349367
//args[0] = JSON.toJSONString(args[0]); // Java 调 js 函数只支持传基本类型,改用 invokeMethod ?
@@ -354,7 +372,7 @@ public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNu
354372
//}
355373

356374
// 支持 JSONObject
357-
result = INVOCABLE.invokeFunction(methodName, args);
375+
result = invocable.invokeFunction(methodName, args);
358376
//result = INVOCABLE.invokeMethod(args[0], methodName, args);
359377

360378
//switch (newArgs.length) {

0 commit comments

Comments
 (0)