一种基于EMF模型的在GEF中判断创建连接线有效性的方法

简介: 结合目前比较受欢迎的 EMF(Eclipse Modeling Framework)和 GEF(Graphical Editing Framework)技术,提出了一种在图形化开发中创建连接线时普遍适用的验证方法. 最后给出了一个创建 连接线时动态 Schema 验证的例子,并根据 Schema 的定义列出创建连接线的真值表。针对该真值表的每 项进行验证,保证不符合 Schema 定义规则的模型对应的图形之间不能创建连接线,降低了 Schema 验证 和修改的复杂性。

一种基于 EMF 模型的在 GEF 中判断创建连接线有效性的方法

在 Java 中进行图形化工具的开发传统的方法是直接使用 AWT 或者 Swing,这种方法在处理图形化开 发的细节上(图形的创建/删除、放大/缩小、拖放和撤销等)一般比较复杂;图形化设计和后台模型的对 应关系都需要开发者自己定义,没有统一的标准,这样很难进行维护;AWT 或者 Swing 开发的图形界面 跟 Windows 界面的风格不一致,让一直使用 Windows 的用户很难接受。 EMF 和 GEF 技术作为 Eclipse 工程的一部分,分别用来进行模型的代码生成和图形化工具的开发。其中 GEF 简化了对图形的处理,开 发人员不必把主要精力放在图形的处理上;提供了一个基于 MVC(Model-View-Controller)结构的图形 化开发框架,有效地维持了图形和模型之间的对应关系;基于SWT,图形的风格跟Windows的一样。因此, 采用 GEF 进行图形化开发可以提高开发效率的同时保证了可扩展性。

EMF 和 GEF 介绍

EMF

EMF 是一套 Java 的框架,可以用于创建基于结构化模型的工具和其他的应用程序。对于引入的面向 对象的模型,EMF 可以帮助你快速地将你的模型转换为高效、正确和容易定制的 Java 代码。 EMF 使用 的模型定义的标准格式是 XMI(XML Metadata Interchange),有四种方式可以将你自己创建的模型转换 为XMI格式:

使用文本或 XML 编辑器直接创建 XMI 文档;

将使用 Rational Rose 等建模工具创建的模型导出,生成 XMI 文档;

使用带有模型特征注释的 Java 接口;

使用 XML Schema 来描述模型的格式。

GEF

GEF 可以方便开发者从一个现成的模型来创建一个功能丰富的图形化编辑器,提供了一个基本框架来 构建多种应用,比如说:状态图、GUI 编辑器、类图编辑器和状态机等。 GEF 包含了两个插件: org.eclipse.draw2d 和org.eclipse.gef。 其中 org.eclipse.draw2d 为显示的图形提供了布局和描述 的工具集;org.eclipse.gef 使用了 MVC 的架构,提供了控制器(比如: EditPart )来操作各个模型和 视图。

GEF工作原理

GEF 采用的是 MVC 架构,其架构图如图1所示。GEF一般和 EMF 结合使用,EMF 负责生成模型。MVC 的各个部分都是树状结构的,并且是一一对应关系。其中 EditPart 充当控制器的角色,里面可以使用各 种 EditPolicy,而 EditPolicy 的具体实现有时需要调用 Command 工具集类;而通过 draw2d 绘制的图 形充当视图的角色。 具体的工作流程为:

EditPartFacTory 会针对每个模型创建一个对应的EditPart;

在每个 EditPart 内部会创建与模型对应的视图,即显示的图形;

当模型的属性改变后,会通知 EditPart 它的属性变化情况;

EditPart 会根据模型属性的变化更新视图的显示;

当需要在模型间建立某种关联关系时,用 Command 在两个图形间建立一条连接线。该连接线也是一个 模型,所以针对该连接线的一些操作可以重复以上1)—4)步。

当图形化设计完后进行保存,后台调用的是 EMF 的保存机制,将各个模型和它们之间的关系保存成 EMF 自定义的 XMI 格式(各个模型保存时是并列的结构,它们之间的关系是通过属性来标识,具体的关 系要在设计时确定)。 这个 XMI 文件一般作为一种中间格式来保存,当我们想要按照自己的格式来保存 各个模型和它们之间的关系时(比如说树状结构),最好的办法就是对 EMF 保存的 XMI 文件进行二次 XML 处理。

