首页 > 代码库 > Apache OFbiz MiniLang 源码解读

Apache OFbiz MiniLang 源码解读

MiniLang所有元素的父类——MiniLangElement

MiniLang 是基于XML的“描述型语言”。所有的元素,包括节点、属性都继承自该类。它包含三个属性:


  • lineNumber:表示解析MiniLang的源码(通常是Java)所处的行号,主要是为了便于日志记录
  • tagName:当前元素的tag名称,主要用于日志记录
  • simpleMethod:simpleMethod是一个大的“传输对象”,里面实现了MiniLang支持的所有执行方式,其作用类似于serviceengine中的serviceDispatcher。
该类中没有太多的功能代码,除了outputTraceMessage。它用于记录跟踪日志消息,以上提及的两个属性(lineNumber/tagName)主要用在这里。

对应于服务引擎的实现——SimpleServiceEngine

在之前一篇关于ofbizservice engine的剖析中,我们谈到了里面也有minilang相关的一个执行引擎,其实就是此处的SimpleServiceEngine。它继承了GenericAsyncEngine(这里继承的语义并不是is-a的关系,主要是代码复用,因为GenericAsyncEngine实现了runAsync,而其他的子引擎都没必要实现这个接口方法)。
SimpleServiceEngine的继承关系图:

SimpleServiceEngine实现了父类中的两个抽象run方法:


但这两个方法都不包含主要的实现逻辑,真正的逻辑被定义在私有方法:serviceInvoker中,它最终是通过SimpleMethod的静态runSimpleService方法来执行的。

BeanScript的引擎实现——SimpleMethodBsfEngine

准确来说,它是对IBM的Beanscripting 库的适配器。用于在minilang中调用Beanscript。它实现了如下方法:

其中apply以及call未提供实现(抛出异常),它在内部维护了一个上下文对象,用来存放BSFDeclaredBean,而该上下文对象用于为SimpleMethod的执行提供另一个上下文。维护上下文对象通过如下两个方法:
  • declareBean
  • undeclareBean
方法执行的主要逻辑实现位于eval中。它通过方法参数找到SimpleMethod对象,然后构造执行的上下文对象,调用SimpleMethod对象的exec执行。

MiniLang真正的执行者——SimpleMethod

SimpleMethod继承自MiniLangElement,说明它也是MiniLang中的一个元素。SimpleMethod包含了很多跟执行任务相关的代码:

当然这些方法大多是应对MiniLang可以应用场合的重载,可以看到它可以应用于简单方法、事件以及服务。最终真正的执行方法是exec方法。
当然还有一些方法是静态帮助方法。比如readOperations,它返回当前元素所有子元素所被代表的MethodOperation实例的集合,(关于MethodOperation后面会讲到,每个minilang节点都最终被影射为一个MethodOperation,由Java解释执行)。

验证检查器——MiniLangValidate

由于MiniLang是采用xml来描述任务的“语言”,因此它并不具备编程语言的很多编译检查机制。所以它采用了一些辅助方法来进行检查:包括了验证属性、验证子元素、测试元素是否为空若为空设置默认值、测试某属性是否为常量值等、是严格模式还是宽松模式以及错误处理等等

MiniLang的帮助类——MiniLangUtil

该类是MiniLang的帮助类,提供了一些方法:调用SimpleMethod的方法、类型转换/获取的方法、设置MiniLang内容的方法等

字段验证及转换器——SimpleMapProcessor

SimpleMapProcessor从上下文对象中获取到字段信息,然后进行验证以及转换(当然真正的验证以及转换逻辑并不是由他来实现的,它只是起到触发动作),然后将验证通过的字段放入目标集合中去。MiniLang会定义很多这样的MapProcessor,而SimpleMapProcessor主要用于获取这些所有的mapProcessor(内部获取,不对外公开)然后运行他们:

对于所有的mapProcessor,SimpleMapProcessor支持两种缓存,一种是基于字符串xmlResource作key的缓存,一种是基于URLxmlURL为key的缓存。而所有的runSimpleMapProcessor都是先获取到mapProcessor集合中特定的mapProcessor,然后调用其exec方法来执行验证以及转换动作(后面会有介绍)。

操作描述的基类——SimpleMapOperation

MiniLang中提供了很多的operation,而所有这些operation都继承自SimpleMapOperation这个抽象类:


SimpleMapOperation的构造方法接收两个参数:
  • element:一个xml元素
  • simpleMapProcess:SimpleMapProcess类的实例
