1.X-Meta引擎的主要类

    本文主要讲述X-Meta引擎实现的主要Java类。

2.事物(Thing)

2.1事物的类(org.xmeta.Thing)

    事物(Thing)对应的Java类是org.xmeta.Thing。事物对应的是数据模型,因此模型、事物、事物模型在这里都是同一个东西,通常我们简称事物模型为事物。

2.2事物的结构

    我们认为一个事物是由属性和子事物构成的。

2.2.1属性

    事物的属性是用key-value(键值)的方式存储的,其中属性的名称是字符串,属性的值可以是任意Java对象。

//--------属性的相关操作-----------
//设置属性,其中set和put方法作用一样
thing.set(String name, Object value);
thing.put(String name, Object value);

//获取属性
Object value = thing.get(String name)
//获取属性:带有类型转换的方法
String value =thing.getString(String name);
int value = thing.getInt(String name);
int value = thing.getInt(String name, int defualtValue);
double value = thing.getDouble(String name);
double value = thing.getDouble(String name, double defualtValue);
//其他类似的方法
xxxx value = thing.getXxx(String name);
xxxx value = thing.getXxx(String name, xxxx, defualtValue);

2.2.2子事物

    子事物是事物的子节点,用List存储。

//--------子事物的相关操作-----------
//添加子节点
thing.addChild(Thing child);
thing.addChild(Thing child, int index);

//获取全部子节点列表
List<Thing> childs = thing.getChilds();
//按照事物名获取对应的子节点列表
List<Thing> childs = thing.getChilds(String thingName);

2.3事物的行为

    事物模型认为任何事物都可以转化为动作,而动作是可以执行的程序,因此可以认为一个事物的某些子事物是它的行为。

    在X-Meta引擎里我们约定一个事物的第一个事物名为actions的子事物是事物的行为定义节点,第一个事物名为actions的子事物的子事物为具体的行为。

    其中事物名是什么见下面事物的描述,而事物的行为如何执行等见下面的动作。

2.4事物的描述

    一个事物是什么?它的结构是什么样的?它有哪些行为?我们认为可以使用描述的方法来解释,即使用一个事物去解释另一个事物,那么如果使用事物A解释事物B,那么也称事物A是事物B的描述者

    事物之间的描述关系是存放到事物的一个名为descriptors的属性里的,比如如果事物A是事物B的描述者,那么:

Thing a = new Thing();
Thing b = new Thing();

//设置事物a为事物b的描述者,其中"a"为事物a的路径
//事物的路径件下面世界(World)的文档,通过事物的路径可以访问到指定的事物
b.put("descriptors", "a");

//获取第一个描述者
Thng descritpor = b.getDescriptor();
//获取自身定义的所有描述者
 List<Thing> descriptors = b.getDescriptors();
//获取所有描述者,包含描述者的继承
List<Thing> descriptors = b.getAllDescriptors();

    在这里需要注意的是事物模型定义了事物之间的描述关系,但没有定义具体的解释方法,也就说你可以根据具体需要具体实现。

2.4.1描述者行为的继承

    由于我们认为一个事物有哪些行为也是属于描述的范畴,所以如果事物A是事物B的描述者,那么我们认为事物A可以描述事物B的行为,具体实现方法就是事物B拥有事物A的行为。

    因此描述者的一个重要作用就是行为的继承,这样描述者和被描述的事物有点类似于类和对象的关系,如果A是对象B的类,我们知道如果类A具有一个行为,那么对象B也应该是有的。

2.4.2事物名

    如果事物A是事物B的描述者,我们定义事物B的事物名为事物A。

    事物名的概念取自于类和对象,如果A是对象B的类,那么我们知道可以说B就是A,比如人是张三的类,那么我们就可以说张三是人,而人是张三的事物名。

2.4.3描述者的限制

    我们认为一个事物可以把任意事物当做它的描述者,甚至是它自己,个数也不限,并且一个事物的描述者是可以随时修改的。

    如果一个事物的描述者有多个,那么在descriptors属性里它们的路径使用英文逗号分隔的,而行为的继承的顺序则是在descriptors属性里出现的先后顺序。

2.5事物之间的继承

    一些事物在逻辑上可能拥有无限重复的子事物节点,它可以包含子事物,子事物又可以包含子事物,子子事物又可以包含子事物,可以这样无限下去,但是它们的子节点是重复的,是一种递归的重复。像这样的事物不能在计算机中直接表示,所以我们引入了继承的概念。

2.5.1继承

    我们定义如果一个事物B继承了事物A,那么在逻辑上事物B就拥有了事物A的属性和子事物。请注意这是逻辑上的拥有,并不是真的拥有,通过事物B的获取属性的方法并不会取到事物A的属性。