图 1. GEF 的 MVC 架构图

连接线创建时的验证方法

在使用图形化来设计工作流的时候,为了把具体的流程和逻辑表现清楚,需要在不同的模型之间建立 关联关系,通常的方式就是在模型对应的图形之间创建一条连接线(连接线本身也是一个模型,代表了某 个特定的关联关系)。关联关系可以是多种多样的,比如说一对一、一对多、多对多等。 如图2所示,模 型 A 同时跟三个模型 B1、B2 和 B3 建立了连接(假定均为一对一的关系)。每条连接线都有起始端和 目的端,当创建一条连接线时,连接线两端对应的模型都要进行添加连接线的操作。在建模的时候,对于 每个模型都允许从其引出一条连接线或者作为连接线的终点,而连接线是保存在模型内部的一个集合中。 连接线的创建是在一个 Command 里面实现的。 Command 是 GEF 里包含的一个基类,提供了重新执行、 撤销执行和执行条件判断等操作。

图 2. 一般的连接线创建

由 EMF 生成的模型对应的 Java 代码有着特定格式的。 假设有模型 A、B1、B2 和 B3,模型A 和 B1 、B2、B3 的关系分别为一对一、一对多和多对多。 每个模型分别对应着两个类(一个接口、一个接口实 现类)。 比如模型 A对应着 interface ModelA 和 class ModelAImpl(此处用的是假设的类名)。 图3 为 EMF 生成模型的类图。可以看出,当模型间的关系不同时,其对应类的成员方法是有规律可循的。A 和 B1是一对一的,对应的 ModelA 类就含有ModelB1 getModelB1( ) 和void setModelB1(ModelB1)方法 ;而 A 和 B2 是一对多的,ModelA 类就含有 EList getModelB2( ) 方法。

图 3. EMF 生成模型的类图

在创建连接线之前先定义好不同的连接线分别代表的关联关系(一对一、一对多和多对多)。在创建 某种连接线时,根据该连接线代表的关联关系,分别对连接线两端模型对应的类进行上面所述的方法验证 ,如果符合的话,就允许创建该连接线,否则,撤销刚刚建立的连接线。

一个 Schema 验证的例子

该部分给出了一个通过 Schema 定义来验证连接线有效性的例子。 可以直接使用 EMF 导入Schema 文 件,Schema 文件中定义的各个复杂类型和其元素都被生成对应的模型,模型间的关系和 Schema 文件中 定义的一样。图4是一个定义复杂类型 A 的 Schema 文件,可以看出类型 A 里面包含 B1、B2、 sourceConn 和 targetConn 元素和 a 属性。 当编写一个 xml 文档用到 A 标签时,它的后继标签只能 是 B1、B2、sourceConn 和 targetConn。同时通过 Schema 文件里对各个元素最大出现次数属性 maxOccurs 的赋值可知:B1 的出现次数最多只能是一次,而其它标签可以出现任意多次。 如果 A 的后 继标签中出现了 B3 之类的标签时,将不能通过 Schema 的验证,说明该 xml 文档是非法的。

图 4. 复杂类型 A 的 Schema 文件内容

我们定义连接线代表的关联关系是:连接线发起端和目的端的模型分别对应的标签符合 Schema 中的 定义。 假如现在有四个图形分别对应着模型 A、B1、B2 和 B3。 如果在它们之间建立连接线的时候,想 让连接线目的端模型 B1 作为发起端模型 A 的子模型,即后台保存的 XMI 文档中,B1 对应的标签是作 为子标签嵌套在 A 对应标签里的,这时就需要用Schema 验证该 XMI 文档的合法性。现在想在创建连接 线的时候进行动态的验证,即如果连接线发现目的端和发起端对应的模型不符合 Schema 中的定义时,该 连接线就不被创建。由于B3 不是 A 的元素,所以在 A 和 B3 之间创建连接线时该连接线就不能创建, 如图5所示。

图 5. A 和 B3 不允许建立连接

