用模型驱动Eclipse开发 ( by quqi99 )

用模型驱动Eclipse开发 ( by quqi99 )

EMF(Eclipse Modeling Framework)是一个模型架构和代码生成工具,它可以用来建构以结构化数据为基础的工具或者应用。作为MDA和Eclipse的结合体,它发展迅速,IBM的大部分工具产品如RSA等都将建立在它的基础之上。

样例

我们将构建一个简单的手机库管工具,它只维护种类信息,并不存储数量库位等。通过该工具,我们可以添加,删除,修改主机及配件;维护主机,配件的功能;并且可以通过拖放将主机和相关配件组成一种配置。

 建立模型

 EMF通过JET和JMERGE来实现支持MDA,它可以从annotated Java, UML, or XML Schema三种模型生成Eclipse plug-in代码。我们将用Rational Rose建立UML模型来作为系统模型。


  图1:简单的手机库管工具的UML模型表示

将模型导入Eclipse中

建立EMF工程,在Wizard中会提示选择初始化的模型内容。从Rose中读取类模型以后,将生成了一个工程,其中包含两个文件:.ecore和.genmodel。

Ecore文件代表我们的模型本身,你可以通过修改它来改变模型。比如改变属性的类型,类之间的关系等。你也完全可以通过手动的方式建立ecore文件来创建整个模型。我们可以看到,在ecore模型中,所有的类被转换为EClass;聚合关系变成了一个EClass包含其它EClass作为EReference,例如主机、配置、配件都作为库存的EReference。在这里,我们需要修改EReference的Containment属性,缺省的值是false。Containment属性是在持久化时的一个重要属性,它表明存储时数据的包含关系,如果全部保留为fasle,将不会有任何信息被存储到文件中,除了顶级节点:库存。应该以谁创建,谁包含为原则。比如库存可以创建主机、配件、配置,那么这些库存的EReference的Containment属性都应该设为true;而配置并不负责创建主机和配件,只是从库存中现有的主机和配件拖放过来的,那么它下面的主机,配件EReference的Containment属性都应该为false。

 以XMI存储为例,修改后存储的格式应该为:

<?xml version="1.0" encoding="UTF-8"?>
<mobiles:库存 xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:mobiles="http:///mobiles.ecore">
<配置 配件="//@配件.0" 主机="//@主机.0"/>
<配件>
<功能/>
</配件>
<主机>
<功能/>
</主机>
</mobiles:库存>

Genmodel文件主要维护着一些与生成代码相关的设置,比如说,某个属性可不可以修改。大部分的属性都不用修改,我们要决定的仍然是EReference的属性:Children,Create Child,Notify。

Notify是表明它应不应该将在这个包含节点中有关自身的改变通知给其它的相同节点。比如某个主机V3在库存中创建之后被拖到某个配置里,这样在整个树上就存在两个V3:一个是V3本身,另一个是它的一个引用。如果将配置中主机的Notify属性设为true后,改变配置中引用的V3价格,它就会把这个改变通知给V3自身,实现同步。通常情况下应将所有的EReference的Notify设为true。

按照下表做出设置:

包含节点 EReference Children Create Child Notify
库存 主机
配件
配置 True True True
主机 功能 True True True
主机 配件 True False True
配件 功能 True True True
配置 主机
配件 True False True

生成代码并运行

用EMF generator(缺省的Eidtor)打开genmodel文件,原来的工程中会生成Model代码,两个新的工程Edit和Editor工程会被生成, Edit工程包含了一些方便编辑Model的代码,Eidtor工程中大都是UI部分的代码,不在本文范围之内。

.mobiles文件生成后,将会用Mobiles Model Editor打开。现在就可以在库存中添加主机配件等,并将其拖到某个配置中去。这里所谓的Mobiles在缺省情况下与你的Rose文件的名字相同,在Editor工程的Plugin.xml的editor扩展中可以看到生成的后缀。



 Model Plug-in

EMF是从作为MOF规范在Eclipse的一个实现开始的,随后通过大量的运用在工具的实现,EMF成为一个有效的MOF API的一个核心子集的Java实现。EMF中的元数据被称为Ecore。


 灰色的类代表抽象类,所有的类都继承自Eobject。EPackage包含关于模型类(EClass)和数据类型(EDataType)的信息。EClass描述一个建模的类,并且指定属性和参考以描述实例的数据。EAttribute描述简单数据,它由一个EDataType来指定。EReference描述一个类之间的关联;它的类型是一个Eclass。EFactory包含创建模型元素的方法。更多的关于Ecore的描述请参考Eclipse官方网站。