2.5.2继承的表示

    事物间的继承关系是用属性extends表示的,如果事物B继承事物A,那么在事物B的属性里设置事物A的路径。

Thing a = new Thing();
Thing b = new Thing();

//设置事物b继承事物a,其中"a"为事物a的路径
b.put("extends", "a");

//获取事物自身定义的继承列表
List<Thing> extendThings = b.getExtends();
//获取事物所有的继承列表,包括继承的事物的继承
List<Thing> extendThings = b.getAllExtends();

2.5.3行为的继承

    由于在逻辑上继承了事物的子事物,而一个事物的行为是由子事物定义的,因此我们认为如果事物B继承了事物A,那么事物B也拥有事物A的行为,其中行为的继承是在X-Meta引擎内部实现的。

2.5.4继承的限制

    一个事物可以继承多个事物,数量没有限制,由于继承自己没有意义,所以我们约定一个事物不能继承自己,如果一个事物继承了多个事物,那么在extends属性里用英文逗号分隔,继承行为的顺序则是按照extends里出现的顺序为优先级。

2.6描述和继承的作用

    通过描述和继承可以实现面向对象几乎全部的概念,但是可以看到在事物模型里并没有类和对象的概念,这是因为使用描述和继承不仅能够实现面向对象,还可以实现其他功能,我们不局限于类和对象就是为了还可以实现其他功能,比如XWorker的事物管理器把描述者当做事物的结构,从而实现了一套编辑事物的方法。

3.动作(Action)

    事物模型也是可以运行的,它是通过动作(Action)实现的。

3.1任何事物都可以转化为动作,而动作是可以执行的程序

    在类事物(Thing)里有一个getAction()方法用于把事物转化成动作(Action),而动作(Action)是可以执行的。

//事物到动作的转换
Action action = thing.getAction();

//动作是可以执行的,其中ActionContext是变量上下文
action.run(ActionContext actionContext)

    在这里任何事物都有getAction方法,但并不是任意事物转化后的动作执行都是有意义的,动作的执行遵循一些规则。

3.2动作的类(org.xmeta.Action)

    动作对应的Java类是org.xmeta.Action。

3.3动作执行的原理

    动作执行的原理比较简单,那就是如果动作对应的事物的事物名是JavaAction,那么认为执行的是Java代码,否则就执行对应事物的run行为。

    在X-Meta引擎里对应的代码片段是:

