本文介绍了EMF(Eclipse Modeling Framework),给出了用EMF开发Eclipse插件的一般步骤。
使用的软件及插件版本
Eclipse 3.1、
什么是EMF?为什么我们要用EMF?
EMF用于定义和实现结构化数据模型。所谓数据模型就是用来处理应用中需要处理的数据的一组相关类。
使用EMF的好处
1. 代码生成。根据模型的定义生成可用数据模型的所有代码。EMF依照模板文件生成容易阅读的代码,模板文件可以定制。你可以修改所生成的代码,并且重新生成类时会保留所做的修改。生成代码需要的是Rational Rose模型文件,批注Java接口或XML schema 定义(开发中)
2. 元数据。你可以用程序查询模型结构,得到比标准的Java BeanInfo或反射更多的信息。EMF还支持访问和更新模型。
3. 缺省序列化。EMF可以从XMI文件装载模型实例,也可以保存模型实例到XMI文件(XMI文件是一种XML格式的文件)。你也可以保存到不同格式的文件。文件格式XML schema还在开发中。
4. 文件之间的连接。你可以保存和编辑多个文件中的数据
5. 编辑器。EMF还会生成一个模型编辑器,还有一个反射编辑器,只用模型的元数据就可以浏览和编辑EMF模型文件。
用EMF开发Eclipse插件
下面以family tree编辑器为例,给出用EMF开发Eclipse插件的一般步骤
第一步:设计模型
第二步:定义模型
你可以使用Rational Rose创建模型,EMF可以直接从mdl文件生成代码。
也可以从批注Java接口生成代码。
1. 在Eclipse中创建Java工程文件和包文件,工程文件名是com.ibm.example.familytree ,包文件名是com.ibm.example.familytree。
2. 在包中创建Java接口FamilyTree和Family。在每个接口的Javadoc批注中增加一行@model。这行告诉EMF这个接口是模型的一部分。
3. Individual也需要一个Java接口,因为Individual是一个抽象类,在Javadoc批注中增加一行@model abstract=”true”。
4. 创建接口Male和Female,它们继承了Individual,增加@model批注
定义属性
Individual有name,因此需要向Individual接口增加属性“name”。增加方法如下:/**
* Return the individuals name.
* @return the name
* @model
**/
String getName();
定义简单引用
Family应当引用mother和father。增加下面的方法到Family接口:
/**
* Return the father
* @return the father
* @model
**/
/**
* Return the mother
* @return the mother
* @model
**/
Female getMother();
注意到方法 与属性的定义非常类似 。
定义包含关系
在上面的UML模型中,黑箭头连线是包含关系。例如,Individual即可以备Family包含,也可以被FamilyTree包含。一个对象只能有一个包含者。例如,前面定义的Family和Individual之间的关系不是包含关系---因为一个人可以多次结婚。
当用EMF生成的编辑器创建这个模型的实例时,将只有一个顶层FamilyTree对象,它直接或间接地包含了模型中的所有其它对象。如果有对象没有包含者,模型就不能正确保存。
为了定义包含关系,向FamilyTree中增加下面的方法:
/**
* Return a list of contained families
* @model type="Family" containment="true"
**/
java.util.List getFamilies();
/**
* Return a list of contained individuals
* @model type="Individual" containment="true"
**/
java.util.List getIndividuals();
与前面定义的简单引用不同,这些方法返回的是Lists。这是因为FamilyTree可以包含多个Family和Individual。返回的类型必须是java.util.List或org.eclipse.emf.comm.on.util.Elist,这样EMF就知道这是多值的。注意到@model标记 声明了可以出现在List中的对象类型。此外,Containment=”true” 表明这是一个包含关系。
Family中还有一个包含关系要定义:
/**
* Return children
* @return list of child Individuals
* @model type="Individual" containment="true"
**/
java.util.List getChildren();
第三步:生成模型
现在已经定义好了模型,可以生成模型的实现了。
1. 在File菜单中,选择New>Other…
2. 在New File向导中,选择Eclipse Modeling Framework>EMF Model,点击Next按钮
3. 在接下来的页面上选择目录com.ibm.example.familytree,输入文件名后点击Next按钮
4. 在Model Importers列表框中选择Annotated Java,点击Next按钮
5. 在接下来的页面中,Root packages列表框中应有familytree包,点击Finish按钮
6. 新生成了两个文件,一个是familytree.ecore(这是一个包含了family tree模型定义的XMI文件);另一个是genmodel文件,这个文件包含了EMF如何生成模型代码的其它信息。Genmodel文件已经在编辑器中打开,可以编辑。
7. 在编辑器中,选择根节点,右击弹出菜单
8. 选择Generate Model Code菜单项生成模型的实现代码
工程文件中增加了两个新的包com.ibm.example.familytree.impl 和com.ibm.example.familytree.util。在原来的包com.ibm.examplee.familytree中增加了两个新接口FamilytreeFactory和FamilytreePackage,这两个接口分别用于通过编程创建模型元素和查询元数据。同时,EMF对包中的其它接口也作了一些修改
第四步:生成编辑器
genmodel编辑器的弹出菜单中有五个选项
l Generate Model Code
l Generate Edit Code
l Generate Editor Code
l Generate Test Code
l Generate All
选择Generate Edit Code和Generate Editor Code创建两个新的插件工程文件com.ibm.example.familytree.edit 和 com.ibm.example.familytree.editor。
第五步:试用所生成的插件
所生成的编辑器可以作为开发应用的起点。但是,请不要立即开始开发工作。首先用所生成的编辑器检查一下你的数据模型是否能够处理一些样本数据。如果发现问题,可以重新设计数据模型,重复前面的过程,直到你满意为止。现在修改模型比在编辑器中做了许多工作后再修改模型要容易得多。
要测试所生成的编辑器,打开plugin.xml文件,在多页编辑器的Overview页面上点击Launch an Eclipse application启动另一个Eclipse实例。在新的Eclipse实例中
1. 新建Java工程文件test
2. 选择菜单File>New>Other…
3. 选择Example EMF Model Creation Wizards>Familytree Model,然后点击Next
4. 在出现的页面上选择所建的工程文件test,输入扩展名为familytree的文件名,然后点击Next
5. 在出现的页面上的Model Object列表框中选择FamilyTree,然后点击Finish
新建的文件已用多页编辑器打开,在Selection页面上你会看到FamilyTree节点。右击FamilyTree节点会弹出菜单,允许你增加子节点---Family、Female或Male
。
选择Family Tree节点增加子节点---Female或Male,在Properties view中设置属性Name的值,增加子节点Family,在Properties view中选择属性Father、Mother
的值。选择Family节点增加子节点---Female或Male,在Properties view中设置属性Name的值。结果如下图所示:
当你在Family中增加children时,它们是树中Family节点的子节点。你可以在Properties view中选择Family的属性Father、Mother的值,但不会改变树,因为mother和father与family联系,但不被family包含。
了解EMF编辑器
修改模型
例如,为了向Individual增加desription属性,在Individual接口中增加如下的方法:
/**
* Return a description.
* @return a description
* @model
**/
String getDescription();
然后,需要更新genmodel文件。选择genmodel文件右击,在弹出的菜单中选择Reload…。然后重新生成代码。如果你修改了所生成的代码,为了在重建代码时保留你所做的修改,就要移除@generated标记。