图4 Schema 文件中复杂类型 A 对应的模型生成的 Java 类中有 interface AType 和 class ATypeImpl(此处为真实的类名)。当规定元素 B1 的最大出现次数为1的话,则在 interface AType 和 class ATypeImpl 中会有相应的 void setB1(B1Type) 和 B1 getB1( ) 方法;若元素B2 的最大出现次数 不限的话,则在 interface AType 和 class ATypeImpl 中会有相应的 EList getB2( )方法。

另外,类型 A 里面包含了元素 sourceConn 和 targetConn。 在 interface AType 和 class ATypeImpl 中会有 EList getSourceConn( ) 和 EList getTargetConn( ) 方法。这两个方法是为了维护 从 A 出发或者结束到 A 的连接线。

表1中列出了 A 和 B 之间是否允许创建连接线的真值表,可以很清楚地看出满足什么条件下 A 和 B 之间才可以建立连接线。 本文的最后给出了对连接线进行 Schema 验证的详细步骤。

表 1. 创建连接线真值表

首先建一个 ConnectionCreateCommand 类,内部创建一个成员方法 boolean validateConnection( ) ,该类继承了 GEF 的 Command 类。根据以上的真值表,把验证过程分为三个部分:判断 A 是否包含 B 、判断 A 和 B之间是否存在连接线、判断 B 在 A 中出现的次数限制。

判断 A 是否包含 B

获取连接线两端的模型对应的Java类,即 ATypeImpl 和 BTypeImpl;

获取 ATypeImpl 类(包括其父类)的所有方法名中包含 “set” 或者 “get” 字符串的成员方法集 合,并循环判断方法集合中是否含有 “void setB(B)” 或者 “EList getB( )” 方法;

如果2)中的条件成立则说明 A 包含 B,否则说明 A 不包含 B。

判断 A和 B之间是否存在连接线

在 ATypeImpl 中调用 getSourceConn( ) 方法返回一个从 A 出发的连接线的集合;

获取该集合中的每个元素(连接线),判断其目的端对应类的名称是否为 BTypeImpl;

如果2)中的条件成立则说明 A 和 B 之间已经存在连接线,否则说明不存在连接线。

判断 B在 A中出现的次数限制

同 “判断 A是否包含 B” 中的一样,获取 ATypeImpl 类(包括其父类)的所有方法名中包含 “set ” 或者 “get” 字符串的成员方法集合;

循环判断方法集合中是否含有 “void setB(B)” 或者 “EList getB( )” 方法;

如果含有 “void setB(B)” 方法,说明 B 在 A 中最多出现一次;

如果含有 “EList getB( )” 方法,说明 B 在 A 中可以出现多次。

由以上三个判断,并且参照表1,可以确定 A 和 B 之间是否可以创建连接线,即确定 validateConnection( ) 方法的返回值。 在 ConnectionCreateCommand 的回调函数 execute( ) 中判断 validateConnection( ) 方法的返回值,如果为 false 的话,则不创建该连接线;反之如果为 true 的 话,则创建该连接线,并且

在 ATypeImpl 中调用 getSourceConn( ) 方法返回一个从 A 出发的连接线的集合,然后向该集合中 添加一个刚才创建的连接线;

在 BTypeImpl 中调用 getTargetConn( ) 方法返回一个目的点是 B 的连接线的集合,然后向该集合 中添加一个刚才创建的连接线。

这样整个验证过程就结束了,保证了后台生成的 XML 文件的规范性。

结束语

本文在 GEF 和 EMF 来进行建模和图形化开发的基础上,提出了对创建的连接线有效性验证的方法。 将其用于业务流程设计中能提高规范化设计的效率。 由于本文中所讨论的模型都是由 EMF 导入的,具体 的验证方法也都是依赖于 EMF 生成的 Java 代码的特定格式,因此如果模型对应的 Java 代码采用其它 的格式时,该验证方法就不能适用。如何提出一种通用的连接线验证机制有待于更进一步的研究。

含泪播种的人一定能含笑收获。

一种基于EMF模型的在GEF中判断创建连接线有效性的方法

相关文章:

你感兴趣的文章:

标签云: