diff --git a/README.md b/README.md index f01edbfb3..6bcbed02d 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,18 @@ -# QLExpress基本语法 +# QLExpress basic syntax -[![Join the chat at https://gitter.im/QLExpress/Lobby](https://badges.gitter.im/QLExpress/Lobby.svg)](https://gitter.im/QLExpress/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +# I, Background introduction -# 一、背景介绍 +A dynamic script engine parsing tool designed by Ali's strong requirements for e-commerce business rules, expressions (Boolean combinations), special mathematical formula calculations (high precision), syntax analysis, and secondary script customization. +It has a strong influence in Alibaba Group. At the same time, in order to continuously optimize and carry forward the spirit of open source contribution, it was open sourced in 2012. -由阿里的电商业务规则、表达式(布尔组合)、特殊数学公式计算(高精度)、语法分析、脚本二次定制等强需求而设计的一门动态脚本引擎解析工具。 -在阿里集团有很强的影响力,同时为了自身不断优化、发扬开源贡献精神,于2012年开源。 +The QLExpress script engine is widely used in Ali's e-commerce business scenarios and has the following characteristics: +1. Thread safety. Temporary variables generated during engine operation are all threadlocal. +2. Efficient execution. The time-consuming script compilation process can be cached on the local machine. The temporary variable creation at runtime uses the technology of buffer pool, which is equivalent to groovy performance. +3. Weakly typed scripting language, similar to groovy and javascript, although it is slower than strong typed scripting language, it greatly enhances business flexibility. +4. Safety control, you can prevent dead loops and high-risk system api calls by setting relevant operating parameters. +5. The code is streamlined and the dependency is minimal. The 250k jar package is suitable for all java operating environments, and it is also widely used in the low-end pos machines of the android system. -QLExpress脚本引擎被广泛应用在阿里的电商业务场景,具有以下的一些特性: -- 1、线程安全,引擎运算过程中的产生的临时变量都是threadlocal类型。 -- 2、高效执行,比较耗时的脚本编译过程可以缓存在本地机器,运行时的临时变量创建采用了缓冲池的技术,和groovy性能相当。 -- 3、弱类型脚本语言,和groovy,javascript语法类似,虽然比强类型脚本语言要慢一些,但是使业务的灵活度大大增强。 -- 4、安全控制,可以通过设置相关运行参数,预防死循环、高危系统api调用等情况。 -- 5、代码精简,依赖最小,250k的jar包适合所有java的运行环境,在android系统的低端pos机也得到广泛运用。 - -# 二、依赖和调用说明 +# II, Dependency and call instructions ```xml @@ -34,13 +32,13 @@ String express = "a+b*c"; Object r = runner.execute(express, context, null, true, false); System.out.println(r); ``` -# 三、语法介绍 -## 1、操作符和java对象操作 -### 普通java语法 +# III, Grammar introduction +## 1. Operators and java object operations +### Ordinary java syntax ``` -//支持 +,-,*,/,<,>,<=,>=,==,!=,<>【等同于!=】,%,mod【取模等同于%】,++,--, -//in【类似sql】,like【sql语法】,&&,||,!,等操作符 -//支持for,break、continue、if then else 等标准的程序控制逻辑 +//Support +,-,*,/,<,>,<=,>=,==,!=,<>[Equivalent to !=],%,mod[Modulo equal to%],++, --, +//in [similar to sql], like [sql syntax], &&,||,!, and other operators +//Support standard program control logic such as for, break, continue, if then else n=10; for(sum=0,i=0;ib?a:b; -``` +``` -### 和java语法相比,要避免的一些ql写法错误 -- 不支持try{}catch{} -- 注释目前只支持 /** **/,不支持单行注释 // -- 不支持java8的lambda表达式 -- 不支持for循环集合操作for (GRCRouteLineResultDTO item : list) -- 弱类型语言,请不要定义类型声明,更不要用Templete(Map之类的) -- array的声明不一样 -- min,max,round,print,println,like,in 都是系统默认函数的关键字,请不要作为变量名 +### Compared with java syntax, some ql writing errors to avoid +- Does not support try{}catch{} +- Comments currently only support /** **/, single-line comments are not supported // +- Java8 lambda expressions are not supported +- Does not support for loop collection operation for (GRCRouteLineResultDTO item: list) +- Weakly typed languages, please do not define type declarations, let alone use Templete (Map and the like) +- The declaration of array is different +- min, max, round, print, println, like, in are all keywords of the system default functions, please do not use them as variable names ``` -//java语法:使用泛型来提醒开发者检查类型 +//java syntax: use generics to remind developers to check the type keys = new ArrayList(); deviceName2Value = new HashMap(7); String[] deviceNames = {"ng","si","umid","ut","mac","imsi","imei"}; int[] mins = {5,30}; -//ql写法: +//ql writing: keys = new ArrayList(); deviceName2Value = new HashMap(); deviceNames = ["ng","si","umid","ut","mac","imsi","imei"]; mins = [5,30]; -//java语法:对象类型声明 +//java syntax: object type declaration FocFulfillDecisionReqDTO reqDTO = param.getReqDTO(); -//ql写法: +//ql writing: reqDTO = param.getReqDTO(); -//java语法:数组遍历 -for(GRCRouteLineResultDTO item : list) { +//java syntax: array traversal +for(GRCRouteLineResultDTO item: list) { } -//ql写法: +//ql writing: for(i=0;i context = new DefaultContext(); runner.execute(exp,context,null,false,false,null); ``` -### 如何自定义Operator +### How to customize Operator ```java -//定义一个继承自com.ql.util.express.Operator的操作符 +//Define an operator inherited from com.ql.util.express.Operator public class JoinOperator extends Operator{ - public Object executeInner(Object[] list) throws Exception { - Object opdata1 = list[0]; - Object opdata2 = list[1]; - if(opdata1 instanceof java.util.List){ - ((java.util.List)opdata1).add(opdata2); - return opdata1; - }else{ - java.util.List result = new java.util.ArrayList(); - result.add(opdata1); - result.add(opdata2); - return result; - } - } +public Object executeInner(Object[] list) throws Exception { +Object opdata1 = list[0]; +Object opdata2 = list[1]; +if(opdata1 instanceof java.util.List){ +((java.util.List)opdata1).add(opdata2); +return opdata1; +}else{ +java.util.List result = new java.util.ArrayList(); +result.add(opdata1); +result.add(opdata2); +return result; +} +} } ``` -### 如何使用Operator +### How to use Operator ``` //(1)addOperator @@ -178,7 +176,7 @@ DefaultContext context = new DefaultContext(); runner.addOperator("join",new JoinOperator()); Object r = runner.execute("1 join 2 join 3", context, null, false, false); System.out.println(r); -//返回结果 [1, 2, 3] +//Return result [1, 2, 3] //(2)replaceOperator ExpressRunner runner = new ExpressRunner(); @@ -186,7 +184,7 @@ DefaultContext context = new DefaultContext(); runner.replaceOperator("+",new JoinOperator()); Object r = runner.execute("1 + 2 + 3", context, null, false, false); System.out.println(r); -//返回结果 [1, 2, 3] +//Return result [1, 2, 3] //(3)addFunction ExpressRunner runner = new ExpressRunner(); @@ -194,23 +192,23 @@ DefaultContext context = new DefaultContext(); runner.addFunction("join",new JoinOperator()); Object r = runner.execute("join(1,2,3)", context, null, false, false); System.out.println(r); -//返回结果 [1, 2, 3] +//Return result [1, 2, 3] ``` -## 4、绑定java类或者对象的method +## 4. Binding method of java class or object addFunctionOfClassMethod+addFunctionOfServiceMethod ``` public class BeanExample { - public static String upper(String abc) { - return abc.toUpperCase(); - } - public boolean anyContains(String str, String searchStr) { +public static String upper(String abc) { +return abc.toUpperCase(); +} +public boolean anyContains(String str, String searchStr) { char[] s = str.toCharArray(); - for (char c : s) { + for (char c: s) { if (searchStr.contains(c+"")) { return true; } @@ -219,56 +217,56 @@ public class BeanExample { } } -runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs", - new String[] { "double" }, null); -runner.addFunctionOfClassMethod("转换为大写", BeanExample.class.getName(), - "upper", new String[] { "String" }, null); +runner.addFunctionOfClassMethod("Take the absolute value", Math.class.getName(), "abs", +new String[] {"double" }, null); +runner.addFunctionOfClassMethod("Convert to uppercase", BeanExample.class.getName(), +"upper", new String[] {"String" }, null); -runner.addFunctionOfServiceMethod("打印", System.out, "println",new String[] { "String" }, null); +runner.addFunctionOfServiceMethod("Print", System.out, "println",new String[] {"String" }, null); runner.addFunctionOfServiceMethod("contains", new BeanExample(), "anyContains", - new Class[] { String.class, String.class }, null); + new Class[] {String.class, String.class }, null); -String exp = “取绝对值(-100);转换为大写(\"hello world\");打印(\"你好吗?\");contains("helloworld",\"aeiou\")”; +String exp = "Take the absolute value (-100); convert to uppercase (\"hello world\"); print (\"How are you?\"); contains("helloworld",\"aeiou\")"; runner.execute(exp, context, null, false, false); ``` - ## 5、macro 宏定义 + ## 5, macro macro definition ``` -runner.addMacro("计算平均成绩", "(语文+数学+英语)/3.0"); -runner.addMacro("是否优秀", "计算平均成绩>90"); +runner.addMacro("Calculate average score", "(Chinese+Math+English)/3.0"); +runner.addMacro("Is it excellent", "Calculate the average score>90"); IExpressContext context =new DefaultContext(); context.put("语文", 88); -context.put("数学", 99); -context.put("英语", 95); -Object result = runner.execute("是否优秀", context, null, false, false); +context.put("Mathematics", 99); +context.put("English", 95); +Object result = runner.execute("Is it excellent", context, null, false, false); System.out.println(r); -//返回结果true +//Return the result true ``` - ## 6、编译脚本,查询外部需要定义的变量和函数。 - **注意以下脚本int和没有int的区别** + ## 6. Compile the script and query external variables and functions that need to be defined. + **Note the difference between the following script int and no int** ``` -String express = "int 平均分 = (语文+数学+英语+综合考试.科目2)/4.0;return 平均分"; +String express = "int average score = (language + mathematics + English + comprehensive examination. Subject 2)/4.0; return average score"; ExpressRunner runner = new ExpressRunner(true,true); String[] names = runner.getOutVarNames(express); for(String s:names){ - System.out.println("var : " + s); + System.out.println("var: "+ s); } -//输出结果: +//Output result: -var : 数学 -var : 综合考试 -var : 英语 -var : 语文 -``` +var: mathematics +var: Comprehensive examination +var: English +var: language +``` -## 7、关于不定参数的使用 +## 7. About the use of indefinite parameters ``` @Test @@ -277,15 +275,15 @@ var : 语文 IExpressContext expressContext = new DefaultContext(); runner.addFunctionOfServiceMethod("getTemplate", this, "getTemplate", new Class[]{Object[].class}, null); - //(1)默认的不定参数可以使用数组来代替 + //(1) The default indefinite parameters can be replaced by arrays Object r = runner.execute("getTemplate([11,'22',33L,true])", expressContext, null,false, false); System.out.println(r); - //(2)像java一样,支持函数动态参数调用,需要打开以下全局开关,否则以下调用会失败 + //(2) Like java, support function dynamic parameter call, you need to turn on the following global switches, otherwise the following calls will fail DynamicParamsUtil.supportDynamicParams = true; r = runner.execute("getTemplate(11,'22',33L,true)", expressContext, null,false, false); System.out.println(r); } - //等价于getTemplate(Object[] params) + //Equivalent to getTemplate(Object[] params) public Object getTemplate(Object... params) throws Exception{ String result = ""; for(Object obj:params){ @@ -295,7 +293,7 @@ var : 语文 } ``` -## 8、关于集合的快捷写法 +## 8. Shortcuts on the collection ``` @Test @@ -313,12 +311,12 @@ var : 语文 System.out.println(r); } -``` +``` -## 9、集合的遍历 -其实类似java的语法,只是ql不支持for(obj:list){}的语法,只能通过下标访问。 +## 9, the traversal of the collection +In fact, the syntax is similar to java, but ql does not support the syntax of for(obj:list){} and can only be accessed through subscripts. ```java - //遍历map + //Traverse the map map = new HashMap(); map.put("a", "a_value"); map.put("b", "b_value"); @@ -332,82 +330,82 @@ var : 语文 ``` -# 四、运行参数和API列表介绍 +# IV, the operating parameters and API list introduction -QLExpressRunner如下图所示,从语法树分析、上下文、执行过程三个方面提供二次定制的功能扩展。 +As shown in the figure below, QLExpressRunner provides secondary customized function extensions from three aspects: syntax tree analysis, context, and execution process. ![QlExpress-detail.jpg](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/dec904b003aba15cbf1af2726914ddee.jpg) -## 1、属性开关 +## 1. Attribute switch ### isPrecise -```java - /** - * 是否需要高精度计算 - */ - private boolean isPrecise = false; +```java +/** +* Whether high precision calculation is required +*/ +private boolean isPrecise = false; ``` -> 高精度计算在会计财务中非常重要,java的float、double、int、long存在很多隐式转换,做四则运算和比较的时候其实存在非常多的安全隐患。 -> 所以类似汇金的系统中,会有很多BigDecimal转换代码。而使用QLExpress,你只要关注数学公式本身 _订单总价 = 单价 * 数量 + 首重价格 + ( 总重量 - 首重) * 续重单价_ ,然后设置这个属性即可,所有的中间运算过程都会保证不丢失精度。 +> High-precision calculations are very important in accounting and finance. There are many implicit conversions of float, double, int, and long in java. There are actually a lot of security risks when doing four arithmetic operations and comparisons. +> So in a system like Huijin, there will be many BigDecimal conversion codes. With QLExpress, you only need to pay attention to the mathematical formula itself _ order total price = unit price * quantity + first weight price + (total weight-first weight) * continued weight unit price_, and then set this attribute, all intermediate calculations will be guaranteed No loss of accuracy. ### isShortCircuit ```java - /** - * 是否使用逻辑短路特性 - */ - private boolean isShortCircuit = true; +/** +* Whether to use logic short circuit feature +*/ +private boolean isShortCircuit = true; ``` -在很多业务决策系统中,往往需要对布尔条件表达式进行分析输出,普通的java运算一般会通过逻辑短路来减少性能的消耗。例如规则公式: +In many business decision-making systems, it is often necessary to analyze and output Boolean conditional expressions. Ordinary Java operations generally reduce performance consumption through logic short-circuits. For example, the rule formula: _star>10000 and shoptype in('tmall','juhuasuan') and price between (100,900)_ -假设第一个条件 _star>10000_ 不满足就停止运算。但业务系统却还是希望把后面的逻辑都能够运算一遍,并且输出中间过程,保证更快更好的做出决策。 +Assuming that the first condition _star>10000_ is not met, stop the operation. However, the business system still hopes to calculate the following logic and output the intermediate process to ensure faster and better decisions. -参照单元测试:[ShortCircuitLogicTest.java](https://github.com/alibaba/QLExpress/blob/master/src/test/java/com/ql/util/express/test/logic/ShortCircuitLogicTest.java) +Refer to unit test: [ShortCircuitLogicTest.java](https://github.com/alibaba/QLExpress/blob/master/src/test/java/com/ql/util/express/test/logic/ShortCircuitLogicTest.java) ### isTrace -```java - /** - * 是否输出所有的跟踪信息,同时还需要log级别是DEBUG级别 - */ - private boolean isTrace = false; +```java +/** +* Whether to output all trace information, and the log level is also required to be DEBUG level +*/ +private boolean isTrace = false; ``` -这个主要是是否输出脚本的编译解析过程,一般对于业务系统来说关闭之后会提高性能。 +This is mainly the process of compiling and analyzing whether to output the script. Generally, the performance of the business system will be improved after it is closed. -## 2、调用入参 +## 2. Call the input parameters ```java /** - * 执行一段文本 - * @param expressString 程序文本 - * @param context 执行上下文,可以扩展为包含ApplicationContext - * @param errorList 输出的错误信息List - * @param isCache 是否使用Cache中的指令集,建议为true - * @param isTrace 是否输出详细的执行指令信息,建议为false - * @param aLog 输出的log + * Execute a text + * @param expressString program text + * @param context execution context can be extended to include ApplicationContext + * @param errorList List of error messages output + * @param isCache Whether to use the instruction set in Cache, it is recommended to be true + * @param isTrace Whether to output detailed execution command information, it is recommended to be false + * @param aLog output log * @return * @throws Exception */ - Object execute(String expressString, IExpressContext context,List errorList, boolean isCache, boolean isTrace, Log aLog); +Object execute(String expressString, IExpressContext context,List errorList, boolean isCache, boolean isTrace, Log aLog); ``` -## 3、功能扩展API列表 -QLExpress主要通过子类实现Operator.java提供的以下方法来最简单的操作符定义,然后可以被通过addFunction或者addOperator的方式注入到ExpressRunner中。 +## 3. Function extension API list +QLExpress mainly implements the simplest operator definition through the following methods provided by Operator.java through subclasses, which can then be injected into ExpressRunner through addFunction or addOperator. ```java - public abstract Object executeInner(Object[] list) throws Exception; +public abstract Object executeInner(Object[] list) throws Exception; ``` -比如我们几行代码就可以实现一个功能超级强大、非常好用的join操作符: +For example, we can implement a super powerful and very useful join operator with a few lines of code: -_list = 1 join 2 join 3;_ -> [1,2,3] -_list = join(list,4,5,6);_ -> [1,2,3,4,5,6] +_list = 1 join 2 join 3;_ -> [1,2,3] +_list = join(list,4,5,6);_ -> [1,2,3,4,5,6] ```java public class JoinOperator extends Operator{ - public Object executeInner(Object[] list) throws Exception { +public Object executeInner(Object[] list) throws Exception { java.util.List result = new java.util.ArrayList(); Object opdata1 = list[0]; if(opdata1 instanceof java.util.List){ @@ -419,186 +417,186 @@ public class JoinOperator extends Operator{ result.add(list[i]); } return result; - } +} } ``` -如果你使用Operator的基类OperatorBase.java将获得更强大的能力,基本能够满足所有的要求。 +If you use OperatorBase.java, the base class of Operator, you will get more powerful capabilities and can basically meet all requirements. -### (1)function相关API +### (1) function related API ```java -//通过name获取function的定义 +//Get the definition of function by name OperatorBase getFunciton(String name); -//通过自定义的Operator来实现类似:fun(a,b,c) +//Achieve similar through a custom Operator: fun(a,b,c) void addFunction(String name, OperatorBase op); -//fun(a,b,c) 绑定 object.function(a,b,c)对象方法 +//fun(a,b,c) bind object.function(a,b,c) object method void addFunctionOfServiceMethod(String name, Object aServiceObject, - String aFunctionName, Class[] aParameterClassTypes, - String errorInfo); -//fun(a,b,c) 绑定 Class.function(a,b,c)类方法 +String aFunctionName, Class[] aParameterClassTypes, +String errorInfo); +//fun(a,b,c) bind Class.function(a,b,c) class method void addFunctionOfClassMethod(String name, String aClassName, - String aFunctionName, Class[] aParameterClassTypes, - String errorInfo); -//给Class增加或者替换method,同时 支持a.fun(b) ,fun(a,b) 两种方法调用 -//比如扩展String.class的isBlank方法:“abc”.isBlank()和isBlank("abc")都可以调用 +String aFunctionName, Class[] aParameterClassTypes, +String errorInfo); +//Add or replace method to Class, and support a.fun(b) and fun(a,b) two method calls +//For example, the isBlank method of extending String.class: "abc".isBlank() and isBlank("abc") can be called void addFunctionAndClassMethod(String name,ClassbindingClass, OperatorBase op); ``` -### (2)Operator相关API +### (2) Operator related API -提到脚本语言的操作符,优先级、运算的目数、覆盖原始的操作符(+,-,*,/等等)都是需要考虑的问题,QLExpress统统帮你搞定了。 +When it comes to the operators of scripting languages, precedence, number of operations, overriding the original operators (+, -, *, / etc.) are all issues that need to be considered. QLExpress will take care of it all for you. ```java - //添加操作符号,可以设置优先级 +//Add operation symbols, you can set the priority void addOperator(String name,Operator op); void addOperator(String name,String aRefOpername,Operator op); - - //替换操作符处理 +To +//Replacement operator processing OperatorBase replaceOperator(String name,OperatorBase op); - //添加操作符和关键字的别名,比如 if..then..else -> 如果。。那么。。否则。。 + //Add aliases for operators and keywords, such as if..then..else -> if. . Well. . otherwise. . void addOperatorWithAlias(String keyWordName, String realKeyWordName, - String errorInfo); +String errorInfo); ``` -### (3)宏定义相关API -QLExpress的宏定义比较简单,就是简单的用一个变量替换一段文本,和传统的函数替换有所区别。 +### (3) Macro definition related API +The macro definition of QLExpress is relatively simple. It simply replaces a piece of text with a variable, which is different from the traditional function replacement. ```java -//比如addMacro("天猫卖家","userDO.userTag &1024 ==1024") -void addMacro(String macroName,String express) +//Such as addMacro("Tmall seller","userDO.userTag &1024 ==1024") +void addMacro(String macroName,String express) ``` -### (4)java class的相关api -QLExpress可以通过给java类增加或者改写一些method和field,比如 链式调用:"list.join("1").join("2")",比如中文属性:"list.长度"。 +### (4) Related APIs of java class +QLExpress can add or rewrite some methods and fields to java classes, such as chain call: "list.join("1").join("2")", such as Chinese attribute: "list. length". ```java -//添加类的属性字段 +//Add the attribute field of the class void addClassField(String field,ClassbindingClass,ClassreturnType,Operator op); -//添加类的方法 +//Method of adding class void addClassMethod(String name,ClassbindingClass,OperatorBase op); ``` -> 注意,这些类的字段和方法是执行器通过解析语法执行的,而不是通过字节码增强等技术,所以只在脚本运行期间生效,不会对jvm整体的运行产生任何影响,所以是绝对安全的。 +> Note that the fields and methods of these classes are executed by the executor through parsing syntax, not through bytecode enhancement and other technologies, so they only take effect during the running of the script and will not have any impact on the overall operation of the jvm, so it is absolutely safe. -### (4)语法树解析变量、函数的API +### (4) Syntax tree parses the API of variables and functions -> 这些接口主要是对一个脚本内容的静态分析,可以作为上下文创建的依据,也可以用于系统的业务处理。 -> 比如:计算 “a+fun1(a)+fun2(a+b)+c.getName()” -> 包含的变量:a,b,c -> 包含的函数:fun1,fun2 +> These interfaces are mainly static analysis of the content of a script, which can be used as a basis for context creation, and can also be used for system business processing. +> For example: calculate "a+fun1(a)+fun2(a+b)+c.getName()" +> Variables included: a, b, c +> Functions included: fun1, fun2 ```java -//获取一个表达式需要的外部变量名称列表 +//Get a list of external variable names required by an expression String[] getOutVarNames(String express); String[] getOutFunctionNames(String express); ``` -### (5)语法解析校验api -脚本语法是否正确,可以通过ExpressRunner编译指令集的接口来完成。 +### (5) Syntax parsing and verification api +Whether the script syntax is correct can be completed through the interface of the ExpressRunner compilation instruction set. ```java String expressString = "for(i=0;i<10;i++){sum=i+1}return sum;"; InstructionSet instructionSet = expressRunner.parseInstructionSet(expressString); -//如果调用过程不出现异常,指令集instructionSet就是可以被加载运行(execute)了! +//If there is no abnormality in the calling process, the instruction set instructionSet can be loaded and run (execute)! ``` -### (6)指令集缓存相关的api -因为QLExpress对文本到指令集做了一个本地HashMap缓存,通常情况下一个设计合理的应用脚本数量应该是有限的,缓存是安全稳定的,但是也提供了一些接口进行管理。 +### (6) APIs related to instruction set cache +Because QLExpress has a local HashMap cache for the text to the instruction set, usually the number of a reasonably designed application script should be limited, the cache is safe and stable, but it also provides some interfaces for management. ```java - //优先从本地指令集缓存获取指令集,没有的话生成并且缓存在本地 - InstructionSet getInstructionSetFromLocalCache(String expressString); - //清除缓存 - void clearExpressCache(); +//Preferably get the instruction set from the local instruction set cache, if not, generate it and cache it locally +InstructionSet getInstructionSetFromLocalCache(String expressString); + //clear cache +void clearExpressCache(); ``` -### (7)安全风险控制 -#### 7.1 防止死循环 +### (7) Security risk control +#### 7.1 Prevent infinite loop ```java try { - express = "sum=0;for(i=0;i<1000000000;i++){sum=sum+i;}return sum;"; - //可通过timeoutMillis参数设置脚本的运行超时时间:1000ms - Object r = runner.execute(express, context, null, true, false, 1000); - System.out.println(r); - throw new Exception("没有捕获到超时异常"); + express = "sum=0;for(i=0;i<1000000000;i++){sum=sum+i;}return sum;"; +//The running timeout time of the script can be set through the timeoutMillis parameter: 1000ms +Object r = runner.execute(express, context, null, true, false, 1000); +System.out.println(r); +throw new Exception("The timeout exception was not caught"); } catch (QLTimeOutException e) { - System.out.println(e); +System.out.println(e); } ``` -#### 7.1 防止调用不安全的系统api +#### 7.1 Prevent calling unsafe system APIs ```java ExpressRunner runner = new ExpressRunner(); QLExpressRunStrategy.setForbiddenInvokeSecurityRiskMethods(true); DefaultContext context = new DefaultContext(); try { - express = "System.exit(1);"; - Object r = runner.execute(express, context, null, true, false); - System.out.println(r); - throw new Exception("没有捕获到不安全的方法"); + express = "System.exit(1);"; +Object r = runner.execute(express, context, null, true, false); +System.out.println(r); +throw new Exception("Unsafe method was not caught"); } catch (QLException e) { - System.out.println(e); +System.out.println(e); } ``` -### (8)增强上下文参数Context相关的api +### (8) Enhance the api related to the context parameter Context -#### 8.1 与spring框架的无缝集成 -上下文参数 IExpressContext context 非常有用,它允许put任何变量,然后在脚本中识别出来。 +#### 8.1 Seamless integration with spring framework +The context parameter IExpressContext context is very useful, it allows to put any variable, and then identify it in the script. -在实际中我们很希望能够无缝的集成到spring框架中,可以仿照下面的例子使用一个子类。 +In practice, we very much hope to be able to seamlessly integrate into the spring framework, and we can use a subclass to imitate the following example. ```java public class QLExpressContext extends HashMap implements - IExpressContext { +IExpressContext { - private ApplicationContext context; +private ApplicationContext context; - //构造函数,传入context和 ApplicationContext - public QLExpressContext(Map map, +//Constructor, pass in context and ApplicationContext +public QLExpressContext(Map map, ApplicationContext aContext) { - super(map); - this.context = aContext; - } - - /** - * 抽象方法:根据名称从属性列表中提取属性值 - */ - public Object get(Object name) { - Object result = null; - result = super.get(name); - try { - if (result == null && this.context != null - && this.context.containsBean((String) name)) { - // 如果在Spring容器中包含bean,则返回String的Bean - result = this.context.getBean((String) name); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - return result; - } - - public Object put(String name, Object object) { - return super.put(name, object); - } +super(map); +this.context = aContext; +} + +/** +* Abstract method: extract attribute value from attribute list based on name +*/ +public Object get(Object name) { +Object result = null; +result = super.get(name); +try { +if (result == null && this.context != null +&& this.context.containsBean((String) name)) { +// If the bean is contained in the Spring container, the String bean is returned +result = this.context.getBean((String) name); +} +} catch (Exception e) { +throw new RuntimeException(e); +} +return result; +} + +public Object put(String name, Object object) { +return super.put(name, object); +} } ``` -完整的demo参照 [SpringDemoTest.java](https://github.com/alibaba/QLExpress/blob/master/src/test/java/com/ql/util/express/test/spring/SpringDemoTest.java) +Complete demo reference [SpringDemoTest.java](https://github.com/alibaba/QLExpress/blob/master/src/test/java/com/ql/util/express/test/spring/SpringDemoTest.java) -#### 8.2 自定义函数操作符获取原始的context控制上下文 +#### 8.2 Custom function operator to obtain the original context control context -自定义的Operator需要直接继承OperatorBase,获取到parent即可,可以用于在运行一组脚本的时候,直接编辑上下文信息,业务逻辑处理上也非常有用。 +A custom Operator needs to directly inherit OperatorBase and get the parent. It can be used to directly edit context information when running a set of scripts. It is also very useful in business logic processing. ```java @@ -625,7 +623,7 @@ public class ContextMessagePutTest { ExpressRunner runner = new ExpressRunner(); OperatorBase op = new OperatorContextPut("contextPut"); runner.addFunction("contextPut",op); - String exp = "contextPut('success','false');contextPut('error','错误信息');contextPut('warning','提醒信息')"; + String exp = "contextPut('success','false');contextPut('error','error information');contextPut('warning','remind information')"; IExpressContext context = new DefaultContext(); context.put("success","true"); Object result = runner.execute(exp,context,null,false,true); @@ -636,12 +634,5 @@ public class ContextMessagePutTest { ``` -附录: -[版本更新列表](VERSIONS.md) - -## links for us -- Gitter channel - Online chat room with QLExpress developers. [Gitter channel ](https://gitter.im/QLExpress/Lobby) -- email:tianqiao@alibaba-inc.com,baoxingjie@126.com -- wechart:371754252 -- QLExpress blogs: https://yq.aliyun.com/album/130 - +appendix: +[Version update list](VERSIONS.md) diff --git a/VERSIONS.md b/VERSIONS.md index bd592607f..e52358980 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -1,126 +1,639 @@ -# QLExpress基本语法 +# QLExpress basic syntax -# 一、背景介绍 +# I. Background introduction -由阿里的电商业务规则、表达式(布尔组合)、特殊数学公式计算(高精度)、语法分析、脚本二次定制等强需求而设计的一门动态脚本引擎解析工具。 -在阿里集团有很强的影响力,同时为了自身不断优化、发扬开源贡献精神,于2012年开源。 -先后出现了1.0版本和2.0版本,到3.0版本之后,引入了比较系统的语法树推导,使语法的功能大大增强和稳定。 -之前svn的开源地址: http://code.taobao.org/p/QLExpress/src/branches/ +A dynamic script engine parsing tool designed by Ali's strong requirements for e-commerce business rules, expressions (Boolean combinations), special mathematical formula calculations (high precision), syntax analysis, and secondary script customization. +It has a strong influence in Alibaba Group. At the same time, in order to continuously optimize and carry forward the spirit of open source contribution, it was open sourced in 2012. -# 二、有记录的版本迭代 +The QLExpress script engine is widely used in Ali's e-commerce business scenarios and has the following characteristics: + 1. Thread safety. Temporary variables generated during engine operation are all threadlocal. + 2. Efficient execution. The time-consuming script compilation process can be cached on the local machine. The temporary variable creation at runtime uses the technology of buffer pool, which is equivalent to groovy performance. + 3. Weakly typed scripting language, similar to groovy and javascript, although it is slower than strong typed scripting language, it greatly enhances business flexibility. + 4. Safety control, you can prevent dead loops and high-risk system api calls by setting relevant operating parameters. + 5. The code is streamlined and the dependency is minimal. The 250k jar package is suitable for all java operating environments, and it is also widely used in the low-end pos machines of the android system. -## 1、3.0.7-SNAPSHOT 版本[2014-06-06 fixed] -BigDecimal.divide()函数增加默认的策略BigDecimal.ROUND_HALF_UP,防止在高精度要求的除法计算时,某些情况下出现以下异常。 -ava.lang.ArithmeticException: Non-terminating decimal expansion +# II. Dependency and call instructions -## 2、3.0.7版本[2015-01-08 fixed] -增加ExpressRunner.getInstructionSetFromLocalCache()方法。支持阿里的某个业务系统,支持直接获取本地指令集缓存,作为业务的判断场景需求。 +```xml + + com.alibaba + QLExpress + 3.2.0 + +``` -## 3、3.0.8版本[2015-04-23 fixed] -(1)增加指令集错误日志打印输出的控制。支付宝解析外部脚本文件,文件信息有可能出现错误,处理的时候打印log日志导致应用压力太大。 -(2)修复线上bug,该业务方不恰当的使用addFunctionMethod(class.name,methodName....)导致脚本运行期间每次去new Object(),效率变慢,影响了qps,换用了addServiceMethod(bean,methodName)之后得到解决。 -对classname-object做了一层缓存保护,保证即使误用也能够获取到较好地性能。 +```java +ExpressRunner runner = new ExpressRunner(); +DefaultContext context = new DefaultContext(); +context.put("a",1); +context.put("b",2); +context.put("c",3); +String express = "a+b*c"; +Object r = runner.execute(express, context, null, true, false); +System.out.println(r); +``` +# III. grammar introduction +## 1. Operators and java object operations +### Ordinary java syntax +``` +//Support +,-,*,/,<,>,<=,>=,==,!=,<>[Equivalent to !=],%,mod[Modulo equal to%],++, --, +//in [similar to sql], like [sql syntax], &&,||,!, and other operators +//Support standard program control logic such as for, break, continue, if then else +n=10; +for(sum=0,i=0;ib?a:b; -com.ql.util.express.bugfix.CrashTest +``` -根本解决方案:在ExpressRunner创建的时候,就排序完毕,之后不再排序,保证多线程安全,同时也提升了编译器的性能和效率。 -临时解决方案:在脚本中,需要分割的地方加一些不可见字符,比如空格等。 +### Compared with java syntax, some ql writing errors to avoid +-Does not support try{}catch{} +-Comments currently only support /** **/, single-line comments are not supported // +-Java8 lambda expressions are not supported +-Does not support for loop collection operation for (GRCRouteLineResultDTO item: list) +-Weakly typed languages, please do not define type declarations, let alone use Templete (Map and the like) +-The declaration of array is different +-min, max, round, print, println, like, in are all keywords of the system default functions, please do not use them as variable names -比如:"单价*数量+运费" 修改成 "单价 * 数量 + 运费" 就会不受这个bug影响 -目前要求所有核心系统版本升级到3.0.9及以上版本。 -```xml - - com.taobao.util - taobao-express - 3.0.9 - ``` - +//java syntax: use generics to remind developers to check the type +keys = new ArrayList(); +deviceName2Value = new HashMap(7); +String[] deviceNames = {"ng","si","umid","ut","mac","imsi","imei"}; +int[] mins = {5,30}; + +//ql writing: +keys = new ArrayList(); +deviceName2Value = new HashMap(); +deviceNames = ["ng","si","umid","ut","mac","imsi","imei"]; +mins = [5,30]; + + +//java syntax: object type declaration +FocFulfillDecisionReqDTO reqDTO = param.getReqDTO(); +//ql writing: +reqDTO = param.getReqDTO(); + +//java syntax: array traversal +for(GRCRouteLineResultDTO item: list) { +} +//ql writing: +for(i=0;i context, List errorList, - boolean isTrace,boolean isCatchException, Log aLog) +a=10; +return add(a,4) + sub(a,9); +``` + +## 3. Extended operator: Operator +### Replace keywords such as if then else + +```java +runner.addOperatorWithAlias("if", "if",null); +runner.addOperatorWithAlias("then", "then",null); +runner.addOperatorWithAlias("Otherwise", "else",null); + +exp = "If (language+mathematics+English>270) then {return 1;} otherwise {return 0;}"; +DefaultContext context = new DefaultContext(); +runner.execute(exp,context,null,false,false,null); +``` + +### How to customize Operator +```java +//Define an operator inherited from com.ql.util.express.Operator +public class JoinOperator extends Operator{ +public Object executeInner(Object[] list) throws Exception { +Object opdata1 = list[0]; +Object opdata2 = list[1]; +if(opdata1 instanceof java.util.List){ +((java.util.List)opdata1).add(opdata2); +return opdata1; +}else{ +java.util.List result = new java.util.ArrayList(); +result.add(opdata1); +result.add(opdata2); +return result; +} +} +} + +``` +### How to use Operator + +``` +//(1)addOperator +ExpressRunner runner = new ExpressRunner(); +DefaultContext context = new DefaultContext(); +runner.addOperator("join",new JoinOperator()); +Object r = runner.execute("1 join 2 join 3", context, null, false, false); +System.out.println(r); +//Return result [1, 2, 3] + +//(2)replaceOperator +ExpressRunner runner = new ExpressRunner(); +DefaultContext context = new DefaultContext(); +runner.replaceOperator("+",new JoinOperator()); +Object r = runner.execute("1 + 2 + 3", context, null, false, false); +System.out.println(r); +//Return result [1, 2, 3] + +//(3)addFunction +ExpressRunner runner = new ExpressRunner(); +DefaultContext context = new DefaultContext(); +runner.addFunction("join",new JoinOperator()); +Object r = runner.execute("join(1,2,3)", context, null, false, false); +System.out.println(r); +//Return result [1, 2, 3] + +``` +## 4. Binding method of java class or object + +addFunctionOfClassMethod+addFunctionOfServiceMethod + +``` + +public class BeanExample { +public static String upper(String abc) { +return abc.toUpperCase(); +} +public boolean anyContains(String str, String searchStr) { + + char[] s = str.toCharArray(); + for (char c: s) { + if (searchStr.contains(c+"")) { + return true; + } + } + return false; + } +} + +runner.addFunctionOfClassMethod("Take the absolute value", Math.class.getName(), "abs", +new String[] {"double" }, null); +runner.addFunctionOfClassMethod("Convert to uppercase", BeanExample.class.getName(), +"upper", new String[] {"String" }, null); + +runner.addFunctionOfServiceMethod("Print", System.out, "println",new String[] {"String" }, null); +runner.addFunctionOfServiceMethod("contains", new BeanExample(), "anyContains", + new Class[] {String.class, String.class }, null); + +String exp = "Take the absolute value (-100); convert to uppercase (\"hello world\"); print (\"How are you?\"); contains("helloworld",\"aeiou\")"; +runner.execute(exp, context, null, false, false); + +``` + + + ## 5, macro macro definition + +``` +runner.addMacro("Calculate average score", "(Chinese+Math+English)/3.0"); +runner.addMacro("Is it excellent", "Calculate the average score>90"); +IExpressContext context =new DefaultContext(); +context.put("语文", 88); +context.put("Mathematics", 99); +context.put("English", 95); +Object result = runner.execute("Is it excellent", context, null, false, false); +System.out.println(r); +//Return the result true + +``` + + ## 6. Compile the script and query external variables and functions that need to be defined. + **Note the difference between the following script int and no int** + +``` +String express = "int average score = (language + mathematics + English + comprehensive examination. Subject 2)/4.0; return average score"; +ExpressRunner runner = new ExpressRunner(true,true); +String[] names = runner.getOutVarNames(express); +for(String s:names){ + System.out.println("var: "+ s); +} + +//Output result: + +var: mathematics +var: Comprehensive examination +var: English +var: language +``` + +## 7. About the use of indefinite parameters +``` + @Test + public void testMethodReplace() throws Exception { + ExpressRunner runner = new ExpressRunner(); + IExpressContext expressContext = new DefaultContext(); + runner.addFunctionOfServiceMethod("getTemplate", this, "getTemplate", new Class[]{Object[].class}, null); + + //(1) The default indefinite parameters can be replaced by arrays + Object r = runner.execute("getTemplate([11,'22',33L,true])", expressContext, null,false, false); + System.out.println(r); + //(2) Like java, support function dynamic parameter call, you need to turn on the following global switches, otherwise the following calls will fail + DynamicParamsUtil.supportDynamicParams = true; + r = runner.execute("getTemplate(11,'22',33L,true)", expressContext, null,false, false); + System.out.println(r); + } + //Equivalent to getTemplate(Object[] params) + public Object getTemplate(Object... params) throws Exception{ + String result = ""; + for(Object obj:params){ + result = result+obj+","; + } + return result; + } + ``` + +## 8. Shortcuts on the collection + +``` + @Test + public void testSet() throws Exception { + ExpressRunner runner = new ExpressRunner(false,false); + DefaultContext context = new DefaultContext(); + String express = "abc = NewMap(1:1,2:2); return abc.get(1) + abc.get(2);"; + Object r = runner.execute(express, context, null, false, false); + System.out.println(r); + express = "abc = NewList(1,2,3); return abc.get(1)+abc.get(2)"; + r = runner.execute(express, context, null, false, false); + System.out.println(r); + express = "abc = [1,2,3]; return abc[1]+abc[2];"; + r = runner.execute(express, context, null, false, false); + System.out.println(r); + } + +``` + +## 9, the traversal of the collection +In fact, the syntax is similar to java, but ql does not support the syntax of for(obj:list){} and can only be accessed through subscripts. +```java + //Traverse the map + map = new HashMap(); + map.put("a", "a_value"); + map.put("b", "b_value"); + keySet = map.keySet(); + objArr = keySet.toArray(); + for (i=0;i High-precision calculations are very important in accounting and finance. There are many implicit conversions of float, double, int, and long in java. There are actually a lot of security risks when doing four arithmetic operations and comparisons. +> So in a system like Huijin, there will be many BigDecimal conversion codes. With QLExpress, you only need to pay attention to the mathematical formula itself _ order total price = unit price * quantity + first weight price + (total weight-first weight) * continued weight unit price_, and then set this attribute, all intermediate calculations will be guaranteed No loss of accuracy. + +### isShortCircuit + +```java +/** +* Whether to use logic short circuit feature +*/ +private boolean isShortCircuit = true; +``` +In many business decision-making systems, it is often necessary to analyze and output Boolean conditional expressions. Ordinary Java operations generally reduce performance consumption through logic short-circuits. For example, the rule formula: +_star>10000 and shoptype in('tmall','juhuasuan') and price between (100,900)_ +Assuming that the first condition _star>10000_ is not met, stop the operation. However, the business system still hopes to calculate the following logic and output the intermediate process to ensure faster and better decisions. + +Refer to unit test: [ShortCircuitLogicTest.java](https://github.com/alibaba/QLExpress/blob/master/src/test/java/com/ql/util/express/test/logic/ShortCircuitLogicTest.java) + +### isTrace + +```java +/** +* Whether to output all trace information, and the log level is also required to be DEBUG level +*/ +private boolean isTrace = false; +``` +This is mainly the process of compiling and analyzing whether to output the script. Generally, the performance of the business system will be improved after it is closed. + +## 2. Call the input parameters + +```java +/** + * Execute a text + * @param expressString program text + * @param context execution context can be extended to include ApplicationContext + * @param errorList List of error messages output + * @param isCache Whether to use the instruction set in Cache, it is recommended to be true + * @param isTrace Whether to output detailed execution command information, it is recommended to be false + * @param aLog output log + * @return + * @throws Exception + */ +Object execute(String expressString, IExpressContext context,List errorList, boolean isCache, boolean isTrace, Log aLog); + +``` + +## 3. Function extension API list +QLExpress mainly implements the simplest operator definition through the following methods provided by Operator.java through subclasses, which can then be injected into ExpressRunner through addFunction or addOperator. +```java +public abstract Object executeInner(Object[] list) throws Exception; -## 8、3.0.14版本[2016-09-13] -(1)支持java不定参数的调用 -(2)提高数组定义的灵活性和准确性。 +``` + +For example, we can implement a super powerful and very useful join operator with a few lines of code: + +_list = 1 join 2 join 3;_ -> [1,2,3] +_list = join(list,4,5,6);_ -> [1,2,3,4,5,6] + +```java +public class JoinOperator extends Operator{ +public Object executeInner(Object[] list) throws Exception { + java.util.List result = new java.util.ArrayList(); + Object opdata1 = list[0]; + if(opdata1 instanceof java.util.List){ + result.addAll((java.util.List)opdata1); + }else{ + result.add(opdata1); + } + for(int i=1;i[] aParameterClassTypes, +String errorInfo); +//fun(a,b,c) bind Class.function(a,b,c) class method +void addFunctionOfClassMethod(String name, String aClassName, +String aFunctionName, Class[] aParameterClassTypes, +String errorInfo); +//Add or replace method to Class, and support a.fun(b) and fun(a,b) two method calls +//For example, the isBlank method of extending String.class: "abc".isBlank() and isBlank("abc") can be called +void addFunctionAndClassMethod(String name,ClassbindingClass, OperatorBase op); + +``` + +### (2) Operator related API + +When it comes to the operators of scripting languages, precedence, number of operations, overriding the original operators (+, -, *, / etc.) are all issues that need to be considered. QLExpress will take care of it all for you. -## 9、3.0.15版本[2016-10-26] -(1)支持Method导出,用于给菜鸟业务动态绑定函数使用 +```java +//Add operation symbols, you can set the priority +void addOperator(String name,Operator op); +void addOperator(String name,String aRefOpername,Operator op); +To +//Replacement operator processing +OperatorBase replaceOperator(String name,OperatorBase op); + + //Add aliases for operators and keywords, such as if..then..else -> if. . Well. . otherwise. . +void addOperatorWithAlias(String keyWordName, String realKeyWordName, +String errorInfo); -## 10、3.0.16版本[2016-10-28] -(1)支持在脚本中给任意的Object增加字段field或者方法method,比如增加string的方法,"helloworld".isNotBlank()或者"helloworld".长度 非常安全,只在脚本中生效,没有采用任何aop或者增强字节码的技术,不会影响外部的调用。 +``` + +### (3) Macro definition related API +The macro definition of QLExpress is relatively simple. It simply replaces a piece of text with a variable, which is different from the traditional function replacement. + +```java +//Such as addMacro("Tmall seller","userDO.userTag &1024 ==1024") +void addMacro(String macroName,String express) +``` -## 11、3.0.17版本[2016-11-30] -(1)考虑到老系统二方包的兼容,恢复了兼容接口ExpressRunner.execute(InstructionSet[] instructionSets....)但是不推荐使用。 -(2)bugfix 3.0.16版本特性的表达式,最后不return情况下的bug。 +### (4) Related APIs of java class +QLExpress can add or rewrite some methods and fields to java classes, such as chain call: "list.join("1").join("2")", such as Chinese attribute: "list. length". -## 12、3.0.18版本[2017-1-16] -(1)来自开源用户的反馈,bugfix 使用addFunctionOfServiceMethod指令集无法序列化的问题。 +```java +//Add the attribute field of the class +void addClassField(String field,ClassbindingClass,ClassreturnType,Operator op); -## 12、3.1.0版本[2017-3-27] -(1)增加 | & ~ << >>位操作符 -(2)增加executeRule函数,打印出规则逻辑结构 +//Method of adding class +void addClassMethod(String name,ClassbindingClass,OperatorBase op); +``` -## 13、3.1.1版本[2017-4-5] -(1)增加指令集的行数,出错的时候增加出错行数信息 +> Note that the fields and methods of these classes are executed by the executor through parsing syntax, not through bytecode enhancement and other technologies, so they only take effect during the running of the script and will not have any impact on the overall operation of the jvm, so it is absolutely safe. -## 14、3.1.3版本[2017-6-4] -(1)内部版本调整,避免其他的分支干扰,覆盖版本3.1.2版本 +### (4) Syntax tree parses the API of variables and functions -## 15、3.1.4版本[2017-9-19] -(1)增加instanceof 的操作符 +> These interfaces are mainly static analysis of the content of a script, which can be used as a basis for context creation, and can also be used for system business processing. +> For example: calculate "a+fun1(a)+fun2(a+b)+c.getName()" +> Variables included: a, b, c +> Functions included: fun1, fun2 -## 16、3.1.5版本[2017-11-17] -(1)负号某些特殊情况下的解析bug:三元操作符,return +```java +//Get a list of external variable names required by an expression +String[] getOutVarNames(String express); -## 17、3.1.6版本[2017-11-17] -(1)bugfix 嵌套runner调用的时候,数据池的还原 +String[] getOutFunctionNames(String express); +``` -## 18、3.1.7版本[2017-11-17] -(1)bugfix 在自定义操作符的情况下,调用 runner.getOutVarNames Api 可能引发的空指针问题 +### (5) Syntax parsing and verification api +Whether the script syntax is correct can be completed through the interface of the ExpressRunner compilation instruction set. +```java +String expressString = "for(i=0;i<10;i++){sum=i+1}return sum;"; +InstructionSet instructionSet = expressRunner.parseInstructionSet(expressString); +//If there is no abnormality in the calling process, the instruction set instructionSet can be loaded and run (execute)! +``` -## 18、3.1.8版本[2018-1-30] -(1)增加扩展功能:ExpressRunner#setIgnoreConstChar(Boolean),设置可以忽略单字符操作,即 'a'自动变成"a"。 +### (6) APIs related to instruction set cache +Because QLExpress has a local HashMap cache for the text to the instruction set, usually the number of a reasonably designed application script should be limited, the cache is safe and stable, but it also provides some interfaces for management. +```java +//Preferably get the instruction set from the local instruction set cache, if not, generate it and cache it locally +InstructionSet getInstructionSetFromLocalCache(String expressString); + //clear cache +void clearExpressCache(); +``` -## 3.2.1版本[2018-2-23] -(1)增加扩展功能:ExpressRunner#setIgnoreConstChar(Boolean),设置可以忽略单字符操作,即 'a'自动变成"a"。 +### (7) Security risk control +#### 7.1 Prevent infinite loop +```java + try { + express = "sum=0;for(i=0;i<1000000000;i++){sum=sum+i;}return sum;"; +//The running timeout time of the script can be set through the timeoutMillis parameter: 1000ms +Object r = runner.execute(express, context, null, true, false, 1000); +System.out.println(r); +throw new Exception("The timeout exception was not caught"); + } catch (QLTimeOutException e) { +System.out.println(e); + } +``` +#### 7.1 Prevent calling unsafe system APIs +```java + ExpressRunner runner = new ExpressRunner(); + QLExpressRunStrategy.setForbiddenInvokeSecurityRiskMethods(true); + + DefaultContext context = new DefaultContext(); + try { + express = "System.exit(1);"; +Object r = runner.execute(express, context, null, true, false); +System.out.println(r); +throw new Exception("Unsafe method was not caught"); + } catch (QLException e) { +System.out.println(e); + } +``` -(2)增加接口来支持绑定自定义classloader的class的method:ExpressRunner#addFunctionOfClassMethod(String name, Class aClass,...)。 +### (8) Enhance the api related to the context parameter Context + +#### 8.1 Seamless integration with spring framework +The context parameter IExpressContext context is very useful, it allows to put any variable, and then identify it in the script. + +In practice, we very much hope to be able to seamlessly integrate into the spring framework, and we can use a subclass to imitate the following example. + +```java +public class QLExpressContext extends HashMap implements +IExpressContext { + +private ApplicationContext context; + +//Constructor, pass in context and ApplicationContext +public QLExpressContext(Map map, + ApplicationContext aContext) { +super(map); +this.context = aContext; +} + +/** +* Abstract method: extract attribute value from attribute list based on name +*/ +public Object get(Object name) { +Object result = null; +result = super.get(name); +try { +if (result == null && this.context != null +&& this.context.containsBean((String) name)) { +// If the bean is contained in the Spring container, the String bean is returned +result = this.context.getBean((String) name); +} +} catch (Exception e) { +throw new RuntimeException(e); +} +return result; +} + +public Object put(String name, Object object) { +return super.put(name, object); +} + +} -## 3.2.2版本[2019-1-22] -(1)android环境的重大优化:减少编译的内存消耗,堆栈溢出问题 +``` -(2)空指针的保护策略:com.ql.util.express.config.QLExpressRunStrategy.setAvoidNullPointer(true) +Complete demo reference [SpringDemoTest.java](https://github.com/alibaba/QLExpress/blob/master/src/test/java/com/ql/util/express/test/spring/SpringDemoTest.java) + + +#### 8.2 Custom function operator to obtain the original context control context + +A custom Operator needs to directly inherit OperatorBase and get the parent. It can be used to directly edit context information when running a set of scripts. It is also very useful in business logic processing. + +```java + +public class ContextMessagePutTest { + + + class OperatorContextPut extends OperatorBase { + + public OperatorContextPut(String aName) { + this.name = aName; + } + + @Override + public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception { + String key = list.get(0).toString(); + Object value = list.get(1); + parent.put(key,value); + return null; + } + } + + @Test + public void test() throws Exception{ + ExpressRunner runner = new ExpressRunner(); + OperatorBase op = new OperatorContextPut("contextPut"); + runner.addFunction("contextPut",op); + String exp = "contextPut('success','false');contextPut('error','error information');contextPut('warning','remind information')"; + IExpressContext context = new DefaultContext(); + context.put("success","true"); + Object result = runner.execute(exp,context,null,false,true); + System.out.println(result); + System.out.println(context); + } +} -## 3.2.3版本[2019-6-18] -(1)增加超时方法:TimeOutExceptionTest +``` -(2)安全审核方法:InvokeSecurityRiskMethodsTest +appendix: +[Version update list](VERSIONS.md) -(3)区分异常类型:ThrowExceptionTest -## 3.2.4版本[2019-12-6] -(1)增加null的数字比较方案"1>null"":NullCompareTest \ No newline at end of file diff --git a/src/main/java/com/ql/util/express/CacheObject.java b/src/main/java/com/ql/util/express/CacheObject.java index 68dcfc499..6402c9a9d 100644 --- a/src/main/java/com/ql/util/express/CacheObject.java +++ b/src/main/java/com/ql/util/express/CacheObject.java @@ -3,7 +3,7 @@ import java.io.Serializable; /** - * 简单的缓存对象 + * Simple cache object * @author tianqiao * */ diff --git a/src/main/java/com/ql/util/express/DefaultExpressResourceLoader.java b/src/main/java/com/ql/util/express/DefaultExpressResourceLoader.java index 146ef7b41..930ef5de5 100644 --- a/src/main/java/com/ql/util/express/DefaultExpressResourceLoader.java +++ b/src/main/java/com/ql/util/express/DefaultExpressResourceLoader.java @@ -12,7 +12,7 @@ public String loadExpress(String expressName) throws Exception { InputStream in = Thread.currentThread().getContextClassLoader() .getResourceAsStream(expressName); if (in == null) { - throw new QLException("不能找到表达式文件:" + expressName); + throw new QLException("Cannot find expression file:" + expressName); } BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder builder = new StringBuilder(); diff --git a/src/main/java/com/ql/util/express/DynamicParamsUtil.java b/src/main/java/com/ql/util/express/DynamicParamsUtil.java index 2975e58a0..79fc1cfb1 100644 --- a/src/main/java/com/ql/util/express/DynamicParamsUtil.java +++ b/src/main/java/com/ql/util/express/DynamicParamsUtil.java @@ -14,10 +14,10 @@ public class DynamicParamsUtil { public static Object[] transferDynamicParams(InstructionSetContext context, ArraySwap list, Class[] delaredParamsClasses,boolean maybeDynamicParams) throws Exception { Object[] params = null; - //参数定义不符合动态参数形式 || 用户自定义不支持 || 用户传入的参数不符合 + //The parameter definition does not conform to the dynamic parameter form || User-defined does not support || The parameter passed in by the user does not conform if(!maybeDynamicParams || !supportDynamicParams || !maybeDynamicParams(context,list,delaredParamsClasses)){ if(delaredParamsClasses.length != list.length){ - throw new QLException("定义的参数长度与运行期传入的参数长度不一致"); + throw new QLException("The defined parameter length is inconsistent with the parameter length passed in during runtime"); } params = new Object[list.length]; for (int i = 0; i < list.length; i++) { @@ -26,7 +26,7 @@ public static Object[] transferDynamicParams(InstructionSetContext context, Arra return params; } - //支持不定参数的使用 function(arg1,arg2,arg3...) + //Support the use of indefinite parameters function(arg1,arg2,arg3...) //list -> parameres[] // arg1,arg2 -> arg1,arg2,[] // arg1,arg2,arg3,arg4,arg5 -> arg1,arg2,[arg3,arg4,arg5] @@ -47,7 +47,7 @@ public static Object[] transferDynamicParams(InstructionSetContext context, Arra } } }else { - throw new QLException("定义的参数长度与运行期传入的参数长度不一致"); + throw new QLException("The defined parameter length is inconsistent with the parameter length passed in during runtime"); } return params; @@ -65,11 +65,11 @@ public static boolean maybeDynamicParams(Class[] delaredParamsClasses) private static boolean maybeDynamicParams(InstructionSetContext context, ArraySwap list, Class[] delaredParamsClasses) throws Exception { - //长度不一致,有可能 + //Inconsistent length, it is possible if(delaredParamsClasses.length != list.length) { return true; } - //长度一致的不定参数:不定参数的数组,只输入了一个参数并且为array,有可能 + //Indefinite parameters with the same length: an array of indefinite parameters, only one parameter is input and it is an array, it is possible int length = list.length; Object lastParam = list.get(length-1).getObject(context); if(lastParam!=null && !lastParam.getClass().isArray()) diff --git a/src/main/java/com/ql/util/express/ExportItem.java b/src/main/java/com/ql/util/express/ExportItem.java index acfc3d9e6..dd4a78c98 100644 --- a/src/main/java/com/ql/util/express/ExportItem.java +++ b/src/main/java/com/ql/util/express/ExportItem.java @@ -3,7 +3,7 @@ import java.io.Serializable; /** - * 输出给其它指令共享使用的对象 + * Output to objects shared by other commands * @author xuannan * */ @@ -16,7 +16,7 @@ public class ExportItem implements Serializable{ String globeName; String name; String type;//def,alias - String desc;//类名或者别名 + String desc;//Class name or alias public ExportItem(String aName,String aType,String aDesc){ this.globeName = aName; this.name = aName; diff --git a/src/main/java/com/ql/util/express/ExpressClassLoader.java b/src/main/java/com/ql/util/express/ExpressClassLoader.java index 483140359..13f2242cc 100644 --- a/src/main/java/com/ql/util/express/ExpressClassLoader.java +++ b/src/main/java/com/ql/util/express/ExpressClassLoader.java @@ -13,7 +13,7 @@ public Class loadClass(String name, byte[] code) { public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - //System.out.print("开始查找 类" + name + "。。。。。。。。。。。"); + //System.out.print("Start to find class" + name + "。。。。。。。。。。。"); Class clasz = findLoadedClass(this, name); if (clasz != null) { //System.out.println(clasz.getClassLoader()); @@ -22,7 +22,7 @@ public synchronized Class loadClass(String name, boolean resolve) if (clasz == null) { clasz = parentLoadClass(this, name); } - if (clasz == null && name.startsWith("[")) { // 进行数组处理 + if (clasz == null && name.startsWith("[")) { // Array processing int index = name.indexOf("L"); String str = name.substring(0, index); String componentClassName = name.substring(index + 1, @@ -35,7 +35,7 @@ public synchronized Class loadClass(String name, boolean resolve) Class componentType = this.loadClass(componentClassName); clasz = Array.newInstance(componentType, dimes).getClass(); } catch (Exception e) { - // 不错处理 + // Good deal } } @@ -72,7 +72,7 @@ public static Class findLoadedClass(ClassLoader loader, String name) public static Class parentLoadClass(ClassLoader loader, String name) throws ClassNotFoundException { - // 如果存在这个类,则直接返回 + // If this class exists, return directly Class clasz = null; if (clasz == null) { try { diff --git a/src/main/java/com/ql/util/express/ExpressLoader.java b/src/main/java/com/ql/util/express/ExpressLoader.java index cf42a2912..e82037c20 100644 --- a/src/main/java/com/ql/util/express/ExpressLoader.java +++ b/src/main/java/com/ql/util/express/ExpressLoader.java @@ -9,7 +9,7 @@ /** - * 表达式装载器 + * Expression loader * * @author xuannan * @@ -29,7 +29,7 @@ public void addInstructionSet(String expressName, InstructionSet set) throws Exception { synchronized (expressInstructionSetCache) { if (expressInstructionSetCache.containsKey(expressName)) { - throw new QLException("表达式定义重复:" + expressName); + throw new QLException("Duplicate expression definition:" + expressName); } expressInstructionSetCache.put(expressName, set); } @@ -39,13 +39,13 @@ public InstructionSet parseInstructionSet(String expressName, String expressString) throws Exception { InstructionSet parseResult = null; if (expressInstructionSetCache.containsKey(expressName)) { - throw new QLException("表达式定义重复:" + expressName); + throw new QLException("Duplicate expression definition:" + expressName); } synchronized (expressInstructionSetCache) { parseResult = this.creator.parseInstructionSet(expressString); parseResult.setName(expressName); parseResult.setGlobeName(expressName); - // 需要将函数和宏定义都提取出来 + // Need to extract both functions and macro definitions for (FunctionInstructionSet item : parseResult .getFunctionInstructionSets()) { this.addInstructionSet(item.name, item.instructionSet); diff --git a/src/main/java/com/ql/util/express/ExpressRemoteCacheRunner.java b/src/main/java/com/ql/util/express/ExpressRemoteCacheRunner.java index f2190f9ed..17f14d5ce 100644 --- a/src/main/java/com/ql/util/express/ExpressRemoteCacheRunner.java +++ b/src/main/java/com/ql/util/express/ExpressRemoteCacheRunner.java @@ -5,13 +5,13 @@ import org.apache.commons.logging.Log; /** - * 远程缓存对象 + * Remote cache object * @author tianqiao * */ public abstract class ExpressRemoteCacheRunner { - - + + public void loadCache(String expressName,String text){ InstructionSet instructionSet; @@ -23,37 +23,37 @@ public void loadCache(String expressName,String text){ cache.setInstructionSet(instructionSet); this.putCache(expressName, cache); } catch (Exception e) { - throw new RuntimeException("解析指令并缓存过程出现错误.",e); - } + throw new RuntimeException("An error occurred during the process of parsing instructions and caching.",e); + } } - - + + public Object execute(String name,IExpressContext context, List errorList, boolean isTrace,boolean isCatchException, Log aLog){ try { CacheObject cache = (CacheObject) this.getCache(name); if(cache==null){ - throw new RuntimeException("未获取到缓存对象."); + throw new RuntimeException("The cache object was not obtained."); } return getExpressRunner().execute(cache.getInstructionSet(), context, errorList, isTrace, isCatchException, aLog); } catch (Exception e) { - throw new RuntimeException("获取缓存信息,并且执行指令集出现错误.",e); - } + throw new RuntimeException("Obtain cache information, and an error occurred in the execution instruction set.",e); + } } - + /** - * 获取执行器ExpressRunner + * Get the executor ExpressRunner * @return */ public abstract ExpressRunner getExpressRunner(); /** - * 获取缓存对象 + * Get the cache object * @param key * @return */ public abstract Object getCache(String key); /** - * 放置缓存的对象 + * Place the cached object * @param key * @param object */ diff --git a/src/main/java/com/ql/util/express/ExpressRunner.java b/src/main/java/com/ql/util/express/ExpressRunner.java index acb34ed05..18cdb3ccf 100644 --- a/src/main/java/com/ql/util/express/ExpressRunner.java +++ b/src/main/java/com/ql/util/express/ExpressRunner.java @@ -23,56 +23,56 @@ import com.ql.util.express.instruction.OperateDataCacheImpl; /** - * 语法分析和计算的入口类 + * Entry class for grammatical analysis and calculation * @author xuannan * */ public class ExpressRunner { private static final Log log = LogFactory.getLog(ExpressRunner.class); - private static final String GLOBAL_DEFINE_NAME="全局定义"; + private static final String GLOBAL_DEFINE_NAME="Global Definition"; /** - * 是否输出所有的跟踪信息,同时还需要log级别是DEBUG级别 + * Whether to output all trace information, and the log level is also required to be DEBUG level */ private boolean isTrace = false; /** - * 是否使用逻辑短路特性增强质量的效率 + * Whether to use the logic short circuit feature to enhance the efficiency of quality */ private boolean isShortCircuit = true; /** - * 是否需要高精度计算 + * Do you need high-precision calculations */ private boolean isPrecise = false; /** - * 一段文本对应的指令集的缓存 + * Cache of instruction set corresponding to a piece of text */ - private Map expressInstructionSetCache = new HashMap(); + private Map expressInstructionSetCache = new HashMap(); /** - * 一段文本对应的规则的缓存 + * Cache of rules corresponding to a piece of text */ private Map ruleCache = new HashMap(); - private ExpressLoader loader; - private IExpressResourceLoader expressResourceLoader; - /** - * 语法定义的管理器 - */ + private ExpressLoader loader; + private IExpressResourceLoader expressResourceLoader; + /** + * Syntax definition manager + */ private NodeTypeManager manager; /** - * 操作符的管理器 + * Operator manager */ private OperatorFactory operatorManager; /** - * 语法分析器 + * Syntax analyzer */ - private ExpressParse parse ; + private ExpressParse parse; /** - * 缺省的Class查找的包管理器 + * The default package manager for Class lookup */ ExpressPackage rootExpressPackage = new ExpressPackage(null); @@ -90,8 +90,8 @@ public AppendingClassFieldManager getAppendingClassFieldManager() { private ThreadLocal m_OperateDataObjectCache = new ThreadLocal(){ protected IOperateDataCache initialValue() { - return new OperateDataCacheImpl(30); - } + return new OperateDataCacheImpl(30); + } }; public IOperateDataCache getOperateDataCache(){ return this.m_OperateDataObjectCache.get(); @@ -102,8 +102,8 @@ public ExpressRunner(){ } /** * - * @param aIsPrecise 是否需要高精度计算支持 - * @param aIstrace 是否跟踪执行指令的过程 + * @param aIsPrecise Do you need high-precision calculation support + * @param aIstrace whether to track the process of executing instructions */ public ExpressRunner(boolean aIsPrecise,boolean aIstrace){ this(aIsPrecise,aIstrace,new DefaultExpressResourceLoader(),null); @@ -113,9 +113,9 @@ public ExpressRunner(boolean aIsPrecise,boolean aIstrace,NodeTypeManager aManage } /** * - * @param aIsPrecise 是否需要高精度计算支持 - * @param aIstrace 是否跟踪执行指令的过程 - * @param aExpressResourceLoader 表达式的资源装载器 + * @param aIsPrecise Do you need high-precision calculation support + * @param aIstrace whether to track the process of executing instructions + * @param aExpressResourceLoader expression resource loader */ public ExpressRunner(boolean aIsPrecise,boolean aIstrace,IExpressResourceLoader aExpressResourceLoader,NodeTypeManager aManager){ this.isTrace = aIstrace; @@ -128,38 +128,38 @@ public ExpressRunner(boolean aIsPrecise,boolean aIstrace,IExpressResourceLoader } this.operatorManager = new OperatorFactory(this.isPrecise); this.loader = new ExpressLoader(this); - this.parse = new ExpressParse(manager,this.expressResourceLoader,this.isPrecise); + this.parse = new ExpressParse(manager,this.expressResourceLoader,this.isPrecise); rootExpressPackage.addPackage("java.lang"); rootExpressPackage.addPackage("java.util"); this.addSystemFunctions(); - this.addSystemOperators(); - } - - private void addSystemOperators() { - try { - this.addOperator("instanceof", new OperatorInstanceOf("instanceof")); - }catch (Exception e){ - throw new RuntimeException(e); - } - } - - public void addSystemFunctions(){ - this.addFunction("max", new OperatorMinMax("max")); - this.addFunction("min", new OperatorMinMax("min")); - this.addFunction("round", new OperatorRound("round")); - this.addFunction("print", new OperatorPrint("print")); - this.addFunction("println", new OperatorPrintln("println")); - } - - /** - * 获取语法定义的管理器 + this.addSystemOperators(); + } + + private void addSystemOperators() { + try { + this.addOperator("instanceof", new OperatorInstanceOf("instanceof")); + }catch (Exception e){ + throw new RuntimeException(e); + } + } + + public void addSystemFunctions(){ + this.addFunction("max", new OperatorMinMax("max")); + this.addFunction("min", new OperatorMinMax("min")); + this.addFunction("round", new OperatorRound("round")); + this.addFunction("print", new OperatorPrint("print")); + this.addFunction("println", new OperatorPrintln("println")); + } + + /** + * Get the grammar definition manager * @return */ public NodeTypeManager getNodeTypeManager(){ return this.manager; } /** - * 获取操作符号管理器 + * Get operation symbol manager * @return */ public OperatorFactory getOperatorFactory(){ @@ -169,18 +169,18 @@ public IExpressResourceLoader getExpressResourceLoader(){ return this.expressResourceLoader; } /** - * 添加宏定义 例如: macro 玄难 { abc(userinfo.userId);} - * @param macroName:玄难 + * Add macro definition For example: macro 玄难 {abc(userinfo.userId);} + * @param macroName: Xuan Nan * @param express :abc(userinfo.userId); * @throws Exception */ public void addMacro(String macroName,String express) throws Exception{ - String macroExpress = "macro " + macroName +" {" + express + "}"; + String macroExpress = "macro "+ macroName +" {" + express + "}"; this.loader.parseInstructionSet(GLOBAL_DEFINE_NAME,macroExpress); } /** - * 装载表达式,但不执行,例如一些宏定义,或者自定义函数 + * Load expressions, but do not execute them, such as some macro definitions or custom functions * @param groupName * @param express * @throws Exception @@ -191,18 +191,18 @@ public void loadMutilExpress(String groupName,String express) throws Exception{ } this.loader.parseInstructionSet(groupName,express); } - /** - * 装载文件中定义的Express - * @param expressName - * @throws Exception - */ + /** + * Express defined in the loading file + * @param expressName + * @throws Exception + */ public void loadExpress(String expressName) throws Exception { this.loader.loadExpress(expressName); } /** - * 添加函数定义 - * @param name 函数名称 - * @param op 对应的操作实现类 + * Add function definition + * @param name function name + * @param op corresponding operation implementation class */ public void addFunction(String name, OperatorBase op) { this.operatorManager.addOperator(name, op); @@ -210,11 +210,11 @@ public void addFunction(String name, OperatorBase op) { }; /** - * 添加函数定义扩展类的方法 + * Add function to define the method of the extended class * @param name * @param bindingClass - * @param op - */ + * @param op + */ public void addFunctionAndClassMethod(String name,ClassbindingClass, OperatorBase op) { this.addFunction(name,op); this.addClassMethod(name,bindingClass,op); @@ -222,7 +222,7 @@ public void addFunctionAndClassMethod(String name,ClassbindingClass, Operator }; /** - * 添加类的方法 + * Method of adding class * @param field * @param bindingClass * @param op @@ -233,7 +233,7 @@ public void addClassField(String field,ClassbindingClass,Operator op) } /** - * 添加类的方法 + * Method of adding class * @param field * @param bindingClass * @param returnType @@ -248,11 +248,11 @@ public void addClassField(String field,ClassbindingClass,ClassreturnType,O } /** - * 添加类的方法 + * Method of adding class * @param name * @param bindingClass - * @param op - */ + * @param op + */ public void addClassMethod(String name,ClassbindingClass,OperatorBase op) { if(this.appendingClassMethodManager==null){ @@ -261,174 +261,174 @@ public void addClassMethod(String name,ClassbindingClass,OperatorBase op) this.appendingClassMethodManager.addAppendingMethod(name, bindingClass, op); } /** - * 获取函数定义,通过函数定义可以拿到参数的说明信息 - * @param name 函数名称 + * Get the function definition, through the function definition you can get the parameter description information + * @param name function name * @return */ public OperatorBase getFunciton(String name){ return this.operatorManager.getOperator(name); } - /** - * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)" - * @param name 函数名称 - * @param aClassName 类名称 - * @param aFunctionName 类中的方法名称 - * @param aParameterClassTypes 方法的参数类型名称 - * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息 - * @throws Exception - */ + /** + * Add a function definition of a class, for example: Math.abs(double) is mapped to "take the absolute value (-5.0)" in the expression + * @param name function name + * @param aClassName class name + * @param aFunctionName method name in the class + * @param aParameterClassTypes method parameter type name + * @param errorInfo If the result of the function execution is false, the error message that needs to be output + * @throws Exception + */ public void addFunctionOfClassMethod(String name, String aClassName, - String aFunctionName, Class[] aParameterClassTypes, - String errorInfo) throws Exception { + String aFunctionName, Class[] aParameterClassTypes, + String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineClassFunction(name, aClassName, aFunctionName, aParameterClassTypes,null,null, errorInfo)); } - - /** - * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)" - * @param name 函数名称 - * @param aClass 类 - * @param aFunctionName 类中的方法名称 - * @param aParameterClassTypes 方法的参数类型名称 - * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息 - * @throws Exception - */ - public void addFunctionOfClassMethod(String name, Class aClass, - String aFunctionName, Class[] aParameterClassTypes, - String errorInfo) throws Exception { - this.addFunction(name, new OperatorSelfDefineClassFunction(name, - aClass, aFunctionName, aParameterClassTypes,null,null, errorInfo)); - - } - - /** - * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)" - * @param name 函数名称 - * @param aClassName 类名称 - * @param aFunctionName 类中的方法名称 - * @param aParameterClassTypes 方法的参数类型名称 - * @param aParameterDesc 方法的参数说明 - * @param aParameterAnnotation 方法的参数注解 - * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息 - * @throws Exception - */ + + /** + * Add a function definition of a class, for example: Math.abs(double) is mapped to "take the absolute value (-5.0)" in the expression + * @param name function name + * @param aClass class + * @param aFunctionName method name in the class + * @param aParameterClassTypes method parameter type name + * @param errorInfo If the result of the function execution is false, the error message that needs to be output + * @throws Exception + */ + public void addFunctionOfClassMethod(String name, Class aClass, + String aFunctionName, Class[] aParameterClassTypes, + String errorInfo) throws Exception { + this.addFunction(name, new OperatorSelfDefineClassFunction(name, + aClass, aFunctionName, aParameterClassTypes,null,null, errorInfo)); + + } + + /** + * Add a function definition of a class, for example: Math.abs(double) is mapped to "take absolute value (-5.0)" in the expression + * @param name function name + * @param aClassName class name + * @param aFunctionName method name in the class + * @param aParameterClassTypes method parameter type name + * @param aParameterDesc method parameter description + * @param aParameterAnnotation method parameter annotation + * @param errorInfo If the result of the function execution is false, the error message that needs to be output + * @throws Exception + */ public void addFunctionOfClassMethod(String name, String aClassName, - String aFunctionName, Class[] aParameterClassTypes, - String[] aParameterDesc,String[] aParameterAnnotation, - String errorInfo) throws Exception { + String aFunctionName, Class[] aParameterClassTypes, + String[] aParameterDesc,String[] aParameterAnnotation, + String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineClassFunction(name, aClassName, aFunctionName, aParameterClassTypes,aParameterDesc,aParameterAnnotation, errorInfo)); } - /** - * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)" - * @param name 函数名称 - * @param aClassName 类名称 - * @param aFunctionName 类中的方法名称 - * @param aParameterTypes 方法的参数类型名称 - * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息 - * @throws Exception - */ + /** + * Add a function definition of a class, for example: Math.abs(double) is mapped to "take the absolute value (-5.0)" in the expression + * @param name function name + * @param aClassName class name + * @param aFunctionName method name in the class + * @param aParameterTypes method parameter type name + * @param errorInfo If the result of the function execution is false, the error message that needs to be output + * @throws Exception + */ public void addFunctionOfClassMethod(String name, String aClassName, - String aFunctionName, String[] aParameterTypes, String errorInfo) + String aFunctionName, String[] aParameterTypes, String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineClassFunction(name, aClassName, aFunctionName, aParameterTypes, null,null,errorInfo)); } - /** - * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)" - * @param name 函数名称 - * @param aClassName 类名称 - * @param aFunctionName 类中的方法名称 - * @param aParameterTypes 方法的参数类型名称 - * @param aParameterDesc 方法的参数说明 - * @param aParameterAnnotation 方法的参数注解 - * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息 - * @throws Exception - */ + /** + * Add a function definition of a class, for example: Math.abs(double) is mapped to "take the absolute value (-5.0)" in the expression + * @param name function name + * @param aClassName class name + * @param aFunctionName method name in the class + * @param aParameterTypes method parameter type name + * @param aParameterDesc method parameter description + * @param aParameterAnnotation method parameter annotation + * @param errorInfo If the result of the function execution is false, the error message that needs to be output + * @throws Exception + */ public void addFunctionOfClassMethod(String name, String aClassName, - String aFunctionName, String[] aParameterTypes, - String[] aParameterDesc,String[] aParameterAnnotation, - String errorInfo) + String aFunctionName, String[] aParameterTypes, + String[] aParameterDesc,String[] aParameterAnnotation, + String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineClassFunction(name, aClassName, aFunctionName, aParameterTypes, aParameterDesc,aParameterAnnotation,errorInfo)); } - /** - * 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数 - * @param name - * @param aServiceObject - * @param aFunctionName - * @param aParameterClassTypes - * @param errorInfo - * @throws Exception - */ + /** + * Used to convert a user-defined object (such as a Spring object) method into an expression calculation function + * @param name + * @param aServiceObject + * @param aFunctionName + * @param aParameterClassTypes + * @param errorInfo + * @throws Exception + */ public void addFunctionOfServiceMethod(String name, Object aServiceObject, - String aFunctionName, Class[] aParameterClassTypes, - String errorInfo) throws Exception { + String aFunctionName, Class[] aParameterClassTypes, + String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineServiceFunction(name, aServiceObject, aFunctionName, aParameterClassTypes,null,null, errorInfo)); } - /** - * 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数 - * @param name - * @param aServiceObject - * @param aFunctionName - * @param aParameterClassTypes - * @param aParameterDesc 方法的参数说明 - * @param aParameterAnnotation 方法的参数注解 - * @param errorInfo - * @throws Exception - */ + /** + * Used to convert a user-defined object (such as a Spring object) method into an expression calculation function + * @param name + * @param aServiceObject + * @param aFunctionName + * @param aParameterClassTypes + * @param aParameterDesc method parameter description + * @param aParameterAnnotation method parameter annotation + * @param errorInfo + * @throws Exception + */ public void addFunctionOfServiceMethod(String name, Object aServiceObject, - String aFunctionName, Class[] aParameterClassTypes, - String[] aParameterDesc,String[] aParameterAnnotation, - String errorInfo) throws Exception { + String aFunctionName, Class[] aParameterClassTypes, + String[] aParameterDesc,String[] aParameterAnnotation, + String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineServiceFunction(name, aServiceObject, aFunctionName, aParameterClassTypes,aParameterDesc,aParameterAnnotation, errorInfo)); } - /** - * 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数 - * @param name - * @param aServiceObject - * @param aFunctionName - * @param aParameterTypes - * @param errorInfo - * @throws Exception - */ + /** + * Used to convert a user-defined object (such as a Spring object) method into an expression calculation function + * @param name + * @param aServiceObject + * @param aFunctionName + * @param aParameterTypes + * @param errorInfo + * @throws Exception + */ public void addFunctionOfServiceMethod(String name, Object aServiceObject, - String aFunctionName, String[] aParameterTypes, String errorInfo) + String aFunctionName, String[] aParameterTypes, String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineServiceFunction(name, aServiceObject, aFunctionName, aParameterTypes,null,null, errorInfo)); } public void addFunctionOfServiceMethod(String name, Object aServiceObject, - String aFunctionName, String[] aParameterTypes, - String[] aParameterDesc,String[] aParameterAnnotation, - String errorInfo) + String aFunctionName, String[] aParameterTypes, + String[] aParameterDesc,String[] aParameterAnnotation, + String errorInfo) throws Exception { this.addFunction(name, new OperatorSelfDefineServiceFunction(name, aServiceObject, aFunctionName, aParameterTypes,aParameterDesc,aParameterAnnotation, errorInfo)); } /** - * 添加操作符号,此操作符号的优先级与 "*"相同,语法形式也是 data name data + * Add operation symbol, the priority of this operation symbol is the same as "*", the syntax form is also data name data * @param name * @param op * @throws Exception */ public void addOperator(String name,Operator op) throws Exception { - this.addOperator(name, "*", op); + this.addOperator(name, "*", op); } /** - * 添加操作符号,此操作符号与给定的参照操作符号在优先级别和语法形式上一致 - * @param name 操作符号名称 - * @param aRefOpername 参照的操作符号,例如 "+","--"等 + * Add operation symbol, this operation symbol is consistent with the given reference operation symbol in priority and grammatical form + * @param name operation symbol name + * @param aRefOpername refers to the operation symbol, such as "+", "--", etc. * @param op * @throws Exception */ @@ -438,19 +438,19 @@ public void addOperator(String name,String aRefOpername,Operator op) throws Exce } /** - * 添加操作符和关键字的别名,同时对操作符可以指定错误信息。 - * 例如:addOperatorWithAlias("加","+",null) + * Add aliases for operators and keywords, and specify error messages for operators. + * For example: addOperatorWithAlias("加","+",null) * @param keyWordName * @param realKeyWordName * @param errorInfo * @throws Exception */ public void addOperatorWithAlias(String keyWordName, String realKeyWordName, - String errorInfo) throws Exception { + String errorInfo) throws Exception { if(errorInfo != null && errorInfo.trim().length() == 0){ errorInfo = null; } - //添加函数别名 +//Add function alias if(this.manager.isFunction(realKeyWordName)){ this.manager.addFunctionName(keyWordName); this.operatorManager.addOperatorWithAlias(keyWordName, realKeyWordName, errorInfo); @@ -458,14 +458,14 @@ public void addOperatorWithAlias(String keyWordName, String realKeyWordName, } NodeType realNodeType = this.manager.findNodeType(realKeyWordName); if(realNodeType == null){ - throw new QLException("关键字:" + realKeyWordName +"不存在"); + throw new QLException("Keyword:" + realKeyWordName + "does not exist"); } boolean isExist = this.operatorManager.isExistOperator(realNodeType.getName()); - if(isExist == false && errorInfo != null){ - throw new QLException("关键字:" + realKeyWordName +"是通过指令来实现的,不能设置错误的提示信息,errorInfo 必须是 null"); + if(isExist == false && errorInfo != null){ + throw new QLException("Keyword:" + realKeyWordName +" is implemented by instructions, you cannot set error prompt information, errorInfo must be null"); } if(isExist == false || errorInfo == null){ - //不需要新增操作符号,只需要建立一个关键子即可 +//No need to add operation symbols, just create a key sub this.manager.addOperatorWithRealNodeType(keyWordName, realNodeType.getName()); }else{ this.manager.addOperatorWithLevelOfReference(keyWordName, realNodeType.getName()); @@ -473,26 +473,26 @@ public void addOperatorWithAlias(String keyWordName, String realKeyWordName, } } /** - * 替换操作符处理 + * Replacement operator processing * @param name */ - public OperatorBase replaceOperator(String name,OperatorBase op){ - return this.operatorManager.replaceOperator(name, op); - } + public OperatorBase replaceOperator(String name,OperatorBase op){ + return this.operatorManager.replaceOperator(name, op); + } public ExpressPackage getRootExpressPackage(){ return this.rootExpressPackage; } - /** - * 清除缓存 - */ + /** + * clear cache + */ public void clearExpressCache() { - synchronized (expressInstructionSetCache) { - this.expressInstructionSetCache.clear(); - } + synchronized (expressInstructionSetCache) { + this.expressInstructionSetCache.clear(); + } } /** - * 根据表达式的名称进行执行 + * Execute according to the name of the expression * @param name * @param context * @param errorList @@ -503,15 +503,15 @@ public void clearExpressCache() { * @throws Exception */ public Object executeByExpressName(String name,IExpressContext context, List errorList, - boolean isTrace,boolean isCatchException, Log aLog) throws Exception { - return InstructionSetRunner.executeOuter(this,this.loader.getInstructionSet(name),this.loader,context, errorList, - isTrace,isCatchException,aLog,false); + boolean isTrace,boolean isCatchException, Log aLog) throws Exception { + return InstructionSetRunner.executeOuter(this,this.loader.getInstructionSet(name),this.loader,context, errorList, + isTrace,isCatchException,aLog,false); } /** - * 执行指令集(兼容老接口,请不要自己管理指令缓存,直接使用execute(InstructionSet instructionSets,....... ) - * 清理缓存可以使用clearExpressCache()函数 + * Execute instruction set (compatible with the old interface, please do not manage the instruction cache yourself, use execute(InstructionSet instructionSets,...) directly + * To clear the cache, use the clearExpressCache() function * @param instructionSets * @param context * @param errorList @@ -524,12 +524,12 @@ public Object executeByExpressName(String name,IExpressContext co @Deprecated public Object execute(InstructionSet[] instructionSets,IExpressContext context, List errorList, boolean isTrace,boolean isCatchException, Log aLog) throws Exception { - return InstructionSetRunner.executeOuter(this,instructionSets[0],this.loader,context, errorList, + return InstructionSetRunner.executeOuter(this,instructionSets[0],this.loader,context, errorList, isTrace,isCatchException,aLog,false); } /** - * 执行指令集 + * Execute instruction set * @param instructionSets * @param context * @param errorList @@ -540,24 +540,24 @@ public Object execute(InstructionSet[] instructionSets,IExpressContext context, List errorList, - boolean isTrace,boolean isCatchException, Log aLog) throws Exception { - return InstructionSetRunner.executeOuter(this,instructionSets,this.loader,context, errorList, - isTrace,isCatchException,aLog,false); - } - /** - * 执行一段文本 - * @param expressString 程序文本 - * @param context 执行上下文 - * @param errorList 输出的错误信息List - * @param isCache 是否使用Cache中的指令集 - * @param isTrace 是否输出详细的执行指令信息 - * @param timeoutMillis 超时毫秒时间 + boolean isTrace,boolean isCatchException, Log aLog) throws Exception { + return InstructionSetRunner.executeOuter(this,instructionSets,this.loader,context, errorList, + isTrace,isCatchException,aLog,false); + } + /** + * Execute a text + * @param expressString program text + * @param context execution context + * @param errorList List of error messages output + * @param isCache Whether to use the instruction set in Cache + * @param isTrace Whether to output detailed execution instruction information + * @param timeoutMillis timeout milliseconds * @return * @throws Exception */ public Object execute(String expressString, IExpressContext context, - List errorList, boolean isCache, boolean isTrace,long timeoutMillis) throws Exception { - //设置超时毫秒时间 + List errorList, boolean isCache, boolean isTrace,long timeoutMillis) throws Exception { +//Set the timeout in milliseconds QLExpressTimer.setTimer(timeoutMillis); try { return this.execute(expressString, context, errorList, isCache, isTrace, null); @@ -567,12 +567,12 @@ public Object execute(String expressString, IExpressContext conte } /** - * 执行一段文本 - * @param expressString 程序文本 - * @param context 执行上下文 - * @param errorList 输出的错误信息List - * @param isCache 是否使用Cache中的指令集 - * @param isTrace 是否输出详细的执行指令信息 + * Execute a text + * @param expressString program text + * @param context execution context + * @param errorList List of error messages output + * @param isCache Whether to use the instruction set in Cache + * @param isTrace Whether to output detailed execution instruction information * @return * @throws Exception */ @@ -581,18 +581,18 @@ public Object execute(String expressString, IExpressContext conte return this.execute(expressString, context, errorList, isCache, isTrace, null); } /** - * 执行一段文本 - * @param expressString 程序文本 - * @param context 执行上下文 - * @param errorList 输出的错误信息List - * @param isCache 是否使用Cache中的指令集 - * @param isTrace 是否输出详细的执行指令信息 - * @param aLog 输出的log + * Execute a text + * @param expressString program text + * @param context execution context + * @param errorList List of error messages output + * @param isCache Whether to use the instruction set in Cache + * @param isTrace Whether to output detailed execution instruction information + * @param aLog output log * @return * @throws Exception */ public Object execute(String expressString, IExpressContext context, - List errorList, boolean isCache, boolean isTrace, Log aLog) + List errorList, boolean isCache, boolean isTrace, Log aLog) throws Exception { InstructionSet parseResult = null; if (isCache == true) { @@ -610,8 +610,8 @@ public Object execute(String expressString, IExpressContext conte } else { parseResult = this.parseInstructionSet(expressString); } - return InstructionSetRunner.executeOuter(this,parseResult,this.loader,context, errorList, - isTrace,false,aLog,false); + return InstructionSetRunner.executeOuter(this,parseResult,this.loader,context, errorList, + isTrace,false,aLog,false); } public RuleResult executeRule(String expressString, IExpressContext context, boolean isCache, boolean isTrace) @@ -635,54 +635,54 @@ public RuleResult executeRule(String expressString, IExpressContext selfDefineClass = new HashMap (); - for(ExportItem item : this.loader.getExportInfo()){ + for(ExportItem item: this.loader.getExportInfo()){ if(item.getType().equals(InstructionSet.TYPE_CLASS)){ selfDefineClass.put(item.getName(), item.getName()); } } -// 分成两句话执行,用来保存中间的words结果 -// ExpressNode root = this.parse.parse(this.rootExpressPackage,text, isTrace,selfDefineClass); +// Divide into two sentences to execute to save the words results +// ExpressNode root = this.parse.parse(this.rootExpressPackage,text, isTrace,selfDefineClass); Word[] words = this.parse.splitWords(rootExpressPackage,text,isTrace,selfDefineClass); - ExpressNode root = this.parse.parse(rootExpressPackage,words,text,isTrace,selfDefineClass); + ExpressNode root = this.parse.parse(rootExpressPackage,words,text,isTrace,selfDefineClass); Rule rule = RuleManager.createRule(root,words); rule.setCode(ruleCode); rule.setName(ruleName); return rule; } - - public Condition parseContition(String text) - throws Exception { - - Map selfDefineClass = new HashMap (); - for(ExportItem item : this.loader.getExportInfo()){ - if(item.getType().equals(InstructionSet.TYPE_CLASS)){ - selfDefineClass.put(item.getName(), item.getName()); - } - } - - Word[] words = this.parse.splitWords(rootExpressPackage,text,isTrace,selfDefineClass); - ExpressNode root = this.parse.parse(rootExpressPackage,words,text,isTrace,selfDefineClass); - return RuleManager.createCondition(root,words); - } - - /** - * 解析一段文本,生成指令集合 + + public Condition parseContition(String text) + throws Exception { + + Map selfDefineClass = new HashMap (); + for(ExportItem item: this.loader.getExportInfo()){ + if(item.getType().equals(InstructionSet.TYPE_CLASS)){ + selfDefineClass.put(item.getName(), item.getName()); + } + } + + Word[] words = this.parse.splitWords(rootExpressPackage,text,isTrace,selfDefineClass); + ExpressNode root = this.parse.parse(rootExpressPackage,words,text,isTrace,selfDefineClass); + return RuleManager.createCondition(root,words); + } + + /** + * Parse a piece of text and generate a set of instructions * @param text * @return * @throws Exception @@ -691,7 +691,7 @@ public InstructionSet parseInstructionSet(String text) throws Exception { try { Map selfDefineClass = new HashMap(); - for (ExportItem item : this.loader.getExportInfo()) { + for (ExportItem item: this.loader.getExportInfo()) { if (item.getType().equals(InstructionSet.TYPE_CLASS)) { selfDefineClass.put(item.getName(), item.getName()); } @@ -706,11 +706,11 @@ public InstructionSet parseInstructionSet(String text) }catch (QLCompileException e){ throw e; }catch (Exception e){ - throw new QLCompileException("编译异常:\n"+text,e); + throw new QLCompileException("Compile exception:\n"+text,e); } } /** - * 输出全局定义信息 + * Output global definition information * @return */ public ExportItem[] getExportInfo(){ @@ -718,7 +718,7 @@ public ExportItem[] getExportInfo(){ } /** - * 优先从本地指令集缓存获取指令集,没有的话生成并且缓存在本地 + * First obtain the instruction set from the local instruction set cache, if not, generate it and cache it locally * @param expressString * @return * @throws Exception @@ -750,21 +750,21 @@ public void createInstructionSet(ExpressNode root, InstructionSet result) throws Exception { Stack forStack = new Stack(); createInstructionSetPrivate(result, forStack, root, true); - if (forStack.size() > 0) { - throw new QLCompileException("For处理错误"); + if (forStack.size()> 0) { + throw new QLCompileException("For processing error"); } } public boolean createInstructionSetPrivate(InstructionSet result, - Stack forStack, ExpressNode node, - boolean isRoot) throws Exception { + Stack forStack, ExpressNode node, + boolean isRoot) throws Exception { InstructionFactory factory = InstructionFactory .getInstructionFactory(node.getInstructionFactory()); boolean hasLocalVar = factory.createInstruction(this,result, forStack, node, isRoot); return hasLocalVar; } /** - * 获取一个表达式需要的外部变量名称列表 + * Get a list of external variable names required by an expression * @param express * @return * @throws Exception @@ -784,57 +784,57 @@ public boolean isShortCircuit() { public void setShortCircuit(boolean isShortCircuit) { this.isShortCircuit = isShortCircuit; } - - /** - * 是否忽略charset类型的数据,而识别为string,比如'a' -》 "a" - * 默认为不忽略,正常识别为String - */ - public boolean isIgnoreConstChar() { - return this.parse.isIgnoreConstChar(); - } - public void setIgnoreConstChar(boolean ignoreConstChar) { - this.parse.setIgnoreConstChar(ignoreConstChar); - } - - /** - * 提供简答的语法检查,保证可以在运行期本地环境编译成指令 - * @param text - * @return - */ - public boolean checkSyntax(String text) - { - return checkSyntax(text,false,null); - } - - /** - * 提供复杂的语法检查,(比如检查自定义的java类),不保证运行期在本地环境可以编译成指令 - * @param text - * @param mockRemoteJavaClass - * @param remoteJavaClassNames - * @return - */ - public boolean checkSyntax(String text,boolean mockRemoteJavaClass,List remoteJavaClassNames){ - - try { - Map selfDefineClass = new HashMap(); - for (ExportItem item : this.loader.getExportInfo()) { - if (item.getType().equals(InstructionSet.TYPE_CLASS)) { - selfDefineClass.put(item.getName(), item.getName()); - } - } - Word[] words = this.parse.splitWords(rootExpressPackage,text,isTrace,selfDefineClass); - ExpressNode root = this.parse.parse(this.rootExpressPackage, words,text, isTrace, selfDefineClass,mockRemoteJavaClass); - InstructionSet result = createInstructionSet(root, "main"); - if (this.isTrace && log.isDebugEnabled()) { - log.debug(result); - } - if(mockRemoteJavaClass && remoteJavaClassNames!=null) { - remoteJavaClassNames.addAll(Arrays.asList(result.getVirClasses())); - } - return true; - }catch (Exception e){ - log.error("checkSyntax has Exception",e); - return false; - } - } + + /** + * Whether to ignore the charset type data and recognize it as a string, such as'a'-"a" + * The default is not to ignore, normally recognized as String + */ + public boolean isIgnoreConstChar() { + return this.parse.isIgnoreConstChar(); + } + public void setIgnoreConstChar(boolean ignoreConstChar) { + this.parse.setIgnoreConstChar(ignoreConstChar); + } + + /** + * Provide short-answer syntax check to ensure that the local environment can be compiled into instructions during runtime + * @param text + * @return + */ + public boolean checkSyntax(String text) + { + return checkSyntax(text,false,null); + } + + /** + * Provides complex syntax checking, (such as checking custom java classes), does not guarantee that the runtime can be compiled into instructions in the local environment + * @param text + * @param mockRemoteJavaClass + * @param remoteJavaClassNames + * @return + */ + public boolean checkSyntax(String text,boolean mockRemoteJavaClass,List remoteJavaClassNames){ + + try { + Map selfDefineClass = new HashMap(); + for (ExportItem item: this.loader.getExportInfo()) { + if (item.getType().equals(InstructionSet.TYPE_CLASS)) { + selfDefineClass.put(item.getName(), item.getName()); + } + } + Word[] words = this.parse.splitWords(rootExpressPackage,text,isTrace,selfDefineClass); + ExpressNode root = this.parse.parse(this.rootExpressPackage, words,text, isTrace, selfDefineClass,mockRemoteJavaClass); + InstructionSet result = createInstructionSet(root, "main"); + if (this.isTrace && log.isDebugEnabled()) { + log.debug(result); + } + if(mockRemoteJavaClass && remoteJavaClassNames!=null) { + remoteJavaClassNames.addAll(Arrays.asList(result.getVirClasses())); + } + return true; + }catch (Exception e){ + log.error("checkSyntax has Exception",e); + return false; + } + } } diff --git a/src/main/java/com/ql/util/express/ExpressUtil.java b/src/main/java/com/ql/util/express/ExpressUtil.java index aa972da04..f2aac2daa 100644 --- a/src/main/java/com/ql/util/express/ExpressUtil.java +++ b/src/main/java/com/ql/util/express/ExpressUtil.java @@ -15,7 +15,7 @@ /** - * 表达式工具类 + * Expression tools * * @author qhlhl2010@gmail.com * @@ -48,7 +48,7 @@ public class ExpressUtil { public static Map methodCache = new ConcurrentHashMap(); public static Class[][] classMatchs =new Class[][]{ - //原始数据类型 + //Primitive data type {BigDecimal.class,double.class},{BigDecimal.class,float.class},{BigDecimal.class,long.class},{BigDecimal.class,int.class}, {BigDecimal.class,short.class},{BigDecimal.class,byte.class}, {double.class,float.class},{double.class,long.class},{double.class,int.class}, {double.class,short.class},{double.class,byte.class},{double.class,BigDecimal.class}, {float.class,long.class}, {float.class,int.class}, {float.class,short.class},{float.class,byte.class},{float.class,BigDecimal.class}, @@ -136,7 +136,7 @@ else if (source == Float.class) else if (source == Double.class) source = double.class; } - if (target == source)// 转换后需要在判断一下 + if (target == source)// Need to judge after conversion return true; for (int i = 0; i < classMatchs.length; i++) { @@ -201,7 +201,7 @@ public static int findMostSpecificSignature(Class[] idealMatch, Class[] bestMatch = null; int bestMatchIndex = -1; - for (int i = candidates.length - 1; i >= 0; i--) {// 先从基类开始查找 + for (int i = candidates.length - 1; i >= 0; i--) {// Start looking up from the base class Class[] targetMatch = candidates[i]; if (ExpressUtil.isSignatureAssignable(idealMatch, targetMatch) && ((bestMatch == null) || ExpressUtil @@ -496,8 +496,8 @@ public static Class loadClass(String name) throws ClassNotFoundException { } /** - * 替换字符串中的参数 replaceString("$1强化$2实施$2",new String[]{"qq","ff"}) - * ="qq 强化 ff 实施 ff" + * Replace the parameters in the string replaceString("$1 strengthens $2 implements $2",new String[]{"qq","ff"}) + * ="qq strengthen ff implement ff" * * @param str * @param parameters @@ -515,7 +515,7 @@ public static String replaceString(String str, Object[] parameters) while (m.find()) { int index = Integer.parseInt(m.group().substring(1)) - 1; if (index < 0 || index >= parameters.length) { - throw new QLException("设置的参数位置$" + (index + 1) + "超过了范围 " + throw new QLException("Set parameter position$" + (index + 1) + ";Out of range " + parameters.length); } m.appendReplacement(sb, " " + parameters[index].toString() + " "); @@ -585,7 +585,7 @@ public static void setProperty(Object bean, Object name, Object value) { PropertyUtils.setProperty(bean, name.toString(),ExpressUtil.castObject(value, filedClass, false)); } } catch (Exception e) { - throw new RuntimeException("不能访问" + bean + "的property:" + name,e); + throw new RuntimeException("Can not access" + bean + "of property:" + name,e); } } @@ -599,7 +599,7 @@ public static Object[] transferArray(Object[] values,Class[] types){ * * @param value * @param type - * @param isForce 是否强制转换 + * @param isForce Whether to force conversion * @return */ public static Object castObject(Object value, Class type,boolean isForce){ @@ -612,7 +612,7 @@ public static Object castObject(Object value, Class type,boolean isForce){ && (type.isPrimitive() || Number.class.isAssignableFrom(type))) { return OperatorOfNumber.transfer((Number)value, type, isForce); }else if(type.isArray() && value.getClass().isArray()) { - //需要对元素做兼容性,如果value的元素全部为null并且和声明的不一致,转化为所声明的类型 + //Compatibility of elements is required. If the elements of value are all null and are inconsistent with the declared, they are converted to the declared type Class valueType = value.getClass().getComponentType(); Class declareType = type.getComponentType(); if(declareType!=valueType){ @@ -637,7 +637,7 @@ public static Object castObject(Object value, Class type,boolean isForce){ public static void main(String[] args) throws Exception { - System.out.println(replaceString("$1强化$2实施$2", new String[] { "qq", + System.out.println(replaceString("$1 strengthened $2 implemented $2", new String[] { "qq", "ff" })); System.out.println(Number.class.isAssignableFrom(Long.class)); Object obj = castObject(Double.valueOf(1d),Double.class,false); diff --git a/src/main/java/com/ql/util/express/IExpressContext.java b/src/main/java/com/ql/util/express/IExpressContext.java index f246fc46d..2f11a36af 100644 --- a/src/main/java/com/ql/util/express/IExpressContext.java +++ b/src/main/java/com/ql/util/express/IExpressContext.java @@ -1,21 +1,21 @@ package com.ql.util.express; /** - * 表达式计算的数据注入接口 + * Data injection interface for expression calculation * @author qhlhl2010@gmail.com * */ public interface IExpressContext { /** - * 根据名称从属性列表中提取属性值。如果表达式中用到了Spring的对象,也是通过此方法获取 - * @param key 属性名称 + * Extract the attribute value from the attribute list based on the name. If the Spring object is used in the expression, it is also obtained through this method + * @param key Attribute name * @return */ public V get(Object key); /** - * 表达式计算的结果可以设置回调用系统,例如 userId = 3 + 4 - * @param name 属性名称 - * @param object 属性值 + * The result of expression calculation can be set back to the calling system, for example userId = 3 + 4 + * @param name Attribute name + * @param object Attribute value */ public V put(K name, V object); } diff --git a/src/main/java/com/ql/util/express/IExpressResourceLoader.java b/src/main/java/com/ql/util/express/IExpressResourceLoader.java index 0b53c00a4..c884f4016 100644 --- a/src/main/java/com/ql/util/express/IExpressResourceLoader.java +++ b/src/main/java/com/ql/util/express/IExpressResourceLoader.java @@ -1,13 +1,13 @@ package com.ql.util.express; /** - * 加载表达式资源接口 + * Load expression resource interface * @author xuannan * */ public interface IExpressResourceLoader { /** - * 根据表达式名称获取表达式的内容 + * Get the content of the expression based on the expression name * @param expressName * @return * @throws Exception diff --git a/src/main/java/com/ql/util/express/InstructionSet.java b/src/main/java/com/ql/util/express/InstructionSet.java index 9cc8f2a3c..6a175256d 100644 --- a/src/main/java/com/ql/util/express/InstructionSet.java +++ b/src/main/java/com/ql/util/express/InstructionSet.java @@ -21,7 +21,7 @@ /** - * 表达式执行编译后形成的指令集合 + * The instruction set formed after the expression is executed and compiled * @author qhlhl2010@gmail.com * */ @@ -48,18 +48,18 @@ public class InstructionSet implements Serializable{ private String globeName; /** - * 指令 + * instruction */ private Instruction[] instructionList = new Instruction[0]; /** - * 函数和宏定义 + * Function and macro definition */ private Map functionDefine = new HashMap(); //为了增加性能,开始的时候缓存为数组 private Map cacheFunctionSet = null; private List exportVar = new ArrayList(); /** - * 函数参数定义 + * Function parameter definition */ private List parameterList = new ArrayList(); @@ -108,7 +108,7 @@ public String[] getOutAttrNames() throws Exception{ } } - //剔除本地变量定义和别名定义 + //Eliminate local variable definitions and alias definitions for (int i = 0; i < instructionList.length; i++) { Instruction instruction = instructionList[i]; if (instruction instanceof InstructionOperator) { @@ -134,7 +134,7 @@ public String[] getOutAttrNames() throws Exception{ /** - * 添加指令,为了提高运行期的效率,指令集用数组存储 + * Add instructions, in order to improve the efficiency of the runtime, the instruction set is stored in an array * @param item * @return */ @@ -145,7 +145,7 @@ private void addArrayItem(Instruction item){ this.instructionList = newArray; } /** - * 插入数据 + * Insert data * @param aPoint * @param item */ @@ -162,7 +162,7 @@ private void insertArrayItem(int aPoint,Instruction item){ * @param environmen * @param context * @param errorList - * @param isReturnLastData 是否最后的结果,主要是在执行宏定义的时候需要 + * @param isReturnLastData Whether the final result is mainly needed when executing the macro definition * @param aLog * @return * @throws Exception @@ -171,7 +171,7 @@ public CallResult excute(RunEnvironment environmen,InstructionSetContext context List errorList,boolean isReturnLastData,Log aLog) throws Exception { - //将函数export到上下文中,这儿就是重入也没有关系,不需要考虑并发 + //Export the function to the context, it does not matter if it is reentrant here, no need to consider concurrency if(cacheFunctionSet == null){ Map tempMap = new HashMap(); for(FunctionInstructionSet s : this.functionDefine.values()){ @@ -183,7 +183,7 @@ public CallResult excute(RunEnvironment environmen,InstructionSetContext context context.addSymbol(cacheFunctionSet); this.executeInnerOrigiInstruction(environmen, errorList, aLog); - if (environmen.isExit() == false) {// 是在执行完所有的指令后结束的代码 + if (environmen.isExit() == false) {// Is the code that ends after executing all the instructions if (environmen.getDataStackSize() > 0) { OperateData tmpObject = environmen.pop(); if (tmpObject == null) { @@ -202,7 +202,7 @@ public CallResult excute(RunEnvironment environmen,InstructionSetContext context } } if (environmen.getDataStackSize() > 1) { - throw new QLException("在表达式执行完毕后,堆栈中还存在多个数据"); + throw new QLException("After the expression is executed, there are multiple data in the stack "); } CallResult result = OperateDataCacheManager.fetchCallResult(environmen.getReturnValue(), environmen.isExit()); return result; @@ -218,8 +218,8 @@ public void executeInnerOrigiInstruction(RunEnvironment environmen,List } } catch (Exception e) { if (printInstructionError) { - log.error("当前ProgramPoint = " + environmen.programPoint); - log.error("当前指令" + instruction); + log.error("Current ProgramPoint = " + environmen.programPoint); + log.error("Current instruction =" + instruction); log.error(e); } throw e; @@ -299,7 +299,7 @@ public String toString() { public String toString(int level) { try { StringBuffer buffer = new StringBuffer(); - // 输出宏定义 + //Output macro definition for (FunctionInstructionSet set : this.functionDefine.values()) { appendSpace(buffer,level); buffer.append(set.type + ":" + set.name).append("("); diff --git a/src/main/java/com/ql/util/express/InstructionSetContext.java b/src/main/java/com/ql/util/express/InstructionSetContext.java index 7e476cae6..bdb3ca758 100644 --- a/src/main/java/com/ql/util/express/InstructionSetContext.java +++ b/src/main/java/com/ql/util/express/InstructionSetContext.java @@ -8,14 +8,14 @@ public class InstructionSetContext implements IExpressContext { /* - * 没有知道数据类型的变量定义是否传递到最外层的Context + * It is not known whether the variable definition of the data type is passed to the outermost Context */ private boolean isExpandToParent = true; private IExpressContext parent = null; private Map content; /** - * 符号表 + * Symbol table */ private Map symbolTable =new HashMap(); @@ -58,7 +58,7 @@ public void exportSymbol(String varName,Object aliasNameObject) throws Exception } public void addSymbol(String varName,Object aliasNameObject) throws Exception{ if(this.symbolTable.containsKey(varName)){ - throw new QLException("变量" + varName + "已经存在,不能重复定义,也不能再从函数内部 exprot "); + throw new QLException("Variable:" + varName + " already exists, cannot be re-defined, nor can export from within the function "); } this.symbolTable.put(varName,aliasNameObject); } @@ -130,7 +130,7 @@ public Object put(String key, Object value){ }else if(this.parent != null){ return this.parent.put(key,value); }else{ - throw new RuntimeException("没有定义局部变量:" + key +",而且没有全局上下文"); + throw new RuntimeException("No local variables defined:" + key +",with no global context"); } } diff --git a/src/main/java/com/ql/util/express/InstructionSetRunner.java b/src/main/java/com/ql/util/express/InstructionSetRunner.java index 97bc5f947..87d2f7f31 100644 --- a/src/main/java/com/ql/util/express/InstructionSetRunner.java +++ b/src/main/java/com/ql/util/express/InstructionSetRunner.java @@ -16,7 +16,7 @@ public static Object executeOuter(ExpressRunner runner,InstructionSet sets,Expre Log aLog,boolean isSupportDynamicFieldName) throws Exception{ try{ - //开始计时 + //start the timer QLExpressTimer.startTimer(); OperateDataCacheManager.push(runner); @@ -27,7 +27,7 @@ public static Object executeOuter(ExpressRunner runner,InstructionSet sets,Expre } /** - * 批量执行指令集合,指令集间可以共享 变量和函数 + * Batch execution of instruction sets, variables and functions can be shared between instruction sets * @param runner * @param sets * @param loader diff --git a/src/main/java/com/ql/util/express/LocalExpressCacheRunner.java b/src/main/java/com/ql/util/express/LocalExpressCacheRunner.java index fdbd03554..307c66bb1 100644 --- a/src/main/java/com/ql/util/express/LocalExpressCacheRunner.java +++ b/src/main/java/com/ql/util/express/LocalExpressCacheRunner.java @@ -4,7 +4,7 @@ import java.util.Map; /** - * 作为表达式 + * As an expression * @author tianqiao * */ diff --git a/src/main/java/com/ql/util/express/OperateData.java b/src/main/java/com/ql/util/express/OperateData.java index b17271583..0dbf830f5 100644 --- a/src/main/java/com/ql/util/express/OperateData.java +++ b/src/main/java/com/ql/util/express/OperateData.java @@ -4,7 +4,7 @@ import com.ql.util.express.exception.QLException; /** - * 数据类型定义 + * Data type definition * @author qhlhl2010@gmail.com * */ @@ -19,7 +19,7 @@ public OperateData(Object obj, Class aType) { this.dataObject = obj; } /** - * 给对象缓存接口使用 + * Use for object cache interface * @param obj * @param aType */ @@ -50,7 +50,7 @@ public Class getType(InstructionSetContext parent) throws Exception { public final Object getObject(InstructionSetContext context) throws Exception { if(this.type != null && this.type.equals(void.class)){ - throw new QLException("void 不能参与任何操作运算,请检查使用在表达式中使用了没有返回值的函数,或者分支不完整的if语句"); + throw new QLException("Cannot participate in any operation, please check the use of a function that does not return a value in the expression, or if the branch is incomplete "); } return getObjectInner(context); } @@ -58,11 +58,11 @@ public Object getObjectInner(InstructionSetContext context) throws Exception{ return this.dataObject; } public void setObject(InstructionSetContext parent, Object object) throws Exception { - throw new RuntimeException("必须在子类中实现此方法"); + throw new RuntimeException("This method must be implemented in the subclass"); } public String toJavaCode(){ if(this.getClass().equals(OperateData.class) == false){ - throw new RuntimeException(this.getClass().getName() + "没有实现:toJavaCode()"); + throw new RuntimeException(this.getClass().getName() + "Not realized:toJavaCode()"); } String result ="new " + OperateData.class.getName() +"("; if(String.class.equals(this.type)){ diff --git a/src/main/java/com/ql/util/express/Operator.java b/src/main/java/com/ql/util/express/Operator.java index c136db0e3..b9bb649bd 100644 --- a/src/main/java/com/ql/util/express/Operator.java +++ b/src/main/java/com/ql/util/express/Operator.java @@ -8,7 +8,7 @@ import java.util.Date; /** - * 操作符的基类 + * Operator base class * * @author xuannan */ @@ -25,7 +25,7 @@ public OperateData executeInner(InstructionSetContext context, ArraySwap list) t } Object result = this.executeInner(parameters); if (result != null && result.getClass().equals(OperateData.class)) { - throw new QLException("操作符号定义的返回类型错误:" + this.getAliasName()); + throw new QLException("The return type defined by the operation symbol is wrong: " + this.getAliasName()); } if (result == null) { //return new OperateData(null,null); @@ -39,7 +39,7 @@ public OperateData executeInner(InstructionSetContext context, ArraySwap list) t public abstract Object executeInner(Object[] list) throws Exception; /** - * 进行对象是否相等的比较 + * Compare whether objects are equal * @param op1 * @param op2 * @return @@ -53,34 +53,34 @@ public static boolean objectEquals(Object op1, Object op2) throws Exception{ return false; } - //Character的值比较 + //Character-Value comparison if(op1 instanceof Character || op2 instanceof Character){ int compareResult = 0; if (op1 instanceof Character && op2 instanceof Character) { - return ((Character) op1).equals((Character) op2); + return op1.equals(op2); }else if (op1 instanceof Number) { - compareResult = OperatorOfNumber.compareNumber((Number) op1, (int) ((Character) op2).charValue()); + compareResult = OperatorOfNumber.compareNumber((Number) op1, (int) (Character) op2); return compareResult==0; } else if (op2 instanceof Number) { - compareResult = OperatorOfNumber.compareNumber((int) ((Character) op1).charValue(), (Number) op2); + compareResult = OperatorOfNumber.compareNumber((int) (Character) op1, (Number) op2); return compareResult==0; } } - //数值的值比较 + //Numerical value comparison if (op1 instanceof Number && op2 instanceof Number) { - //数字比较 + //Number comparison int compareResult = OperatorOfNumber.compareNumber((Number) op1, (Number) op2); return compareResult==0; } - //调用原始Object的比较 + //Call the comparison of the original Object return op1.equals(op2); } - /** - * 进行对象比较 - * + + + /** Compare objects * @param op1 * @param op2 - * @return 0 等于 ,负数 小于 , 正数 大于 + * @return * @throws Exception */ public static int compareData(Object op1, Object op2) throws Exception { @@ -103,10 +103,10 @@ public static int compareData(Object op1, Object op2) throws Exception { } else if (op2 instanceof Number) { compareResult = OperatorOfNumber.compareNumber((int) ((Character) op1).charValue(), (Number) op2); } else { - throw new QLException(op1 + "和" + op2 + "不能执行compare 操作"); + throw new QLException(op1 + ":" + op2 + " - Cannot perform compare operation "); } } else if (op1 instanceof Number && op2 instanceof Number) { - //数字比较 + //Number comparison compareResult = OperatorOfNumber.compareNumber((Number) op1, (Number) op2); } else if ((op1 instanceof Boolean) && (op2 instanceof Boolean)) { if (((Boolean) op1).booleanValue() == ((Boolean) op2).booleanValue()) @@ -116,7 +116,7 @@ public static int compareData(Object op1, Object op2) throws Exception { } else if ((op1 instanceof Date) && (op2 instanceof Date)) { compareResult = ((Date) op1).compareTo((Date) op2); } else - throw new QLException(op1 + "和" + op2 + "不能执行compare 操作"); + throw new QLException(op1 + ":" + op2 + " - Cannot perform compare operation "); return compareResult; } diff --git a/src/main/java/com/ql/util/express/OperatorOfNumber.java b/src/main/java/com/ql/util/express/OperatorOfNumber.java index be62614cd..b09cdab27 100644 --- a/src/main/java/com/ql/util/express/OperatorOfNumber.java +++ b/src/main/java/com/ql/util/express/OperatorOfNumber.java @@ -3,21 +3,19 @@ import com.ql.util.express.exception.QLException; import java.math.BigDecimal; +import java.math.RoundingMode; /** - * 数字运行函数集合 - * @author qhlhl2010@gmail.com * */ - interface NumberType{ - public int NUMBER_TYPE_BYTE = 1; - public int NUMBER_TYPE_SHORT = 2; - public int NUMBER_TYPE_INT = 3; - public int NUMBER_TYPE_LONG = 4; - public int NUMBER_TYPE_FLOAT = 5; - public int NUMBER_TYPE_DOUBLE = 6; - public int NUMBER_TYPE_BIGDECIMAL = 7; + int NUMBER_TYPE_BYTE = 1; + int NUMBER_TYPE_SHORT = 2; + int NUMBER_TYPE_INT = 3; + int NUMBER_TYPE_LONG = 4; + int NUMBER_TYPE_FLOAT = 5; + int NUMBER_TYPE_DOUBLE = 6; + int NUMBER_TYPE_BIGDECIMAL = 7; } public class OperatorOfNumber { @@ -28,11 +26,11 @@ public static double round(double v, int scale) { } BigDecimal b = new BigDecimal(Double.toString(v)); BigDecimal one = new BigDecimal("1"); - return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); + return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); } /** - * 获取数据类型精度顺序 + * Get data type precision order * @param aClass * @return */ @@ -44,10 +42,10 @@ public static int getSeq(Class aClass){ if(aClass == Float.class || aClass == float.class) return NumberType.NUMBER_TYPE_FLOAT; if(aClass == Double.class || aClass == double.class) return NumberType.NUMBER_TYPE_DOUBLE; if(aClass == BigDecimal.class) return NumberType.NUMBER_TYPE_BIGDECIMAL; - throw new RuntimeException("不能处理的数据类型:" + aClass.getName()); + throw new RuntimeException("Unknown numerical class:" + aClass.getName()); } /** - * 进行数据类型转换 + * Perform data type conversion * @param value * @param type * @return @@ -55,96 +53,101 @@ public static int getSeq(Class aClass){ public static Number transfer(Number value,Class type,boolean isForce){ if (isForce == true || value instanceof BigDecimal == false) { if (type.equals(byte.class) || type.equals(Byte.class)) { - return ((Number) value).byteValue(); + return value.byteValue(); } else if (type.equals(short.class) || type.equals(Short.class)) { - return ((Number) value).shortValue(); + return value.shortValue(); } else if (type.equals(int.class) || type.equals(Integer.class)) { - return ((Number) value).intValue(); + return value.intValue(); } else if (type.equals(long.class) || type.equals(Long.class)) { - return ((Number) value).longValue(); + return value.longValue(); } else if (type.equals(float.class) || type.equals(Float.class)) { - return ((Number) value).floatValue(); + return value.floatValue(); } else if (type.equals(double.class) || type.equals(Double.class)) { - return ((Number) value).doubleValue(); + return value.doubleValue(); } else if (type.equals(BigDecimal.class)) { return new BigDecimal(value.toString()); }else{ - throw new RuntimeException("没有处理的数据类型:" + type.getName()); + throw new RuntimeException("Data types not processed: " + type.getName()); } } else { if (type.equals(byte.class) || type.equals(Byte.class)) { if(((BigDecimal)value).scale() >0 ){ - throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + throw new RuntimeException("There are decimal places and cannot be converted to: "+ type.getName()); } - return ((Number) value).byteValue(); + return value.byteValue(); } else if (type.equals(short.class) || type.equals(Short.class)) { if(((BigDecimal)value).scale() >0 ){ - throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + throw new RuntimeException("There are decimal places and cannot be converted to: "+ type.getName()); } - return ((Number) value).shortValue(); + return value.shortValue(); } else if (type.equals(int.class) || type.equals(Integer.class)) { if(((BigDecimal)value).scale() >0 ){ - throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + throw new RuntimeException("There are decimal places and cannot be converted to: "+ type.getName()); } - return ((Number) value).intValue(); + return value.intValue(); } else if (type.equals(long.class) || type.equals(Long.class)) { if(((BigDecimal)value).scale() >0 ){ - throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + throw cannotProcessDecimalFor(type); } - return ((Number) value).longValue(); + return value.longValue(); } else if (type.equals(float.class) || type.equals(Float.class)) { - return ((Number) value).floatValue(); + return value.floatValue(); } else if (type.equals(double.class) || type.equals(Double.class)) { - return ((Number) value).doubleValue(); + return value.doubleValue(); }else{ - throw new RuntimeException("没有处理的数据类型:" + type.getName()); + throw new RuntimeException("Data types not processed: " + type.getName()); } } } + + private static RuntimeException cannotProcessDecimalFor(Class type) { + return new RuntimeException("There are decimal places and cannot be converted to: "+ type.getName()); + } + public static int compareNumber(Number op1, Number op2){ int type1 = OperatorOfNumber.getSeq(op1.getClass()); int type2 = OperatorOfNumber.getSeq(op2.getClass()); int type = type1 > type2 ? type1:type2; if(type == 1) { - byte o1 = ((Number)op1).byteValue(); - byte o2 = ((Number)op2).byteValue(); + byte o1 = op1.byteValue(); + byte o2 = op2.byteValue(); if(o1 == o2) return 0; if(o1 < o2) return -1; return 1; } if(type == 2) { - short o1 = ((Number)op1).shortValue(); - short o2 = ((Number)op2).shortValue(); + short o1 = op1.shortValue(); + short o2 = op2.shortValue(); if(o1 == o2) return 0; if(o1 < o2) return -1; return 1; } if(type == 3) { - int o1 = ((Number)op1).intValue(); - int o2 = ((Number)op2).intValue(); + int o1 = op1.intValue(); + int o2 = op2.intValue(); if(o1 == o2) return 0; if(o1 < o2) return -1; return 1; } if(type == 4) { - long o1 = ((Number)op1).longValue(); - long o2 = ((Number)op2).longValue(); + long o1 = op1.longValue(); + long o2 = op2.longValue(); if(o1 == o2) return 0; if(o1 < o2) return -1; return 1; } if(type == 5) { - float o1 = ((Number)op1).floatValue(); - float o2 = ((Number)op2).floatValue(); + float o1 = op1.floatValue(); + float o2 = op2.floatValue(); if(o1 == o2) return 0; if(o1 < o2) return -1; return 1; } if(type == 6){ - double o1 = ((Number)op1).doubleValue(); - double o2 = ((Number)op2).doubleValue(); + double o1 = op1.doubleValue(); + double o2 = op2.doubleValue(); if(o1 == o2) return 0; if(o1 < o2) return -1; return 1; @@ -200,9 +203,8 @@ public static Object modulo(Object op1,Object op2) throws Exception{ } class NormalNumberOperator { - + /** - * 普通的加法运算 * @param op1 * @param op2 * @return @@ -219,12 +221,15 @@ public static Number addNormal(Number op1, Number op2) throws Exception { if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() + op2.floatValue(); if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() + op2.doubleValue(); if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).add(new BigDecimal(op2.toString())); - throw new QLException("不支持的对象执行了\"+\"操作"); + throw unsupportedOperation("+"); } + private static QLException unsupportedOperation(String operation) { + return new QLException("Unsupported object performed operation: "+ operation); + } - public static Number subtractNormal(Number op1,Number op2) throws Exception{ + public static Number subtractNormal(Number op1,Number op2) throws Exception{ int type1 = OperatorOfNumber.getSeq(op1.getClass()); int type2 = OperatorOfNumber.getSeq(op2.getClass()); int type = type1 > type2 ? type1:type2; @@ -235,7 +240,7 @@ public static Number subtractNormal(Number op1,Number op2) throws Exception{ if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() - op2.floatValue(); if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() - op2.doubleValue(); if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).subtract(new BigDecimal(op2.toString())); - throw new QLException("不支持的对象执行了\"-\"操作"); + throw unsupportedOperation("-"); } public static Number multiplyNormal(Number op1,Number op2) throws Exception { @@ -249,7 +254,7 @@ public static Number multiplyNormal(Number op1,Number op2) throws Exception { if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() * op2.floatValue(); if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() * op2.doubleValue(); if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).multiply(new BigDecimal(op2.toString())); - throw new QLException("不支持的对象执行了\"*\"操作"); + throw unsupportedOperation("*"); } public static Number divideNormal(Number op1,Number op2) throws Exception{ int type1 = OperatorOfNumber.getSeq(op1.getClass()); @@ -262,7 +267,7 @@ public static Number divideNormal(Number op1,Number op2) throws Exception{ if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() / op2.floatValue(); if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() / op2.doubleValue(); if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).divide(new BigDecimal(op2.toString()), BigDecimal.ROUND_HALF_UP); - throw new QLException("不支持的对象执行了\"/\"操作"); + throw unsupportedOperation("/"); } @@ -274,12 +279,12 @@ public static Number moduloNormal(Number op1,Number op2) throws Exception{ if(type == NumberType.NUMBER_TYPE_SHORT) return op1.shortValue() % op2.shortValue(); if(type == NumberType.NUMBER_TYPE_INT) return op1.intValue() % op2.intValue(); if(type == NumberType.NUMBER_TYPE_LONG) return op1.longValue() % op2.longValue(); - throw new QLException("不支持的对象执行了\"mod\"操作"); + throw unsupportedOperation("mod"); } } /** - * 高精度计算 + * High-precision calculation * @author xuannan */ class PreciseNumberOperator { diff --git a/src/main/java/com/ql/util/express/RunEnvironment.java b/src/main/java/com/ql/util/express/RunEnvironment.java index 6ce834e2c..e346260dd 100644 --- a/src/main/java/com/ql/util/express/RunEnvironment.java +++ b/src/main/java/com/ql/util/express/RunEnvironment.java @@ -95,13 +95,13 @@ public void push(OperateData data){ } public OperateData peek(){ if(point <0){ - throw new RuntimeException("系统异常,堆栈指针错误"); + throw new RuntimeException("System exception, stack pointer error"); } return this.dataContainer[point]; } public OperateData pop(){ if(point <0) - throw new RuntimeException("系统异常,堆栈指针错误"); + throw new RuntimeException("System exception, stack pointer error"); OperateData result = this.dataContainer[point]; this.point--; return result; @@ -113,7 +113,7 @@ public void gotoWithOffset(int aOffset ){ this.programPoint = this.programPoint + aOffset; } /** - * 此方法是调用最频繁的,因此尽量精简代码,提高效率 + * This method is called the most frequently, so try to streamline the code and improve efficiency * @param context * @param len * @return @@ -137,13 +137,13 @@ public OperateData[] popArrayOld(InstructionSetContext context,int len) throws E public OperateData[] popArrayBackUp(InstructionSetContext context,int len) throws Exception { int start = point - len + 1; if(start <0){ - throw new QLException("堆栈溢出,请检查表达式是否错误"); + throw new QLException("Stack overflow, please check if the expression is wrong "); } OperateData[] result = new OperateData[len]; for (int i = 0 ; i < len; i++) { result[i] = this.dataContainer[start + i]; if(void.class.equals(result[i].getType(context))){ - throw new QLException("void 不能参与任何操作运算,请检查使用在表达式中使用了没有返回值的函数,或者分支不完整的if语句"); + throw new QLException("Cannot participate in any operation, please check the use of a function that does not return a value in the expression, or if the branch is incomplete "); } } point = point - len; diff --git a/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java b/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java index aac61ca52..8e614ff42 100644 --- a/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java +++ b/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java @@ -7,19 +7,19 @@ import java.util.List; /** - * ExpressRunner设置全局生效的配置,直接使用静态方法控制 + * ExpressRunner Set the globally effective configuration, directly use the static method to control */ public class QLExpressRunStrategy { /** - * 预防空指针 + * Null pointer prevention */ private static boolean avoidNullPointer = false; /** - * 当空对象进行大小比较时,返回false, 例如 1 > null 和 null > 1都返回false + * When comparing the size of an empty object, it returns false, for example, 1> null and null> 1 both return false */ private static boolean compareNullLessMoreAsFalse = false; @@ -40,9 +40,7 @@ public static void setAvoidNullPointer(boolean avoidNullPointer) { } - /** - * 禁止调用不安全的方法 - */ + private static boolean forbiddenInvokeSecurityRiskMethods = false; public static boolean isForbiddenInvokeSecurityRiskMethods() { @@ -56,8 +54,8 @@ public static void setForbiddenInvokeSecurityRiskMethods(boolean forbiddenInvoke private static ListsecurityRiskMethods = new ArrayList(); static{ - securityRiskMethods.add(System.class.getName()+"."+"exit");//系统退出 - securityRiskMethods.add(Runtime.getRuntime().getClass().getName()+".exec");//运行脚本命令 + securityRiskMethods.add(System.class.getName()+"."+"exit"); + securityRiskMethods.add(Runtime.getRuntime().getClass().getName()+".exec"); } public static void addSecurityRiskMethod(Class clazz, String methodName ) @@ -69,7 +67,7 @@ public static void assertBlackMethod(Method m) throws QLSecurityRiskException { if(forbiddenInvokeSecurityRiskMethods && m!=null){ if(securityRiskMethods.contains(m.getDeclaringClass().getName()+"."+m.getName())) { - throw new QLSecurityRiskException("使用QLExpress调用了不安全的系统方法:" + m.toString()); + throw new QLSecurityRiskException("An unsafe system method was called using QLExpress: " + m.toString()); } } } diff --git a/src/main/java/com/ql/util/express/config/QLExpressTimer.java b/src/main/java/com/ql/util/express/config/QLExpressTimer.java index 7d8204a55..ad11e7286 100644 --- a/src/main/java/com/ql/util/express/config/QLExpressTimer.java +++ b/src/main/java/com/ql/util/express/config/QLExpressTimer.java @@ -23,8 +23,8 @@ protected Boolean initialValue() { /** - * 设置计时器 - * @param timeoutMillis 超时时间 + * Set timer + * @param timeoutMillis overtime time */ public static void setTimer(long timeoutMillis) { @@ -33,7 +33,7 @@ public static void setTimer(long timeoutMillis) } /** - * 开始计时 + * start the timer */ public static void startTimer() { @@ -46,13 +46,13 @@ public static void startTimer() /** - * 断言是否超时 + * Whether the assertion timed out * @throws QLTimeOutException */ public static void assertTimeOut() throws QLTimeOutException { if(NEED_TIMER.get() && System.currentTimeMillis()>END_TIME.get()){ - throw new QLTimeOutException("运行QLExpress脚本的下一条指令将超过了限定时间:" + TIME_OUT_MILLIS.get() + "ms"); + throw new QLTimeOutException("The next instruction to run the QLExpress script will exceed the time limit:" + TIME_OUT_MILLIS.get() + "ms"); } } diff --git a/src/main/java/com/ql/util/express/exception/QLBizException.java b/src/main/java/com/ql/util/express/exception/QLBizException.java index 33f6d9b2a..9746d91f8 100644 --- a/src/main/java/com/ql/util/express/exception/QLBizException.java +++ b/src/main/java/com/ql/util/express/exception/QLBizException.java @@ -1,7 +1,7 @@ package com.ql.util.express.exception; /** - * 非QLExpress框架捕获的业务系统代码的异常 + * Business system code exceptions captured by non-QLExpress framework * @author tianqiao@taobao.com * @since 2019/6/18 2:13 PM */ diff --git a/src/main/java/com/ql/util/express/exception/QLCompileException.java b/src/main/java/com/ql/util/express/exception/QLCompileException.java index 0f31f8317..b0d1a1a34 100644 --- a/src/main/java/com/ql/util/express/exception/QLCompileException.java +++ b/src/main/java/com/ql/util/express/exception/QLCompileException.java @@ -1,7 +1,7 @@ package com.ql.util.express.exception; /** - * 编译器的异常信息 + * Compiler exception information * @author tianqiao@taobao.com * @since 2019/6/18 2:13 PM */ diff --git a/src/main/java/com/ql/util/express/exception/QLException.java b/src/main/java/com/ql/util/express/exception/QLException.java index 47c6ec6f4..772b88e68 100644 --- a/src/main/java/com/ql/util/express/exception/QLException.java +++ b/src/main/java/com/ql/util/express/exception/QLException.java @@ -1,7 +1,7 @@ package com.ql.util.express.exception; /** - * QLExpress的框架执行过程中捕获的异常 + * The exception caught during the execution of the QLExpress framework * @author tianqiao@taobao.com * @since 2019/6/18 2:13 PM */ diff --git a/src/main/java/com/ql/util/express/exception/QLSecurityRiskException.java b/src/main/java/com/ql/util/express/exception/QLSecurityRiskException.java index dca97b891..eef7f6356 100644 --- a/src/main/java/com/ql/util/express/exception/QLSecurityRiskException.java +++ b/src/main/java/com/ql/util/express/exception/QLSecurityRiskException.java @@ -1,7 +1,7 @@ package com.ql.util.express.exception; /** - * 系统安全相关异常(比如调用操作系统命令等) + * System security related exceptions (such as calling operating system commands, etc.) * @author tianqiao@taobao.com * @since 2019/6/18 10:36 AM */ diff --git a/src/main/java/com/ql/util/express/exception/QLTimeOutException.java b/src/main/java/com/ql/util/express/exception/QLTimeOutException.java index e89283aee..4fd2a011b 100644 --- a/src/main/java/com/ql/util/express/exception/QLTimeOutException.java +++ b/src/main/java/com/ql/util/express/exception/QLTimeOutException.java @@ -1,7 +1,7 @@ package com.ql.util.express.exception; /** - * 设置了timeoutMills造成的超时异常 + * Timeout exception caused by timeoutMills is set * @author tianqiao@taobao.com * @since 2019/6/18 10:36 AM */ diff --git a/src/main/java/com/ql/util/express/match/IDataNode.java b/src/main/java/com/ql/util/express/match/IDataNode.java index 78727d6d2..90e407e78 100644 --- a/src/main/java/com/ql/util/express/match/IDataNode.java +++ b/src/main/java/com/ql/util/express/match/IDataNode.java @@ -3,14 +3,14 @@ public interface IDataNode { - public void setNodeType(INodeType type); - public void setTreeType(INodeType findNodeType); - public INodeType getNodeType(); - public INodeType getTreeType(); + void setNodeType(INodeType type); + void setTreeType(INodeType findNodeType); + INodeType getNodeType(); + INodeType getTreeType(); - public void addLeftChild(IDataNode ref); - public IDataNode createExpressNode(INodeType aType,String aValue) throws Exception; + void addLeftChild(IDataNode ref); + IDataNode createExpressNode(INodeType aType, String aValue) throws Exception; - public String getValue(); - public void setObjectValue(Object value); + String getValue(); + void setObjectValue(Object value); } diff --git a/src/main/java/com/ql/util/express/match/INodeType.java b/src/main/java/com/ql/util/express/match/INodeType.java index a3166887d..57ef521d6 100644 --- a/src/main/java/com/ql/util/express/match/INodeType.java +++ b/src/main/java/com/ql/util/express/match/INodeType.java @@ -2,12 +2,12 @@ /** - * 匹配类型 + * Match type * @author xuannan * */ public interface INodeType { - public String getName(); - public INodeTypeManager getManager(); - public QLPatternNode getPatternNode(); + String getName(); + INodeTypeManager getManager(); + QLPatternNode getPatternNode(); } diff --git a/src/main/java/com/ql/util/express/match/INodeTypeManager.java b/src/main/java/com/ql/util/express/match/INodeTypeManager.java index e30134995..dc33d518c 100644 --- a/src/main/java/com/ql/util/express/match/INodeTypeManager.java +++ b/src/main/java/com/ql/util/express/match/INodeTypeManager.java @@ -1,5 +1,5 @@ package com.ql.util.express.match; public interface INodeTypeManager { - public INodeType findNodeType(String name); + INodeType findNodeType(String name); } diff --git a/src/main/java/com/ql/util/express/match/QLPattern.java b/src/main/java/com/ql/util/express/match/QLPattern.java index 6625866e9..e2f39a2b3 100644 --- a/src/main/java/com/ql/util/express/match/QLPattern.java +++ b/src/main/java/com/ql/util/express/match/QLPattern.java @@ -12,8 +12,8 @@ public class QLPattern { private static final Log log = LogFactory.getLog(QLPattern.class); - public static boolean optimizeStackDepth = true;//优化栈的递归深度 - public static boolean printStackDepth = false;//打印栈的最大深度 + public static boolean optimizeStackDepth = true;//Optimize the recursion depth of the stack + public static boolean printStackDepth = false;//Maximum depth of printing stack public static QLPatternNode createPattern(INodeTypeManager nodeTypeManager,String name,String pattern) throws Exception{ return new QLPatternNode(nodeTypeManager,name,pattern); @@ -26,14 +26,14 @@ public static QLMatchResult findMatchStatement(INodeTypeManager aManager,QLPatte MatchParamsPack staticParams = new MatchParamsPack(aManager, nodes, maxDeep, maxMatchPoint,resultCache,arrayListCache); QLMatchResult result = findMatchStatementWithAddRootOptimizeStack(staticParams, pattern, point, true, 1); if(printStackDepth) { - log.warn("递归堆栈深度:" + maxDeep.longValue() + " 重用QLMatchResult次数:" + resultCache.fetchCount - + " 新建QLMatchResult次数:" + resultCache.newCount + " 新建ArrayList数量:" + arrayListCache.newCount); + log.warn("Recursive stack depth: \"+ maxDeep.longValue() +\" number of times to reuse QLMatchResult:" + resultCache.fetchCount + + "Number of new MatchResults:" + resultCache.newCount + "Number of new ArrayLists:" + arrayListCache.newCount); } if(result == null || result.getMatchSize() == 0){ - throw new QLCompileException("程序错误,不满足语法规范,没有匹配到合适的语法,最大匹配致[0:" + (maxMatchPoint.longValue()-1) +"]"); + throw new QLCompileException("Program error, does not meet the grammar specification, does not match the appropriate grammar, the maximum match is [0:" + (maxMatchPoint.longValue()-1) +"]"); }else if(result != null && result.getMatchSize() != 1){ - throw new QLCompileException("程序错误,不满足语法规范,必须有一个根节点:" + pattern + ",最大匹配致[0:" + (maxMatchPoint.longValue()-1) +"]"); + throw new QLCompileException("Program error, does not meet the grammatical specifications, there must be a root node: "+ pattern + ", the maximum match is [0:" + (maxMatchPoint.longValue()-1) +"]"); } return result; } @@ -86,12 +86,12 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa resultDetail = findMatchStatementWithAddRootOptimizeStack(staticParams,pattern.nodeType.getPatternNode(),pointDetail,false,deep); if(pattern.targetNodeType != null && resultDetail != null && resultDetail.getMatchSize() >0){ if(resultDetail.getMatchSize() > 1){ - throw new QLCompileException("设置了类型转换的语法,只能有一个根节点"); + throw new QLCompileException("The type conversion syntax is set, there can only be one root node"); } resultDetail.getMatchs().get(0).targetNodeType = pattern.targetNodeType; } } - if(pattern.blame == true){//取返处理 + if(pattern.blame == true){//Retrieve processing if( resultDetail == null){ resultDetail = staticParams.resultCache.fetch(); resultDetail.addQLMatchResultTree(new QLMatchResultTree(tempNodeType,nodes.get(pointDetail),null)); @@ -116,7 +116,7 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa int pointAnd = lastPoint; QLMatchResultTree root = null; - int matchCount =0;//用于调试日志的输出 + int matchCount =0;//Output for debug log List tempListAnd =null; boolean isBreak = false; for (QLPatternNode item : pattern.children) { @@ -136,7 +136,7 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa pointAnd = tempResultAnd.getMatchLastIndex(); if (item.isTreeRoot == true && tempResultAnd.getMatchSize() >0) { if (tempResultAnd.getMatchSize() > 1) { - throw new QLCompileException("根节点的数量必须是1"); + throw new QLCompileException("The number of root nodes must be 1"); } if (root == null) { QLMatchResultTree tempTree = tempResultAnd.getMatchs().get(0); @@ -154,7 +154,7 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa } else { tempListAnd.addAll(tempResultAnd.getMatchs()); } - //归还QLMatchResult对象到对象池 + //Return the MatchResult object to the object pool if (tempResultAnd!= null) { staticParams.resultCache.sendBack(tempResultAnd); tempResultAnd = null; @@ -193,12 +193,12 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa } }else{ - throw new QLCompileException("不正确的类型:" + pattern.matchMode.toString()); + throw new QLCompileException("Incorrect type:" + pattern.matchMode.toString()); } if(tempResult == null){ if(count >= pattern.minMatchNum && count <=pattern.maxMatchNum){ - //正确匹配 + //Correct match result = staticParams.resultCache.fetch(); if(tempList != null){ result.addQLMatchResultTreeList(tempList); @@ -215,13 +215,13 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa lastPoint = tempResult.getMatchLastIndex(); if(pattern.isTreeRoot == true){ if(tempResult.getMatchSize() > 1){ - throw new QLCompileException("根节点的数量必须是1"); + throw new QLCompileException("The number of root nodes must be 1"); } if(tempList.size() == 0){ tempList.addAll(tempResult.getMatchs()); }else{ tempResult.getMatchs().get(0).addLeftAll(tempList); - //为了能回收QLMatchResult对象,这个地方必须进行数组拷贝 + //In order to be able to recover the MatchResult object, this place must be an array copy tempList = staticParams.arrayListCache.fetch(); tempList.addAll(tempResult.getMatchs()); } @@ -230,7 +230,7 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa } } - /** 归还QLMatchResult */ + /** Return MatchResult */ if(tempResult != null){ staticParams.resultCache.sendBack(tempResult); tempResult = null; @@ -247,7 +247,7 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa } } if(result != null && pattern.isSkip == true){ - //忽略跳过所有匹配到的节点 + //Ignore skip all matched nodes result.getMatchs().clear(); } @@ -266,7 +266,7 @@ private static QLMatchResult findMatchStatementWithAddRootOptimizeStack(MatchPa public static void traceLog(QLPatternNode pattern, QLMatchResult result, List nodes, int point,int matchCount) { if (log.isTraceEnabled() && (pattern.matchMode ==MatchMode.DETAIL || pattern.matchMode == MatchMode.AND && matchCount > 1 && pattern.name.equals("ANONY_PATTERN") == false )) { - log.trace("匹配--" + pattern.name +"[" + point + ":" + (result.getMatchLastIndex() -1)+ "]:" + pattern); + log.trace("Match--" + pattern.name +"[" + point + ":" + (result.getMatchLastIndex() -1)+ "]:" + pattern); } } diff --git a/src/main/java/com/ql/util/express/match/QLPatternNode.java b/src/main/java/com/ql/util/express/match/QLPatternNode.java index f9d357194..fb2fbb5d9 100644 --- a/src/main/java/com/ql/util/express/match/QLPatternNode.java +++ b/src/main/java/com/ql/util/express/match/QLPatternNode.java @@ -17,60 +17,60 @@ public class QLPatternNode{ String name; /** - * 原始的字符串 + * Original string */ String orgiContent; /** - * 匹配模式 + * Match mode */ MatchMode matchMode =MatchMode.NULL ; /** - * 是否一个子匹配模式 + * Is a submatch pattern */ boolean isChildMode = false; /** - * 层次 + * level */ int level =0; /** - * 是否根节点,例如:if^ + * Whether the root node, for example: if^ */ protected boolean isTreeRoot =false; /** - * 最小匹配次数,0..n + * Minimum number of matches, 0..n */ protected int minMatchNum =1; /** - * 最大匹配次数 + * Maximum number of matches */ protected int maxMatchNum =1; /** - * 匹配类型,例如 ID,if,SELECT + * Match type, such as ID,if,SELECT */ protected INodeType nodeType; /** - * 匹配到的节点需要转换成的类型,例如 ID -》CONST_STRING + * The type that the matched node needs to be converted into, such as ID-"CONST_STRING */ protected INodeType targetNodeType; /** - * 需要转为的虚拟类型,例如:(ID$(,$ID)*)#COL_LIST + * The virtual type to be converted to, for example:(ID$(,$ID)*)#COL_LIST */ protected INodeType rootNodeType; /** - * 是否匹配成功,但在输出的时候忽略,用"~"表示 + * Whether the match is successful, but ignored in the output, expressed with "~" * CONST$(,~$CONST)* */ protected boolean isSkip =false; /** - * 取反,例如:+@,匹配不是+的所有字符 + * Negative, for example: +@, matches all characters that are not + */ protected boolean blame = false; @@ -89,15 +89,15 @@ public boolean canMergeDetail(){ } /** - * 子匹配模式 + * Submatch */ List children = new ArrayList(); protected QLPatternNode(INodeTypeManager aManager,String aName,String aOrgiContent) throws Exception{ this(aManager,aName,aOrgiContent,false,1); // if(this.toString().equals(aOrgiContent)==false){ - //throw new QLCompileException("语法定义解析后的结果与原始值不一致,原始值:"+ aOrgiContent + " 解析结果:" + this.toString()); - //log.error(("语法定义解析后的结果与原始值不一致,原始值:"+ aOrgiContent + " 解析结果:" + this.toString())); + //throw new QLCompileException("The parsed result of the grammar definition is inconsistent with the original value, original value: "+ aOrgiContent + "parsed result:" + this.toString()); + //log.error(("The parsed result of the grammar definition is inconsistent with the original value, original value: "+ aOrgiContent + "parsed result:" + this.toString())); // } } protected QLPatternNode(INodeTypeManager aManager,String aName,String aOrgiContent,boolean aIsChildMode,int aLevel) throws Exception{ @@ -124,7 +124,7 @@ public void splitChild() throws Exception{ for(int i=0;i 0) { - throw new QLCompileException("不正确的模式串,(没有找到对应的):" + orgStr); + throw new QLCompileException("Incorrect pattern string, (the corresponding one was not found):" + orgStr); } if(this.children.size() > 0){ @@ -179,7 +179,7 @@ public void splitChild() throws Exception{ tempStr =""; } - //需要剔除乘法*的情况 + //Need to eliminate multiplication * if(tempStr.endsWith("*") && tempStr.length() >1){ this.minMatchNum = 0; this.maxMatchNum = Integer.MAX_VALUE; @@ -216,7 +216,7 @@ public void splitChild() throws Exception{ tempStr = tempStr.substring(0,tempStr.length() -1); } - //处理(ABC|bcd)模式 + //Processing (ABC|bcd) mode if(tempStr.length() > 2 && tempStr.charAt(0)=='(' && tempStr.charAt(tempStr.length() - 1) ==')'){ this.isChildMode = true; this.children.add(new QLPatternNode(this.nodeTypeManager,"ANONY_PATTERN",tempStr.substring(1, tempStr.length() - 1), false,this.level + 1)); diff --git a/src/main/java/com/ql/util/express/parse/AppendingClassFieldManager.java b/src/main/java/com/ql/util/express/parse/AppendingClassFieldManager.java index dd31e00e3..16a49bf05 100644 --- a/src/main/java/com/ql/util/express/parse/AppendingClassFieldManager.java +++ b/src/main/java/com/ql/util/express/parse/AppendingClassFieldManager.java @@ -39,7 +39,7 @@ public void addAppendingField(String name,Class bindingClass,Class returnT public AppendingField getAppendingClassField(Object object, String FieldName) { for(AppendingField Field : Fields){ - //object是定义类型的子类 + //object is a subclass of the defined type if(FieldName.equals(Field.name) && (object.getClass()==Field.bindingClass || Field.bindingClass.isAssignableFrom(object.getClass()))){ return Field; } diff --git a/src/main/java/com/ql/util/express/parse/AppendingClassMethodManager.java b/src/main/java/com/ql/util/express/parse/AppendingClassMethodManager.java index dc817b768..517686b45 100644 --- a/src/main/java/com/ql/util/express/parse/AppendingClassMethodManager.java +++ b/src/main/java/com/ql/util/express/parse/AppendingClassMethodManager.java @@ -37,7 +37,7 @@ public void addAppendingMethod(String name,Class bindingClass,OperatorBase op public AppendingMethod getAppendingClassMethod(Object object, String methodName) { for(AppendingMethod method : methods){ - //object是定义类型的子类 + //object is a subclass of the defined type if(methodName.equals(method.name) && (object.getClass()==method.bindingClass || method.bindingClass.isAssignableFrom(object.getClass()))){ return method; } diff --git a/src/main/java/com/ql/util/express/parse/ExpressNode.java b/src/main/java/com/ql/util/express/parse/ExpressNode.java index 37a403cd7..78f9b8e94 100644 --- a/src/main/java/com/ql/util/express/parse/ExpressNode.java +++ b/src/main/java/com/ql/util/express/parse/ExpressNode.java @@ -10,24 +10,24 @@ public class ExpressNode implements IDataNode{ /** - * 节点类型 + * Node type */ private NodeType nodeType; private NodeType treeType; /** - * 节点值 + * Node value */ private String value; /** - * 节点原始值 + * Node original value */ private String orgiValue; private Object objectValue; /** - * 父节点 + * Parent node */ private ExpressNode parent; private List leftChildren; @@ -35,15 +35,15 @@ public class ExpressNode implements IDataNode{ private boolean isSplitStatement = false; /** - * 行号 + * Line number */ private int line; /** - * 列号 + * Column number */ private int col; /** - * word的序号 + * word number */ private int wordIndex = -1; @@ -56,7 +56,7 @@ public ExpressNode(NodeType aType, String aValue) throws Exception{ } public ExpressNode(NodeType aType,String aValue,String aOrgiValue,Object aObjectValue,NodeType aTreeType,int aLine,int aCol,int wordIndex) throws Exception{ if(aType == null){ - throw new QLCompileException(aValue + " 没有找到对应的节点类型"); + throw new QLCompileException(aValue + " No corresponding node type found"); } this.nodeType = aType; this.treeType = aTreeType; @@ -113,7 +113,7 @@ public String getInstructionFactory(){ if(this.treeType != null && this.treeType.getInstructionFactory() != null){ return this.treeType.getInstructionFactory(); } - throw new RuntimeException("没有定义节点的指令InstructionFactory信息:" + this.nodeType.getName()+ (this.treeType == null?"":" 或者 " +this.treeType.getName()) ); + throw new RuntimeException("The instruction InstructionFactory information of the node is not defined:" + this.nodeType.getName()+ (this.treeType == null?"":" or " +this.treeType.getName()) ); } public String getOrgiValue() { diff --git a/src/main/java/com/ql/util/express/parse/ExpressPackage.java b/src/main/java/com/ql/util/express/parse/ExpressPackage.java index 570d01fe1..38b1f7a1c 100644 --- a/src/main/java/com/ql/util/express/parse/ExpressPackage.java +++ b/src/main/java/com/ql/util/express/parse/ExpressPackage.java @@ -63,7 +63,7 @@ public Class getClass(String name) { private Class getClassInner(String name,boolean isRootCall) { Class result = null; if (isRootCall == true) { - // 如果本身具有包名,这直接定位 + // If it has a package name, this directly locates if (name.indexOf(".") >= 0) { try { result = Class.forName(name); @@ -99,7 +99,7 @@ private Class getClassInner(String name,boolean isRootCall) { try { result = Class.forName(tmp); } catch (ClassNotFoundException ex) { - // 不做任何操作 + // Do nothing } if (result != null) { return result; diff --git a/src/main/java/com/ql/util/express/parse/ExpressParse.java b/src/main/java/com/ql/util/express/parse/ExpressParse.java index 4f6c474da..2e4dc7baa 100644 --- a/src/main/java/com/ql/util/express/parse/ExpressParse.java +++ b/src/main/java/com/ql/util/express/parse/ExpressParse.java @@ -22,12 +22,12 @@ public class ExpressParse { IExpressResourceLoader expressResourceLoader; /** - * 是否忽略charset类型的数据,而识别为string,比如'a' -> "a" - * 在计算比如 '1'+'2'=='12' + * Whether to ignore charset type data and recognize it as string, such as'a' -> "a" + * In the calculation such as '1'+'2'=='12' */ private boolean ignoreConstChar = false; /** - * 是否需要高精度计算 + * Do you need high-precision calculations */ private boolean isPrecise = false; @@ -75,7 +75,7 @@ protected Word[] dealInclude(Word[] wordObjects) throws Exception{ } /** - * 进行单词类型分析 + * Perform word type analysis * @param aRootExpressPackage * @param wordObjects * @param selfClassDefine @@ -91,7 +91,7 @@ public List transferWord2ExpressNode(ExpressPackage aRootExpressPac ExpressPackage tmpImportPackage = null; if(dealJavaClass==true){ tmpImportPackage = new ExpressPackage(aRootExpressPackage); - //先处理import,import必须放在文件的最开始,必须以;结束 + //Process import first, import must be placed at the very beginning of the file and must end with; boolean isImport = false; StringBuffer importName = new StringBuffer(); while(point transferWord2ExpressNode(ExpressPackage aRootExpressPac char firstChar = tempWord.charAt(0); char lastChar = tempWord.substring(tempWord.length() - 1).toLowerCase().charAt(0); if(firstChar >='0' && firstChar<='9'){ - if(result.size() >0){//对 负号进行特殊处理 + if(result.size() >0){//Special treatment for negative signs if(result.get(result.size() -1).getValue().equals("-")){ if(result.size() == 1 || result.size() >=2 @@ -180,7 +180,7 @@ public List transferWord2ExpressNode(ExpressPackage aRootExpressPac point = point + 1; }else if(firstChar =='"'){ if(lastChar !='"' || tempWord.length() <2){ - throw new QLCompileException("没有关闭的字符串:" + tempWord); + throw new QLCompileException("String not closed:" + tempWord); } tempWord = tempWord.substring(1,tempWord.length() -1); tempType =nodeTypeManager.findNodeType("CONST_STRING"); @@ -189,12 +189,12 @@ public List transferWord2ExpressNode(ExpressPackage aRootExpressPac point = point + 1; }else if(firstChar =='\''){ if(lastChar !='\'' || tempWord.length() <2){ - throw new QLCompileException("没有关闭的字符:" + tempWord); + throw new QLCompileException("No closed characters:" + tempWord); } tempWord = tempWord.substring(1,tempWord.length() -1); treeNodeType = nodeTypeManager.findNodeType("CONST"); - if(tempWord.length() == 1 && !ignoreConstChar){ //转换为字符串 + if(tempWord.length() == 1 && !ignoreConstChar){ //Convert to string tempType =nodeTypeManager.findNodeType("CONST_CHAR"); objectValue = tempWord.charAt(0); }else{ @@ -211,7 +211,7 @@ public List transferWord2ExpressNode(ExpressPackage aRootExpressPac }else { tempType = nodeTypeManager.isExistNodeTypeDefine(tempWord); if(tempType != null && tempType.getKind() != NodeTypeKind.KEYWORD){ - //不是关键字 + //Not a keyword tempType = null; } if (tempType == null) { @@ -314,7 +314,7 @@ public static void resetParent(ExpressNode node,ExpressNode parent){ } } /** - * 提取自定义的Class + * Extract custom Class * @param words */ public static void fetchSelfDefineClass(Word[] words,Map selfDefineClass){ @@ -332,15 +332,15 @@ public ExpressNode parse(ExpressPackage rootExpressPackage,String express,boolea public Word[] splitWords(ExpressPackage rootExpressPackage,String express,boolean isTrace,Map selfDefineClass) throws Exception{ Word[] words = WordSplit.parse(this.nodeTypeManager.splitWord,express); if(isTrace == true && log.isDebugEnabled()){ - log.debug("执行的表达式:" + express); - log.debug("单词分解结果:" + WordSplit.getPrintInfo(words,",")); + log.debug("Expression executed:" + express); + log.debug("Word decomposition result:" + WordSplit.getPrintInfo(words,",")); } words = this.dealInclude(words); if(isTrace == true && log.isDebugEnabled()){ - log.debug("预处理后结果:" + WordSplit.getPrintInfo(words,",")); + log.debug("Result after preprocessing:" + WordSplit.getPrintInfo(words,",")); } - //提取自定义Class + //Extract custom class if(selfDefineClass == null){ selfDefineClass = new HashMap(); } @@ -359,16 +359,16 @@ public ExpressNode parse(ExpressPackage rootExpressPackage,Word[] words ,String List tempList = this.transferWord2ExpressNode(rootExpressPackage,words,selfDefineClass,true); if(isTrace == true && log.isDebugEnabled()){ - log.debug("单词分析结果:" + printInfo(tempList,",")); + log.debug("Word analysis result:" + printInfo(tempList,",")); } - //比如用在远程配置脚本,本地jvm并不包含这个java类,可以 + //For example, when used in remote configuration scripts, the local jvm does not contain this java class, you can if(mockRemoteJavaClass){ List tempList2 = new ArrayList(); for(int i=0;i>",// 位操作 - "+", "-","*", "/", "%","++", "--",//四则运算: - ".",",",":",";","(", ")", "{", "}", "[", "]","?",//分隔符号 - "!","<", ">", "<=", ">=", "==","!=","&&","||",//Boolean运算符号 + "^","~","&","|","<<", ">>",// Bit manipulation + "+", "-","*", "/", "%","++", "--",//Arithmetic: + ".",",",":",";","(", ")", "{", "}", "[", "]","?",//Delimiter + "!","<", ">", "<=", ">=", "==","!=","&&","||",//Boolean operation symbol "=","/**","**/" }; public String[] keyWords = new String[] { diff --git a/src/main/java/com/ql/util/express/parse/NodeType.java b/src/main/java/com/ql/util/express/parse/NodeType.java index 34ba0b975..29aaa51fc 100644 --- a/src/main/java/com/ql/util/express/parse/NodeType.java +++ b/src/main/java/com/ql/util/express/parse/NodeType.java @@ -21,7 +21,7 @@ public class NodeType implements INodeType { private NodeType realNodeType; private String instructionFactory; /** - * 模式匹配 + * Pattern matching */ private QLPatternNode qlPatternNode; @@ -67,13 +67,13 @@ public void initial() { this.qlPatternNode = QLPattern.createPattern(this.manager, this.name, tempList[1]); } else { - throw new RuntimeException("不能识别\"" + this.name - + "\"的属性类型:" + tempList[0] + " 定义:" + throw new RuntimeException("Not recognized\"" + this.name + + "\"Attribute type:" + tempList[0] + " definition:" + this.defineStr); } } } catch (Exception e) { - throw new RuntimeException("节点类型\"" + this.name + "\"初始化失败,定义:" + throw new RuntimeException("Node type\"" + this.name + "\"Initialization failed, definition:" + this.defineStr, e); } } @@ -92,7 +92,7 @@ public boolean isContainerChild(NodeType child) { return ((NodeType) this.qlPatternNode.getNodeType()) .isContainerChild(child); } - // 是and类型,不能增加子节点或进行判断 + // It is of type and, cannot add child nodes or judge if (this.qlPatternNode.isAndMode() && this.qlPatternNode.getChildren().size() > 0) { return false; diff --git a/src/main/java/com/ql/util/express/parse/NodeTypeManager.java b/src/main/java/com/ql/util/express/parse/NodeTypeManager.java index f5dbdfced..596d5a44a 100644 --- a/src/main/java/com/ql/util/express/parse/NodeTypeManager.java +++ b/src/main/java/com/ql/util/express/parse/NodeTypeManager.java @@ -19,7 +19,7 @@ public class NodeTypeManager implements INodeTypeManager { protected String[][] instructionFacotryMapping; protected Map nodeTypes = new HashMap(); - //所有的函数定义 + //All function definitions protected Map functions = new HashMap(); public NodeTypeManager() { @@ -38,7 +38,7 @@ public NodeTypeManager(KeyWordDefine4Java keyWorkdDefine){ } public void initial() { - //创建所有的关键字 + //Create all keywords NodeType[] tempKeyWordNodeTypes = new NodeType[splitWord.length + keyWords.length]; for (int i = 0; i < splitWord.length; i++) { tempKeyWordNodeTypes[i] = this.createNodeType(splitWord[i] + ":TYPE=KEYWORD"); @@ -46,22 +46,22 @@ public void initial() { for (int i = 0 ; i < keyWords.length; i++) { tempKeyWordNodeTypes[i + splitWord.length] = this.createNodeType(keyWords[i] + ":TYPE=KEYWORD"); } - // 初始化所有的类型信息, + // Initialize all type information, for (int i = 0; i < tempKeyWordNodeTypes.length; i++) { tempKeyWordNodeTypes[i].initial(); } - // 创建所有的类型信息,但不能初始化 + // Create all type information, but cannot initialize NodeType[] nodeTypes = new NodeType[nodeTypeDefines.length]; for (int i = 0; i < nodeTypeDefines.length; i++) { nodeTypes[i] = this.createNodeType(nodeTypeDefines[i]); } - // 初始化所有的类型信息, + // Initialize all type information, for (int i = 0; i < nodeTypes.length; i++) { nodeTypes[i].initial(); } - //初始化指令Facotry + //Initialization instruction Factory if (this.instructionFacotryMapping != null) { for (String[] list : this.instructionFacotryMapping) { for (String s : list[0].split(",")) { @@ -72,7 +72,7 @@ public void initial() { } /** - * 创建节点类型,需要注意的是不能初始化,必须所有的类型都创建完成后才能调用初始化方法 + * When creating a node type, it should be noted that it cannot be initialized, and the initialization method must be called after all types are created. * @param aDefineStr * @return */ @@ -81,15 +81,15 @@ public NodeType createNodeType(String aDefineStr){ String name = aDefineStr.substring(0,index).trim(); NodeType define = nodeTypes.get(name); if(define != null ){ - log.warn("节点类型定义重复:"+name+" 定义1="+define.getDefineStr() + " 定义2=" + aDefineStr); - throw new RuntimeException("节点类型定义重复:"+name+" 定义1="+define.getDefineStr() + " 定义2=" + aDefineStr); + log.warn("Duplicate node type definition:"+name+" Definition 1="+define.getDefineStr() + " Definition 2=" + aDefineStr); + throw new RuntimeException("Duplicate node type definition:"+name+" Definition 1="+define.getDefineStr() + " Definition 2=" + aDefineStr); } define = new NodeType(this,name,aDefineStr); nodeTypes.put(name, define); return define; } /** - * 根据类型名称查找节点类型 + * Find node type based on type name * @param name * @return */ @@ -97,7 +97,7 @@ public NodeType createNodeType(String aDefineStr){ public NodeType findNodeType(String name){ NodeType result = nodeTypes.get(name); if(result == null){ - throw new RuntimeException("没有定义的节点类型:" + name); + throw new RuntimeException("Undefined node type:" + name); } while(result.getRealNodeType() != null){ result = result.getRealNodeType(); @@ -106,7 +106,7 @@ public NodeType findNodeType(String name){ } /** - * 增加关键字,但是用实际的类型代替,例如 :"如果" -》"if" + * Add keywords, but replace them with actual types, for example: "if"-"if" * @param keyWordName * @param realName */ @@ -116,7 +116,7 @@ public void addOperatorWithRealNodeType(String keyWordName, String realName){ } /** - * 增加新的操作符号,其优先级别,以及语法关系与参照的操作符号一致 + * Add new operation symbols, their priority levels, and grammatical relations are consistent with the reference operation symbols * @param operName * @param refOperName * @throws Exception @@ -136,7 +136,7 @@ public void addOperatorWithLevelOfReference(String operName, String refOperName) } /** - * 判断是否存在节点类型定义 + * Determine whether there is a node type definition * @param name * @return */ diff --git a/src/main/java/com/ql/util/express/parse/WordSplit.java b/src/main/java/com/ql/util/express/parse/WordSplit.java index d5460c3ad..3300538c6 100644 --- a/src/main/java/com/ql/util/express/parse/WordSplit.java +++ b/src/main/java/com/ql/util/express/parse/WordSplit.java @@ -10,8 +10,8 @@ /** - * 语法解析类 - * 1、单词分解 + * Grammar analysis class + * 1. Word decomposition * @author xuannan * */ @@ -19,7 +19,7 @@ public class WordSplit { /** - * 文本分析函数,“.”作为操作符号处理 + * Text analysis function, "." is handled as an operation symbol * @param str String * @throws Exception * @return String[] @@ -33,26 +33,26 @@ public static Word[] parse(String[] splitWord,String str) throws Exception{ List list = new ArrayList(); int i= 0; int point = 0; - // 当前行第一个字符相对脚本起点的偏移量offset + // The offset of the first character of the current line from the beginning of the script int currentLineOffset = 0; while(i0 && str.charAt(index - 1) =='\\'){ index = str.indexOf(c,index + 1); } if (index < 0) - throw new QLCompileException("字符串没有关闭"); + throw new QLCompileException("String is not closed"); String tempDealStr = str.substring(i,index + 1); - //处理 \\,\"的情况 + //Handle the situation of \\,\" String tmpResult = ""; int tmpPoint = tempDealStr.indexOf("\\"); while(tmpPoint >=0 ){ tmpResult = tmpResult + tempDealStr.substring(0,tmpPoint); if(tmpPoint == tempDealStr.length() -1){ - throw new QLCompileException("字符串中的" + "\\错误:" + tempDealStr); + throw new QLCompileException("In the string" + "\\error:" + tempDealStr); } tmpResult = tmpResult + tempDealStr.substring(tmpPoint + 1 ,tmpPoint + 2); tempDealStr = tempDealStr.substring(tmpPoint + 2); @@ -67,7 +67,7 @@ public static Word[] parse(String[] splitWord,String str) throws Exception{ i = index + 1; point = i; }else if(c=='.' && point < i && isNumber(str.substring(point,i))){ - i = i + 1; //小数点的特殊处理 + i = i + 1; //Special handling of decimal point }else if(c == ' ' ||c =='\r'|| c =='\n'||c=='\t'||c=='\u000C'){ if (point < i ){ list.add(new Word(str.substring(point,i),line,point - currentLineOffset + 1)); @@ -127,7 +127,7 @@ protected static boolean isNumber(String str) { if (str == null || str.equals("")) return false; char c = str.charAt(0); - if (c >= '0' && c <= '9') { // 数字 + if (c >= '0' && c <= '9') { // digital return true; } else { return false; diff --git a/src/main/java/com/ql/util/express/rule/RuleManager.java b/src/main/java/com/ql/util/express/rule/RuleManager.java index 0b885dd24..eddfb9e32 100644 --- a/src/main/java/com/ql/util/express/rule/RuleManager.java +++ b/src/main/java/com/ql/util/express/rule/RuleManager.java @@ -37,7 +37,7 @@ public static RuleResult executeRule(ExpressRunner runner,Rule rule, IExpressCon actionResult = runner.execute(action.getText(),context,null,isCache,isTrace); } catch (Exception e) { result.setHasException(true); - log.error("执行action出错:action=\n"+action.getText(),e); + log.error("Error executing action:action=\n"+action.getText(),e); actionResult = null; } } @@ -60,7 +60,7 @@ private static Boolean calculateCondition(ExpressRunner runner, IExpressContext< return r; } catch (Exception e) { result.setHasException(true); - log.error("计算condition出错:condition=\n"+text,e); + log.error("Error calculating condition:condition=\n"+text,e); traceMap.put(key,false); return false; } @@ -233,7 +233,7 @@ private static void transferCondition(ExpressNode express, Condition condition, transferCondition(child, subCondition, words); } } else { - if (isNodeType(express, "CHILD_EXPRESS")||isNodeType(express, "STAT_BLOCK")||isNodeType(express, "STAT_SEMICOLON")) { //注意括号的情况 + if (isNodeType(express, "CHILD_EXPRESS")||isNodeType(express, "STAT_BLOCK")||isNodeType(express, "STAT_SEMICOLON")) { //Pay attention to the parentheses ExpressNode realExpress = express.getChildren()[0]; condition.setPrior(true); transferCondition(realExpress, condition, words); @@ -254,14 +254,14 @@ private static String makeActionString(ExpressNode express, Word[] words) { int min = getMinNode(express); int max = getMaxNode(express); - //最后需要匹配一个)括号的问题,另外还有是无参数的情况 function() + //Finally, you need to match a) parenthesis, and there are no parameters function() while(max+1=words.length) max = words.length-1; StringBuilder result = new StringBuilder(); - int balance = 0;//小括号的相互匹配数量 + int balance = 0;//The number of matching parentheses for(int i=min;i<=max;i++) { if(words[i].word.equals("(")){ @@ -270,7 +270,7 @@ private static String makeActionString(ExpressNode express, Word[] words) balance--; } if(balance<0){ - balance++;//当前字符不合并,恢复成0,用于最终的判断 + balance++;//The current characters are not merged and restored to 0 for final judgment break; } result.append(words[i].word); @@ -280,7 +280,7 @@ private static String makeActionString(ExpressNode express, Word[] words) } if(balance!=0){ System.out.println(result); - throw new RuntimeException("括号匹配异常"); + throw new RuntimeException("Bracket match abnormal"); } return result.toString(); } @@ -289,14 +289,14 @@ private static String makeCondtionString(ExpressNode express,Word[] words) { int min = getMinNode(express); int max = getMaxNode(express); - //最后需要匹配一个括号的问题 + //Finally, the problem of matching a parenthesis while(max+1=words.length) max = words.length-1; StringBuilder result = new StringBuilder(); - int balance = 0;//小括号的相互匹配数量 + int balance = 0;//The number of matching parentheses for(int i=min;i<=max;i++) { if(words[i].word.equals("(")){ @@ -305,13 +305,13 @@ private static String makeCondtionString(ExpressNode express,Word[] words) balance--; } if(balance<0){ - balance++;//当前字符不合并,恢复成0,用于最终的判断 + balance++;//The current characters are not merged and restored to 0 for final judgment break; } result.append(words[i].word); } if(balance!=0){ - throw new RuntimeException("括号匹配异常"); + throw new RuntimeException("Bracket match abnormal"); } return result.toString(); } diff --git a/src/test/java/com/ql/util/express/bugfix/ArrayMapTest.java b/src/test/java/com/ql/util/express/bugfix/ArrayMapTest.java index 50f9114e2..257433488 100644 --- a/src/test/java/com/ql/util/express/bugfix/ArrayMapTest.java +++ b/src/test/java/com/ql/util/express/bugfix/ArrayMapTest.java @@ -14,7 +14,7 @@ public class ArrayMapTest { @Test public void testMinus() throws Exception{ ExpressRunner runner = new ExpressRunner(); - //负数需要加括号来解决,就好比 1+(-1) + //Negative numbers need to be resolved by adding parentheses, just like 1+(-1) String exp = "Map abc = NewMap(1:(-1),2:2); return abc.get(1) + abc.get(2)"; IExpressContext context = new DefaultContext(); Object result = runner.execute(exp,context,null,false,true); diff --git a/src/test/java/com/ql/util/express/bugfix/CheckySyntaxTest.java b/src/test/java/com/ql/util/express/bugfix/CheckySyntaxTest.java index 60748d989..d4067e39b 100644 --- a/src/test/java/com/ql/util/express/bugfix/CheckySyntaxTest.java +++ b/src/test/java/com/ql/util/express/bugfix/CheckySyntaxTest.java @@ -26,7 +26,7 @@ public void testCheckySyntax0() throws Exception{ for(String exp :expList) { ArrayList mockClasses = new ArrayList(); Assert.assertTrue(runner.checkSyntax(exp,true,mockClasses)); - System.out.println("未识别的java类列表:"+mockClasses); + System.out.println("List of unrecognized java classes:"+mockClasses); } } @@ -43,7 +43,7 @@ public void testCheckySyntax() throws Exception{ for(String exp :expList) { ArrayList mockClasses = new ArrayList(); Assert.assertTrue(runner.checkSyntax(exp,true,mockClasses)); - System.out.println("未识别的java类列表:"+mockClasses); + System.out.println("List of unrecognized java classes:"+mockClasses); } } diff --git a/src/test/java/com/ql/util/express/bugfix/ContextMessagePutTest.java b/src/test/java/com/ql/util/express/bugfix/ContextMessagePutTest.java index 30323f5ab..67d3f4c78 100644 --- a/src/test/java/com/ql/util/express/bugfix/ContextMessagePutTest.java +++ b/src/test/java/com/ql/util/express/bugfix/ContextMessagePutTest.java @@ -8,7 +8,7 @@ /** * - * @骆凡 + * @Luo Fan * Created by tianqiao on 17/7/5. */ public class ContextMessagePutTest { @@ -34,7 +34,7 @@ public void test() throws Exception{ ExpressRunner runner = new ExpressRunner(); OperatorBase op = new OperatorContextPut("contextPut"); runner.addFunction("contextPut",op); - String exp = "contextPut('success','false');contextPut('error','错误信息');contextPut('warning','提醒信息')"; + String exp = "contextPut('success','false');contextPut('error','Error message');contextPut('warning','Reminder message')"; IExpressContext context = new DefaultContext(); context.put("success","true"); Object result = runner.execute(exp,context,null,false,true); diff --git a/src/test/java/com/ql/util/express/bugfix/CrashTest.java b/src/test/java/com/ql/util/express/bugfix/CrashTest.java index c7b322a85..388b66086 100644 --- a/src/test/java/com/ql/util/express/bugfix/CrashTest.java +++ b/src/test/java/com/ql/util/express/bugfix/CrashTest.java @@ -21,15 +21,15 @@ public void helloworld() public static String[] splitWord={ - "~","&","|","<<", ">>",//位操作 - "+", "-","*", "/", "%","++", "--",//四则运算: - ".",",",":",";","(", ")", "{", "}", "[", "]","?",//分隔符号 - "!","<", ">", "<=", ">=", "==","!=","&&","||",//Boolean运算符号 + "~","&","|","<<", ">>",//Bit manipulation + "+", "-","*", "/", "%","++", "--",//Arithmetic: + ".",",",":",";","(", ")", "{", "}", "[", "]","?",//Delimiter + "!","<", ">", "<=", ">=", "==","!=","&&","||",//Boolean operation symbol "=","/**","**/" }; /** - * 版本3.0.9以下存在多线程初始化问题,这个类作为一个样例 + * There is a multi-threaded initialization problem below version 3.0.9, this class is used as an example */ public void testCrash() throws InterruptedException, BrokenBarrierException { System.out.println(Arrays.asList(splitWord)); diff --git a/src/test/java/com/ql/util/express/bugfix/ErrorColumnTest.java b/src/test/java/com/ql/util/express/bugfix/ErrorColumnTest.java index 8fd7af20a..4f71ee972 100644 --- a/src/test/java/com/ql/util/express/bugfix/ErrorColumnTest.java +++ b/src/test/java/com/ql/util/express/bugfix/ErrorColumnTest.java @@ -8,8 +8,8 @@ */ public class ErrorColumnTest { /** - * 之前的错误:java.lang.Exception: 还有单词没有完成语法匹配:22[if:line=9,col=69] 之后的单词 - * 修改后错误:java.lang.Exception: 还有单词没有完成语法匹配:22[if:line=9,col=12] 之后的单词 + * Previous error: java.lang.Exception: There are still words that have not completed grammatical matching: the words after 22[if:line=9,col=69] + * Error after modification: java.lang.Exception: There are still words that have not completed the grammatical match: the words after 22[if:line=9,col=12] * * @throws Exception */ diff --git a/src/test/java/com/ql/util/express/bugfix/ImportClassPath.java b/src/test/java/com/ql/util/express/bugfix/ImportClassPath.java index 65bc2f97d..ec17917b3 100644 --- a/src/test/java/com/ql/util/express/bugfix/ImportClassPath.java +++ b/src/test/java/com/ql/util/express/bugfix/ImportClassPath.java @@ -22,7 +22,7 @@ public void test() { result = runner.execute(exp,context,null,false,false); System.out.println(result); } catch (Exception e) { - System.out.println("SimpleDateFormat 没有定义,此处应该报错"); + System.out.println("SimpleDateFormat No definition, an error should be reported here"); //e.printStackTrace(); Assert.assertTrue(true); return; diff --git a/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskMethodsTest.java b/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskMethodsTest.java index 461ab712d..32401975e 100644 --- a/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskMethodsTest.java +++ b/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskMethodsTest.java @@ -16,10 +16,10 @@ public class InvokeSecurityRiskMethodsTest { @Before public void before() { - //系统默认阻止的方法黑名单:System.exit(1);Runtime.getRuntime().exec()两个函数 + //Blacklist of methods blocked by the system by default: System.exit(1); Runtime.getRuntime().exec() two functions QLExpressRunStrategy.setForbiddenInvokeSecurityRiskMethods(true); - //用户还可以增加一些类的方法黑名单 + //Users can also add some method blacklists QLExpressRunStrategy.addSecurityRiskMethod(InvokeSecurityRiskMethodsTest.class,"echo"); } @After @@ -49,7 +49,7 @@ public void test() throws Exception { Object r = runner.execute(express, context, null, true, false, 1000); System.out.println(r); - throw new Exception("没有捕获到不安全的方法"); + throw new Exception("Did not catch unsafe methods"); } catch (QLException e) { System.out.println(e.getCause()); } diff --git a/src/test/java/com/ql/util/express/bugfix/LoopFunctionTest.java b/src/test/java/com/ql/util/express/bugfix/LoopFunctionTest.java index 504ac7617..ec786b1a9 100644 --- a/src/test/java/com/ql/util/express/bugfix/LoopFunctionTest.java +++ b/src/test/java/com/ql/util/express/bugfix/LoopFunctionTest.java @@ -10,7 +10,7 @@ import java.util.Collection; /** - * 自定义的LoopAnd,LoopOr,LoopSet function功能 + * Custom LoopAnd, LoopOr, LoopSet function functions * Created by tianqiao on 18/2/8. */ public class LoopFunctionTest {