if(useOtherAction){
	//如果一个动作是引用其他动作的,那么执行被引用的动作 
	Bindings callerBindings = context.getScope(context.getScopesSize() - 2);
	try{
		context.push(callerBindings);
		result = outerAction.run(context, parameters, isSubAction);
	}finally{
		context.pop();
	}
}else if(isJava){
	//如果动作时原生动作,即Java动作,那么通过反射机制调用 
if(actionClass != null){
	if(method != null){
		result = method.invoke(actionClass, new Object[]{context});
	}else{
		logger.info("Java action method is null, " + getThing().getMetadata().getPath());
		}
	}
}else{
	//如果不是Java,那么调用当前动作事物的run行为,run行为有可能是自定义的也有可能是其描述者定义的 
//此方法很重要,用这个方法可以实现其他语言的支持,比如Groovy、JavaScript等脚本语言 
if(isSelfInterpretationType){
	//self类型的动作,当一个动作作为子动作时,而变量self还需要是自己,那么需要定义成此类型 
	if(attributeTemplate){
		//属性模板,动作的属性可以设置成freemarker模板,在执行时用模板生成真正的属性值 
		Thing fthing = (Thing) thing.run("processAttributeTemplate", context, (Map<String, Object>) null, isSubAction, true);
		if(fthing != null){
			fthing.run("run", context, (Map<String, Object>) null, isSubAction, true);
		}
	}else{
		result = thing.run("run", context, (Map<String, Object>) null, isSubAction, true);
	}
}else{
	//获取事物自己的行为run,然后执行 
	Thing actionThing = thing.getActionThing("run");
	if(actionThing != null){
		Action ac = actionThing.getAction();
		result = ac.run(context, null, caller, isSubAction);
	}
}

3.4变量上下文(ActionContext)

    变量上下文对应的Java类是org.xmeta.ActionContext,变量上下文的用途是变量,包括动作执行过程中的临时变量和参数等,X-Meta引擎相当于一个虚拟机,就是靠动作和变量上下文一起实现的。

    变量上下文常用的方法:

//声明变量上下文
ActionContext actionContext = new ActionContext();

//设置和读取变量
actionContext.put(String key,  Object value);
Object value = actionContext.get(String key);

//压栈和出栈操作
Bindings bindings = actionContext.push();
actionContext.pop();

//获取相对的全局变量范围
Bindings globalScope = actionContext.getScope(0);
//获取当前局部变量范围
Bindings localScope = actionContext.getScope();

//Bindings的设置和读取变量
bindings.put(String key, Object value);
Object value = bindings.get(Stirng key);

//获取状态
int status = actionContext.getStatus();

3.4.1函数和方法的调用效果

    使用ActionContext和动作可以实现函数、方法的调用效果,即在执行一个动作时可以压入一个栈得到一个Bindings,然后在Bindings中存放参数和临时变量等,然后在执行完动作时弹出此栈。

3.4.2控制语句模型的实现

    可以通过ActionContext的status实现控制语句,status的可选值有RUNNING、RETURN、CANCEL、BREAK、CONTINUE和EXCEPTION,使用status可以用事物模型实现诸如编程语言中的return、break、continue和异常的抛出和处理等。

3.5动作的调用方式

    调用动作运行一般有两种方式,一是直接运行,另一种是被当做事物的行为来运行。

    下面详细说明一下当做事物的行为来运行。

3.5.1执行事物的行为

    从事物的定义可知一个事物行为是它的某个子节点,或者是从其描述者和继承者继承的,其中事物的行为还是由事物定义的,因此可以通过事物获取到行为的定义事物,然后执行。

    事物的行为是通过doAction方法执行的,不如:

//执行事物的名为xxx的行为
thing.doAction("xxx" , actionContext);

    doAction的实现核心代码:

Thing actionThing = getActionThing(name);
Action action = actionThing.getAction();

Bindings bindings = context.push(null);
bindings.caller = this;
bindings.put("self", this);
		
try{
	return action.run(context);
}finally{
	context.pop();
}

    在这里可以看到在doAction里事物模型以self变量名放入到了变量上下文中,因此动作动作执行时就可知道是谁在调用它了。

4.世界(World)

    与事物对应的词是世界,因此X-Meta引擎使用世界(World)来管理事物,通过World可以获取到任何一个事物。

4.1世界的类(org.xmeta.World)

    世界对应的Java类是org.xmeta.World,World对象单实例的,World world = World.getInstance()。

4.2事物的分组

    为了方便管理类,事物按照ThingManager和Category分组。

4.2.1事物管理器(ThingManager)

    事物管理器对应的Java接口是org.xmeta.ThingManager,ThingManager是一个接口,作用是存储于事物到不同的介质,比如文件系统、Jar和类路径、数据库和内存中等,每一种介质都对应各自的ThingManager的实现。

    由于事物管理器是事物的第一级分组,因此事物管理器还有一个附加作用就是可以当做项目来用。

4.2.2目录(Category)

    目录接口对应的Java是org.xmeta.Category,目录是事物管理器下的具体分组,比如在文件系统下目录对应的文件目录,即可以把事物放到不同的文件目录下,以便区分。

4.3路径

    世界是唯一的(单实例),而事物也是唯一,每一个事物都是独一无二的,因此可以通过其路径来访问。

4.3.1事物的路径规则

    事物的路径是<目录> + 事物的名字,比如xworker.lang.MetaThing是在文件系统下保存的,那么xworker.lang就是相对目录xworker/lang,MetaThing + 编码类型就是文件名,比如MetaThing.xer.txt或MetaThing.xml等。

4.3.2属性和子事物的路径规则

    子路径规则如下:

/                :子事物的分隔符。
@xxx             :寻找id为xxx的子事物
@?xxx            :通过子事物的id或者name属性对比查找。
@n               :n是数字,如果没有找到标识为对应数字的子事物,那么寻找第n个子事物。
xxx@             :寻找事物名为xxx的子事物列表,如果没有返回一个空的列表,不是null。
xxx@n            :寻早事物名为xxx的第n的子事物,如果有标识为n的先返回。        
#xxx             :找名为xxx的属性。
$n                :同@n,用于区别@xxx,$n只用于找第n个子事物。

4.3.3路径的示例

World world = World.getInstance();

//获取事物
Thing thing = world.getThing("xworker.lang.MetaThing");

//直接获取子事物
Thing child = world.getThing("xworker.lang.MetaThing/@thing");

//获取属性
Object value = thing.get("#name");

//获取名为thing的第一个子事物
Thing child = thing.getThing("thing@0");

 

Copyright ©  2007-2014 XWorker.org  版权所有

沪ICP备08000575号