包和工厂
前面说过EPackage包含所有关于EClass和EDataType的信息,参看生成的代码mobiles. MobilesPackage,可以看到Eclass的feature ID声明:

int 主机 = 0;
 int 配置 = 1;

feature ID仅仅是对所有的类元素(不包含类型信息)的一个int类型的编号,有了它可以使你很快的区分出是哪个类的哪个属性。例如在某个类的属性值发生改变后,它的监听者会收到一个通知,通知里就包含了改变了的属性的feature ID,这时你就可以简单的通过一个switch方法来实现分派。

MobilesPackage中另外的一些是关于类型的,例如:

EClass get主机();
 EAttribute get主机_Name();

在某些情况下这些元数据是非常重要的,比如在决定某个属性的编辑框类型的时候。当然你也可以直接调用某个类型的create方法来创建对象:

适配器

EMF最重要的一个特性就是它对Adapter的定义。在EMF中Adapter有两个功能,第一个是类似于Observer的功能,它可以监听目标对象的变化然后做出相应的反映;另一个是通过它可以使目标对象不用继承某个接口或者父类来实现其特有的功能。这一节我们会结合Model Plug_in的代码来探讨Adapter的这两个功能。

Observer

通常的Observer模式需要至少两个类,监听者和目标对象。EMF中,监听者称为Adapter,目标对象称为Notifier。每个Notifier都拥有一个eAdapters列表,维护着所有监听者的类型,一旦Notifier发生变化,它会遍历eAdapters列表将变化通知给列表中的每一个Adapter。所以假如某个Adapter想要监听这个Notifier,只需要将自己添加到Notifier的eAdapters中。

EMF中所有的对象都直接或间接继承自Eobject,如同java中所有的类都继承自Object一样。而Eobject类已经实现了Notifier接口,所以所有的EMF的类都可以是Notifier。

Adapter需要自己来实现AdapterImpl,需要实现的方法主要有两个,isAdapterForType和notifyChanged。IsAdapterForType是用来判断这个Adapter能不能监听某个Notifier,notifyChanged包含着一旦Notifier发生了变化这个Adapter所要做出的所有相应。假设我们需要一个Adapter,它来监听主机的变化,一旦任何关于主机的增删改操作产生就将改变记录在本地文件中。

Notification类是由Notifier发出来的,它包含着发出者getNotifier(),改变之前的旧值getOldValue()和改变后的新值getNewValue()。象如下示例这样使用这个Adapter:

主机 machine= MobilesFactory. EINSTANCE. create主机();
 主机Adapter adapter = new主机Adapter();
 machine.eAdatpters().add(adapter);
 machine.setName(“V3”);

你要自己实例化Adapter,并且把它添加到Notifier的eAdaters里去。假如在其它的某个地方你有同样的需求,但你不确定“主机Adapter”是否已经被添加到“主机”的eAdatpters里了,你就需要遍历现有的adapter,来判断是否已被添加。然后决定创不创建新的“主机Adapter”。事实上EMF提供了AdapterFactory来简化你的工作。可以参照生成的代码mobiles.util. MobilesAdapterFactory.java。它只是一个框架,用来根据Notifier的类型生成相应的Adatpter并将其注册到Notifier的eAdapters列表中去。它还借用了MobilesSwitch类的分派功能。

 MobilesSwitch只做了一件事情,那就是根据Notifier的类型调用不同的case*方法。例如,如果Notifier是“主机”,它会去调用case主机()方法。MobilesAdapterFactory中则实现了case主机()方法,调用create主机Adapter()来创建“主机Adapter”。

继续上面的例子,我们实现一个AdapterFactory:

public class MobilesAdapterFactoryImpl extends MobilesAdapterFactory{
public static MobilesAdapterFactoryImpl
INSTANCE = new MobilesAdapterFactoryImpl ();
public Adapter create主机Adapter() {
return new主机Adapter();
}
}

用的时候就很简单:

主机 machine= MobilesFactory. EINSTANCE. create主机();
MobilesAdapterFactoryImpl.INSTANCE.adapt(machine, 主机Adapter.class);
machine.setName(“V3”);

factory会遍历machine的eAdapters,如果没有“主机Adapter”则创建一个添加进去,否则返回已有的。

行为扩展
 我们把日志功能提取出来,成为一个类:

public interface Logger{
public void log();
}

其实我们希望的是“主机”也能有日志功能,可以在自己改变之后将变化记录下来。以往我们要做的就是让“主机”继承Logger,然后实现log()方法记录下自己这种特定类型的信息。但有的时候通过继承来扩展行为并不是那么舒服,比如继承的关系是死的,你不能在你不需要的时候去掉这些扩展行为。通过Adapter你可以随心所欲的控制这些扩展行为。

public class 主机Adapter extends AdapterImpl implements Logger
{
public void notifyChanged(Notification notification) {
if (notification.getNotifier() instanceof 主机)
log();
}

public boolean isAdapterForType(Object type) {
return type == 主机.class;
}
public void log(){
//log the name, band,year,changed property name and its old value and new value
}
}

用的时候同上边一样:

主机 machine= MobilesFactory. EINSTANCE. create主机();
MobilesAdapterFactoryImpl.INSTANCE.adapt(machine, 主机Adapter.class);
machine.setName(“V3”);

这个时候任何“主机”的变化都会引起“主机Adapter”执行扩展了的log()方法,这一点与AOP很像。

Model Class

 我们现在把目光关注到Model Plug_in中最重要的部分。首先是Model的接口,例如接口“主机”,它的定义非常简单,就是些属性的get,set方法。get方法很简单,而set方法则比较有趣:

public void setName(String newName) {
String oldName = name;
name = newName;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this,
Notification.SET,
MobilesPackage.主机__NAME,
oldName, name));
}

它不仅仅将类变量赋予了新值,还在需要Notify的时候发出了一个Notification。如同上一节所讲的,这个Notification将包含发出者,改变的方式,改变的属性标识(feature ID)、旧值和新值。

 随后是一些e开头的方法,他们都是用作反射的。例如eGet,根据feature ID返回相应的属性值;eSet,根据feature ID设置相应的属性值;eUnset,根据feature ID设置相应的属性值为缺省值;eIsSet,根据feature ID判断相应的属性是否被设置过;

限于篇幅的关系,EMF中还有很多高级的功能没有在本文中介绍,比如持久化,Command pattern等;Edit工程里更是包含了集万千宠爱于一身的ItemProvider,它们都非常重要,希望以后有机会能与读者共同探讨

Eclipse 项目有一个称为 JET 的技术项目就是一个专门的代码生成器 包含了下面文章的例子:使用 JET 在 Eclipse 中创建更多更好的代码(http://www.ibm.com/developerworks/cn/opensource/os-ecl-jet/) 立即下载

相关推荐

Eclipse_EMF_JET_自动代码生成技术入门

基于Eclipse下EMF的JET自动代码生成技术,一步步教你实现HelloWorld的代码生成举例。

[zt]用模型驱动Eclipse开发

FROM:http://www.rcp.org.cn/bbs_topic.do?forumID=8&amp;postID=163       EMF(Eclipse Modeling Framework)是一个模型架构和代码生成工具,它可以用来建构以结构化数据为基础的工具或者应用。作为MDA和Eclipse的结合体,它发展迅速,IBM的大部分工具产品如RSA等都将建立在它的基础之上。    ...

疯狂的菠菜 350

eclipse-emf-ecore-2.3.1.jar

jar包,官方版本,自测可用

ecore模型epackage_EMF-Ecore模型概述

1Ecore模型:1.1说明:这里展示了整个Ecore模型中各个类的集成关系。 2继承图2.1说明:本部分列出了每一个类所包含的字段,字段的值可以通过Java文件,UML图,XML文件或者Ecore模型进行定制,字段的值将直接影响到Ecore所生成的目标代码。2.2EStructurealFeature2.2.1 类图:type="#_x0000_t75" style='width:342p...

weixin_39933438的博客 942

ecore模型epackage_EMF中的ecore模型分析

ecore模型分析目前生成ecore模型主要由四种途径,如图:这里我们采用从UML Model产生ecore模型,首先用Rose设计包emf,然后在包中新建如下类图:生成的ecore模型如下xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:ecore="http...

weixin_39904809的博客 1372

EReference的containment和container属性

EReference的containment属性如果为true,表示目标EClass是被源EClass包含的,这是一种十分强的关系,例如汽车和车轮的关系。在ecore里,不允许包含关系形成圈,也就是说如果A包含B,B就不能再直接或间接的包含A;另外,如果作为容器的对象结束了自己的生命周期,被它包含的对象也将结束自己的生命周期。 如果一个EReference有作为EOpposite的ER...

diaozhuo4700的博客 345

如何在eclipse开发web service (by quqi99)

        如何在eclipse开发web service (by quqi99)                如何在eclipse开发web service1、  新建一个WTP动态WEB工程。2、  在工程中新建一个类,如下:

技术并艺术着 3018

使用eclipse+pydev远程调试OpenStack(by quqi99)

作者:张华  发表于:2014-01-17 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) 1, 对于要远程调试的WSGI web应用中,添加如下代码,其中172.16.1.122是指远程安装eclipse机器的ip地址。 import pydevd pydevd.settrace('

技术并艺术着 1万+

玩转play framework ( by quqi99 )

                                         玩转play framework ( by quqi99 ) 作者:张华  发表于:2011-04-06版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明( http://blog.csdn.net/quqi99 )p { margin-bottom

技术并艺术着 9345

Fedora 16上源码建立pydev + eclipse的OpenStack开发环境笔记草稿 ( by quqi99 )

Fedora 16上源码建立pydev + eclipse的OpenStack开发环境笔记草稿  ( by quqi99 ) 作者:张华  发表于:2012-3-30 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 )          <!-- @page

技术并艺术着 1万+

eclipse中安装插件失败终极解决方案(by quqi99)

eclipse中安装插件失败终极解决方案(by quqi99) 作者:张华 发表于:2009-12-09版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明       今天自己写了一个应用服务器的eclipse插件,可在安装时始终不成功,不报错,就是看不到功能。而这个插件在调试时是好的呀,所以我不怀疑我写的插件的正确性,我

技术并艺术着 2071

搭建基于qemu + eclipse的kernel调试环境(by quqi99)

作者:张华  发表于:2016-02-06版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明( http://blog.csdn.net/quqi99 )使用qemu结合eclipse或者DDD等gdb的图形前端,跟踪协议栈或者文件系统内存管理等都会非常方便。就是与硬件驱动相关的跟踪可能差点。编译内核下载Linux Kernel源码,并编译生成压缩的kernel

技术并艺术着 7637

Android学习笔记[by quqi99 ]

Android platform是一个用于开发移动程序的软件包,它包括了操作系统、中间件及一些关键应用。开发者能使用android SDK为Android platform开发应用,这些应用使用JAVA语言书写,运行在虚拟机Dalvik(一个专为手机程序开发的基于linux内核的JAVA虚拟机)。http://www.androidcn.net/wiki/index.php?title=%E7

The Way of Programming 1万+

EMF与XML序列化和反序列化

在进行EMF与XML序列化和反序列化遇到一些问题,最后终于解决。 首先EMF要序列化需要在ecore模型中将其EReferece的属性设置成containment为true,否则该属性无法序列化, 这点摸索了好几个小时才找到原因。 代码如下: /** * * @author fuliang * */ public class ModelUtil { public s...

fuliang 465

Eclipse EMF教程(上)

为了回答这个问题,“什么是EMF?”,我们将借用EMF网站上的描述:“EMF项目是一个建模框架和代码生成工具,用于基于结构化数据模型构建工具和其他应用程序。根据XMI描述的模型规范,EMF提供了工具和运行时支持来为模型生成一组Java类,以及一组适配器类(支持查看和基于命令编辑模型)和一个基本编辑器来源:https://www.eclipse.org/emf值得一提的是,除了作为一个成功的建模框架外,EMF还一直是许多其他建模技术的稳定标准。

一念天堂 2824

构建 Eclipse 插件在 EMF 模型中浏览内容

 文档选项<!--document.write(打印本页);//-->打印本页<!--document.write(将此页作为电子邮件发送);//--> 将此页作为电子邮件发送未显示需要 JavaScript 的文档选项

CS_Mercy的专栏 1108
上一篇: 编程语言的三大定理
下一篇: 如何才算掌握J2SE
wapysun
博客等级 码龄19年 14粉丝 3原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值