2021SC@SDUSC
public AbstractFunctionParser(RequestMethod method, String tag, int version, @NotNull JSONObject request) {
setMethod(method == null ? RequestMethod.GET : method);
setTag(tag);
setVersion(version);
setRequest(request);
}
设置标签,设置version,设置请求
public RequestMethod getMethod() {
return method;
}
@Override
public AbstractFunctionParser setMethod(RequestMethod method) {
this.method = method;
return this;
}
@Override
public String getTag() {
return tag;
}
@Override
public AbstractFunctionParser setTag(String tag) {
this.tag = tag;
return this;
}
@Override
public int getVersion() {
return version;
}
@Override
public AbstractFunctionParser setVersion(int version) {
this.version = version;
return this;
}
private String key;
@Override
public String getKey() {
return key;
}
@Override
public AbstractFunctionParser setKey(String key) {
this.key = key;
return this;
}
private String parentPath;
@Override
public String getParentPath() {
return parentPath;
}
@Override
public AbstractFunctionParser setParentPath(String parentPath) {
this.parentPath = parentPath;
return this;
}
private String currentName;
@Override
public String getCurrentName() {
return currentName;
}
@Override
public AbstractFunctionParser setCurrentName(String currentName) {
this.currentName = currentName;
return this;
}
@NotNull
@Override
public JSONObject getRequest() {
return request;
}
@Override
public AbstractFunctionParser setRequest(@NotNull JSONObject request) {
this.request = request;
return this;
}
private JSONObject currentObject;
@NotNull
@Override
public JSONObject getCurrentObject() {
return currentObject;
}
@Override
public AbstractFunctionParser setCurrentObject(@NotNull JSONObject currentObject) {
this.currentObject = currentObject;
return this;
}
以上是设置标签,返回标签,设置对象,返回对象,设置请求,得到请求内容设置名字,得到名字之类的具体函数
@param function 例如get(object,key),参数只允许引用,不能直接传值
@param currentObject 不作为第一个参数,就不能远程调用invoke,避免死循环
@return {@link #invoke(AbstractFunctionParser, String, JSONObject)}
public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject) throws Exception {
FunctionBean fb = parseFunction(function, currentObject, false);
JSONObject row = FUNCTION_MAP.get(fb.getMethod());
if (row == null) {
throw new UnsupportedOperationException("不允许调用远程函数 " + fb.getMethod() + " !");
}
int v = row.getIntValue("version");
if (parser.getVersion() < v) {
throw new UnsupportedOperationException("不允许 version = " + parser.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + v + " !");
}
String t = row.getString("tag");
if (t != null && t.equals(parser.getTag()) == false) {
throw new UnsupportedOperationException("不允许 tag = " + parser.getTag() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 tag = " + t + " !");
}
String[] methods = StringUtil.split(row.getString("methods"));
List<String> ml = methods == null || methods.length <= 0 ? null : Arrays.asList(methods);
if (ml != null && ml.contains(parser.getMethod().toString()) == false) {
throw new UnsupportedOperationException("不允许 method = " + parser.getMethod() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 method 在 " + Arrays.toString(methods) + "内 !");
}
try {
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues());
} catch (Exception e) {
if (e instanceof NoSuchMethodException) {
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 不在后端工程的DemoFunction内!"
+ "\n请检查函数名和参数数量是否与已定义的函数一致!"
+ "\n且必须为 function(key0,key1,...) 这种单函数格式!"
+ "\nfunction必须符合Java函数命名,key是用于在request内取值的键!"
+ "\n调用时不要有空格!");
}
if (e instanceof InvocationTargetException) {
Throwable te = ((InvocationTargetException) e).getTargetException();
if (StringUtil.isEmpty(te.getMessage(), true) == false) { //到处把函数声明throws Exception改成throws Throwable挺麻烦
throw te instanceof Exception ? (Exception) te : new Exception(te.getMessage());
}
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数传参类型错误!"
+ "\n请检查 key:value 中value的类型是否满足已定义的函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 的要求!");
}
throw e;
}
}public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject) throws Exception {
FunctionBean fb = parseFunction(function, currentObject, false);
JSONObject row = FUNCTION_MAP.get(fb.getMethod());
if (row == null) {
throw new UnsupportedOperationException("不允许调用远程函数 " + fb.getMethod() + " !");
}
int v = row.getIntValue("version");
if (parser.getVersion() < v) {
throw new UnsupportedOperationException("不允许 version = " + parser.getVersion() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 version >= " + v + " !");
}
String t = row.getString("tag");
if (t != null && t.equals(parser.getTag()) == false) {
throw new UnsupportedOperationException("不允许 tag = " + parser.getTag() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 tag = " + t + " !");
}
String[] methods = StringUtil.split(row.getString("methods"));
List<String> ml = methods == null || methods.length <= 0 ? null : Arrays.asList(methods);
if (ml != null && ml.contains(parser.getMethod().toString()) == false) {
throw new UnsupportedOperationException("不允许 method = " + parser.getMethod() + " 的请求调用远程函数 " + fb.getMethod() + " ! 必须满足 method 在 " + Arrays.toString(methods) + "内 !");
}
try {
return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues());
} catch (Exception e) {
if (e instanceof NoSuchMethodException) {
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 不在后端工程的DemoFunction内!"
+ "\n请检查函数名和参数数量是否与已定义的函数一致!"
+ "\n且必须为 function(key0,key1,...) 这种单函数格式!"
+ "\nfunction必须符合Java函数命名,key是用于在request内取值的键!"
+ "\n调用时不要有空格!");
}
if (e instanceof InvocationTargetException) {
Throwable te = ((InvocationTargetException) e).getTargetException();
if (StringUtil.isEmpty(te.getMessage(), true) == false) { //到处把函数声明throws Exception改成throws Throwable挺麻烦
throw te instanceof Exception ? (Exception) te : new Exception(te.getMessage());
}
throw new IllegalArgumentException("字符 " + function + " 对应的远程函数传参类型错误!"
+ "\n请检查 key:value 中value的类型是否满足已定义的函数 " + getFunction(fb.getMethod(), fb.getKeys()) + " 的要求!");
}
throw e;
}
}
以上判断是否可以远程调用函数
public static FunctionBean parseFunction(@NotNull String function, @NotNull JSONObject request, boolean isSQLFunction) throws Exception {
int start = function.indexOf("(");
int end = function.lastIndexOf(")");
String method = (start <= 0 || end != function.length() - 1) ? null : function.substring(0, start);
if (StringUtil.isEmpty(method, true)) {
throw new IllegalArgumentException("字符 " + function + " 不合法!函数的名称 function 不能为空,"
+ "且必须为 function(key0,key1,...) 这种单函数格式!"
+ "\nfunction必须符合 " + (isSQLFunction ? "SQL 函数/SQL 存储过程" : "Java 函数") + " 命名,key 是用于在 request 内取值的键!");
}
String[] keys = StringUtil.split(function.substring(start + 1, end));
int length = keys == null ? 0 : keys.length;
Class<?>[] types;
Object[] values;
if (isSQLFunction) {
types = new Class<?>[length];
values = new Object[length];
//碰到null就挂了!!!Number还得各种转换不灵活!不如直接传request和对应的key到函数里,函数内实现时自己 getLongValue,getJSONObject ...
Object v;
for (int i = 0; i < length; i++) {
v = values[i] = request.get(keys[i]);
if (v == null) {
types[i] = Object.class;
values[i] = null;
break;
}
if (v instanceof Boolean) {
types[i] = Boolean.class; //只支持JSON的几种类型
}
else if (v instanceof Number) {
types[i] = Number.class;
}
else if (v instanceof String) {
types[i] = String.class;
}
else if (v instanceof JSONObject) { // Map) {
types[i] = JSONObject.class;
//性能比较差 values[i] = request.getJSONObject(keys[i]);
}
else if (v instanceof JSONArray) { // Collection) {
types[i] = JSONArray.class;
//性能比较差 values[i] = request.getJSONArray(keys[i]);
}
else { //FIXME 碰到null就挂了!!!
throw new UnsupportedDataTypeException(keys[i] + ":value 中value不合法!远程函数 key():" + function + " 中的arg对应的值类型"
+ "只能是 [Boolean, Number, String, JSONObject, JSONArray] 中的一种!");
}
}
}
else {
types = new Class<?>[length + 1];
types[0] = JSONObject.class;
values = new Object[length + 1];
values[0] = request;
for (int i = 0; i < length; i++) {
types[i + 1] = String.class;
values[i + 1] = keys[i];
}
}
FunctionBean fb = new FunctionBean();
fb.setFunction(function);
fb.setMethod(method);
fb.setKeys(keys);
fb.setTypes(types);
fb.setValues(values);
return fb;
}
以上判断函数命名是否正确
判断是否为SQL函数,如果是,又是哪种类型,如果不是,那就是JSONobjec他,给函数的各个基本参数赋值。
public static class FunctionBean {
private String function;
private String method;
private String[] keys;
private Class<?>[] types;
private Object[] values;
public String getFunction() {
return function;
}
public void setFunction(String function) {
this.function = function;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String[] getKeys() {
return keys;
}
public void setKeys(String[] keys) {
this.keys = keys;
}
public Class<?>[] getTypes() {
return types;
}
public void setTypes(Class<?>[] types) {
this.types = types;
}
public Object[] getValues() {
return values;
}
public void setValues(Object[] values) {
this.values = values;
}
设置函数的基本信息