构造方法中还初始化了一些参数,比如failMessage、failProperty等。
另外提供了一个方法addMessage,它用于结合failMessage、failProperty,以提供更加完善的错误信息。另一个很重要的方法exec被标记为abstract,以待子类的实现。

字符串参数综合处理器——SimpleMapProcess

该类是MiniLang中参数的综合处理器。它包含一个readOperations方法,用于遍历当前节点的所有子节点,分别对这些子节点的节点名称进行匹配并生成各种不同的SimpleMapOperation的实例,然后加入到集合中去。
而该类也提供了一个exec方法,它遍历所有的处理器,一个一个得对它们运行各处理器自己的exec方法以完成相应的处理。

提供比较操作的基类——BaseCompare

MiniLang中有很多操作是比较操作,而BaseCompare就是执行比较的抽象基类,从上图很明显看出它继承自SimpleMapOperation。
在构造函数中,它从参数element中提取三个属性:
  • operator: 比较操作符
  • type: 比较的对象类型
  • format:格式
另外还有三个方法:

  • doRealCompare是真正用于比较的静态方法,它依赖于ofbiz的其他实现,返回bool值的比较结果
  • doCompare调用doRealCompare获得比较结果,如果结果为false,则调用SimpleMapOperation的addMessage方法,添加失败信息
  • exec:空实现,这是符合语义的,因为这只是个compareoperation

值比较器——Compare

该类提供对输入参数的比较功能。在构造函数中,它提取该元素的value属性,作为要比较的对象之一。
该类对exec方法的实现为:
从方法参数inMap(MiniLang执行所需的所有传入参数的集合)中获得某个fieldName的值(此处fieldName,正是SimpleMapProcess当前正在处理元素中提取出来的)作为另一个比较对象,然后调用BaseCompare的doCompare进行比较。

字段比较器——CompareField

上面的Compare提供某个参数的值跟MiniLang定义的某个元素的值进行比较。而CompareField提供某个参数的值跟MiniLang定义的某个字段的参数值进行比较,这个听着比较绕口,看看代码就明白了:
Compare:
public Compare(Element element, SimpleMapProcess simpleMapProcess) {
        super(element, simpleMapProcess);
        this.value = http://www.mamicode.com/element.getAttribute("value");>
CompareField:
public CompareField(Element element, SimpleMapProcess simpleMapProcess) {
        super(element, simpleMapProcess);
        this.compareName = element.getAttribute("field");
    }

    @Override
    public void exec(Map<String, Object> inMap, Map<String, Object> results, List<Object> messages, Locale locale, ClassLoader loader) {
        Object compareValue = http://www.mamicode.com/inMap.get(compareName);>

MiniLang的拷贝操作——Copy

该类提供将一个参数从输入参数列表拷贝到输出参数列表。在构造方法中,获取元素需要拷贝到的目标key,并获取是否替换以及如果为null则设置相关的配置。exec方法中主要实现拷贝动作。

对字段的非空检测——NotEmpty

该类用于检测当前字段是否为非空(null或者空字符串),如果为空则设置错误信息。示例:
<not-empty>
            <fail-property resource="AccountingUiLabels" property="AccountingCardNumberMissing"/>
        </not-empty>

MiniLang的类型转换器——Convert

Convert类用于转换某个处于输入参数集合中的参数然后将其放入输出参数集合。在构造方法中,它先获得要处理元素的“to-field”属性,然后获得要转换的类型。在exec中,获取要转换的对象,进行转换并放入输出参数集合

MiniLang的正则表达式验证器——Regexp

Regexp用于正则表达式验证,从处理元素中获取expr属性,然后在exec方法中,先将当前字段转换为String,然后对其进行正则匹配。

MiniLang的验证方法调用器——ValidateMethod

minilang支持对字符串调用指定的验证方法进行验证,形如:
<validate-method method="isAnyCard" class="org.ofbiz.base.util.UtilValidate">
            <fail-property resource="AccountingUiLabels" property="AccountingCardNumberIncorrect"/>
        </validate-method>

在构造方法中,它先去获取该元素的method属性以及class属性。其exec方法,先获得该字段的值,然后将其转换为String类型,获得当前线程的classloader,加载该类,获取该方法(值得一提的,这里只支持静态方法)。因为在用反射调用该方法的时候并没有传入该类的实例。

字符串输入参数生成器——MakeInStringOperation

MiniLang支持根据配置生成特定的字符串值作为一个输入参数,这里涉及到几种不同的字符串生成操作类型: