1.X-Meta引擎的主要类

    X-Meta引擎是动态模型的实现,几个主要的Java类如下。

2.事物(Thing)

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

    在X-Meta引擎里模型叫做事物(Thing),对应的Java类是org.xmeta.Thing。通常在X-Meta引擎里模型、事物、事物模型在这里都是同一个东西。

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.事物的名字和事物名

    一个事物的名为name属性的值是它的名字,而一个事物的描述者的名字是它的事物名字。

    在这里事物名相当于对象的类名,比如事物A是事物B的描述者,那么事物B的事物名是A。

2.4.2.描述行为

    在动态模型里,描述者可以起到描述行为的作用。比如事物A是事物B的描述者,那么通过事物A可以知道事物B的部分或全部的行为。

    具体实现方法是事物继承它的描述者的行为。比如事物A是事物B的描述者,如果事物A拥有一个名为sayHello的行为,那么事物B也有一个名为sayHello的行为,虽然事物B自身没有定义名为sayHello的行为,sayHello行为是从事物A继承的。

2.4.3.描述属性和子事物

    在动态模型里,描述者可以起到描述属性和子事物的作用。比如事物A是事物B的描述者,那么通过事物A可以可以知道事物B的部分或全部的属性和子事物,

2.4.4.描述者的限制

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

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

2.5.事物之间的继承

2.5.1.继承

    在动态模型里,一个事物可以继承除自身外的其它事物,从而拥有被继承事物的行为。比如事物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.描述者之间的继承

    如果一个事物是描述者,这时它起到描述其它事物的结构(属性和子事物)和行为的作用,而如果它也继承了其它事物,则它也继承被继承的事物所描述的结构和行为。

    比如Person是一个模型,它继承了Animal这个模型,而Tom是Person的实例,此时如果Animal定义了一个名为age的属性,那么Tom也就有age的属性,在这里Person继承了Animal的age属性的定义。    

2.5.4.继承的限制

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

2.6描述和继承的作用

    通过描述和继承可以实现面向对象几乎全部的概念,但是可以看到在事物模型里并没有类和对象的概念,

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-2019 XWorker.org  版权所有  沪ICP备08000575号