关于Eclipse中的开源框架EMF(Eclipse Modeling Framework)
Eclipse项目本身可以划分为4个主要的子项目:Equinox,平台,Java开发工具(Java Development Tools,JDT)和插件开发环境(Plug-in Development Environment,PDE).一般来说,这4个子项目足以来扩展架构和开发基于Eclipse的工具.
Equinox和平台是Eclipse的核心组件,许多人直接将他们当做Eclipse.Equinox是OSGI R4核心架构规范的实现.这种规范提供作为所有Eclipse的基础的组件模型.
JDT是使用Eclipse构建的功能完备的Java开发环境,其工具高度集成.代表Eclipse平台的能力所在.JDT可用来开发Eclipse或者其他目标平台的Java程序,JDT甚至可以用来开发Eclipse项目自身.
PDE提供了视图和编辑器来为Eclipse创建插件,PDE通过支持插件开发活动的非Java部分(例如注册插件扩展等)来以JDT为基础构建并扩展JDT.
建模项目:
Eclipse建模项目是Eclipse中基于模型开发技术的改进和提升的重点,其核心是EMF,它为建模提供了基本架构,其他建模子项目建立在EMF核心之上.他们能够提供某些功能,例如模型转换,数据库集成和图形比那机器生成.其中还包括许多重要建模标准的实现.
EMF不需要完全不同的方法或者任何复杂的建模工具,EMF入门所需要的只是Eclipse Java开发工具.EMF和建模概念直接与他们的实现相关联.从而使Eclipse-----通常是Java开发人员的建模入门门槛较低.
本文转自:http://www.cnblogs.com/jpcflyer/archive/2012/05/29/2517678.html
后来发现这个博主也是翻译的一本国外的书(Addison.Wesley.Eclipse.Modeling.Framework.A.Developers.Guide)
Eclipse Modeling Framework (EMF),简单的说,就是Eclipse提供的一套建模框架,可以用EMF建立自己的UML模型,设计模型的XML格式或编写模型的java代码。EMF提供了一套方便的机制,实现了功能的相互转换,大大提高了效率,下面是其具体功能介绍:
一、统一java、UML、XML
为了帮助理解EMF,我们可以举一个例子。假设老板要你写需要写一个程序,来管理供应商的采购清单,采购清单需要维护三大项:付款方(bill to)、运送地址(ship to)和购买货物集合(集合中包含名字name、数量quantity、价格price)。你回答说:没问题。然后就开始设计采购系统的java接口:
public interface PurchaseOrder{//购买订单接口类
String getShipTo();//运送地址
void setShipTo(String value);
String getBillTo();付款方
void setBillTo(String value);
List getItems(); // List of Item 订单中的商品
}
public interface Item{//购买商品的接口类
String getProductName();//名字
void setProductName(String value);
int getQuantity();//数量
void setQuantity(int value);
float getPrice();//价格
void setPrice(float value);
}
然后就准备开始实现自己的接口,忽然老板问了一句,“你不要先建立自己的模型吗”,对于大多数从来不建模的java程序员,你认为代码就是模型,用那些形式化建模元素建立模型除了能在文档中增加篇幅外,没有任何好处,但即使如此,你仍然要听老板的话,所以你建立了如图1所示的UML模型。
这里,你可以要求老板走开,然后编码实现了,但首先你还得保存模型,这里我们你想到了用XML文件保存,自诩聪明之时,写好了如下的XML schema文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://www.example.com/SimplePO"
targetNamespace="http://www.example.com/SimplePO">
<xsd:complexType name="PurchaseOrder">
<xsd:sequence>
<xsd:element name="shipTo" type="xsd:string"/>
<xsd:element name="billTo" type="xsd:string"/>
<xsd:element name="items" type="po:Item"
minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Item">
<xsd:sequence>
<xsd:element name="productName" type="xsd:string"/>
<xsd:element name="quantity" type="xsd:int"/>
<xsd:element name="price" type="xsd:float"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
在下一步工作之前,你突然意识到现在已经有三种系统表示:Java interfaces、UML模型和 XML Schema,你开始思考,同一个系统设计了三种模型(暂且认为XML和接口也是模型),进行了大量重复的工作,有没有一种方法,只设计其中的一种模型,然后实现三者之间的相互转换?
此时,EMF出现了,EMF是一个建模框架,能够实现java代码的生成,即它统一了三种重要的技术:Java, XML 和 UML。如图2所示。
假设你要操作一个XML文档,如果你是XML schema大牛,你可以从设计schema开始,然后通过EMF得到UML模型,再通过EMF得到java代码,当然如果你不是,可以从设计UML模型开始,一样可以完成上述功能。
二、建模 vs 编程
这里有的人可能会问:难道EMF只是一个描述模型和生成其它东西的框架吗?回答是的,但不全面,EMF的功能远不止此,它能有效地为编程服务,这也是一个经典问题的答案:“我是应该先建模还是直接写代码?”,EMF的回答是两者都可以,因此在EMF看来,两者是等价的。用英语回答就是:"To model or to program, that is not the question."
三、定义模型
上面我们用三种形式描述了我们的概念模型,那么这三者有没有共同的模型概念,方便它们之间的转换呢(模型转换的知识在此暂时省略)?我们再回顾下前面的三种模型:
- PurchaseOrder and Item 在UML和java中是类,但在XML schema中是复杂类型定义;
- shipTo, billTo, productName, quantity 和 price在UML中是属性,在java中是get()/set()方法对,在XML schema中是内嵌的元素类型;
- items在UML是类的关联或引用,在java中是get()方法,在XML schema中是另一种复杂类型的内嵌元素类型。
可以看到这三者都用到了一种较高层的定义来分别表达UML、XML、java。因此,要实现EMF和模型之间的转换,我们需要这种能够描述EMF模型的模型,我们称为元模型。
1、Ecore (Meta)模型
能够描述EMF的模型称为Ecore元模型(位于MOF的M2层,关于MOF可以参考http://en.wikipedia.org/wiki/Meta-Object_Facility),它本身也是EMF模型,因此Ecore是它自己的元模型。如果再深入一点,Ecore的元模型又是什么呢?回答仍然是Ecore,因为它可以描述自身。Ecore只是OMG的MOF在Eclipse下的一种实现,可能还有其它元模型形式(可以参考http://wenku.baidu.com/view/d28de6717fd5360cba1adb28.html第二段),这里就不详细介绍了。图3给出了一个简化的Ecore元模型,说它是简化的,是因为它只是Ecore元模型的子集,而且为了方便,将某些公共类省略,如ENamedElement类(这个类定义了类中属性的名字)。
从图2中可以看到,我们需要四种Ecore类来描述我们的模型,它们是:
- EClass 用于表示模型中的类,它有一个name,0个或多个attributes,0个或多个references。
- EAttribute 用于表示模型中的attribute,它有一个name和一个type。
- EReference 用于表示两个类之间的关联,它有一个name,一个布尔值表示它是否是containment,还有一个引用类型(其它类)。
- EDataType 用于表示attribute的类型,它可以是基本类型,例如int 、 float 或对象类型 java.util.Date等.
我们还可以观察到,Ecore元模型这么类似于UML中的类图,这不足为怪,因为UML本来就是一种统一的建模语言(名符其实),倒是有另一点可能不明白?即然Ecore也是UML,为什么不用UML作为UML的元模型呢?答案很简单,因为Ecore只是UML的子集,没有必要用到除类图以外的其它UML元素。
有了Ecore元模型,我们就可以用我们的例子实例化Ecore元模型,图4是采购系统的Ecore实例(如果对此不理解,可以参考http://www.cnblogs.com/riky/archive/2007/04/07/704298.html)。
将采购订单类描述为名为PurchaseOrder的EClass实例.它包含连个属性(通过eAttribute访问的EAttribute的实例)shipTo和billTo以及一个名为items的引用(通过eReferences访问的EReference的实例),对它来说,eReferenceType(目标类型)相当于另一个名为Item的EClass实例.
用这些Ecore对象表示内存中的模型之后,EMF可以读取它们来生成实现的代码.但是首先该如何创建模型呢?答案就是从开始的输入形式中构建它,如果从Java接口开始,EMF将内省它们并构建Ecore模型,然而,如果从XML Schema开始那么就将根据其构建模型.如果从UML开始就有3种可能的情况:
(1)直接Ecore编辑.EMF包含一个简单的基于结构树的Ecore样本编辑器,如果使用图形工具,Ecore工具(Ecore Tools)项目会提供一个基于UML符号的图形Ecore编辑器.也可以使用第三方选项.包括Topcased的Ecore Editor,Omondo的EclipseUML和Soyatec的eUML.
(2)从UML导入.
EMF项目和EMF模型向导提供一种课扩展的架构,可以再其中插入模型导入程序,以支持不同的模型格式.EMF只支持Rational Rose(.mdl文件).Rose具有这种特殊状态的原因是是它是用来"引导"EMF自身实现的工具.
(3)从UML导出.这类似于第二种选项.但是UML工具专门提供转换支持.从UML工具内而不是从EMF向导调用它.
由此可见第一种最合适,在开发过程中它没有导入或者导出的步骤.只需要编辑模型然后生成代码.同时,它与其它方法不同.用户不用担心Ecore模型与工具本身的共有模型不同步.当UML模型改变时候,其他两种方法都需要显式再导入和再导出.
第二种和第三种的优点是:可以使用UML工具完成EMF建模以外的任务,可以使用UML的全部功能,以及特定工具提供的优秀特性.例如:如果它支持自己的代码生成.就可以使用该工具来定义Ecore模型,或者定义和生成应用程序的其他部分.只要提供到Ecore的转化机制,那么该工具也可以用作EMF以及其生成器的输入源.
2、XMI序列格式
有了Ecore元模型后,可能有人会问:“Ecore的序列化格式(Serialized form)是什么呢?”是Java code、XML Schema 和 UML diagram中的一种吗?实际上,Ecore的规范序列化格式是XMI(XML Metadata Interchange),为什么会出现另外一种XMI格式,而不用前面介绍的三种格式呢?首先,Java code、XML Schema 和 UML diagram都增加了Ecore本身并不具有的信息,已经改变了Ecore;其次,Java code、XML Schema 和 UML diagram中没有一种能够适用于任何场合,即没有一种是通用的,而XMI正好满足这两点。我们的采购系统Ecore实例可以用下面的XMI序列表示:
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="po"
nsURI="http://www.example.com/SimplePO" nsPrefix="po">
<eClassifiers xsi:type="ecore:EClass" name="PurchaseOrder">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="shipTo"
eType="ecore:EDataType
http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="billTo"
eType="ecore:EDataType
http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="items"
upperBound="-1" eType="#//Item" containment="true"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Item">
<eStructuralFeatures xsi:type="ecore:EAttribute"
name="productName" eType="ecore:EDataType
http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="quantity"
eType="ecore:EDataType
http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="price"
eType="ecore:EDataType
http://www.eclipse.org/emf/2002/Ecore#//EFloat"/>
</eClassifiers>
</ecore:EPackage>
当我们听到别人要导出EMF模型时,实际上就是导出EMF的XMI。
3、java注释
我们已经知道EMF能够将java接口自动生成UML的属性和方法,但是否所有的接口都能生成呢?或者什么样的接口才能生成呢?首先,EMF并不会盲目地把所有的java接口自动生成UML的属性和方法,其次,只有符合特定规范才能通过EMF生成(EMF使用的是JavaBeans简单属性祖先命名模式的子集,具体规范可参考http://java.sun.com/products/javabeans/docs/spec.html)。根据此规范,需要用@model标明哪些接口需要用EMF生成模型。例如前面给的PurchaseOrder接口就需要用下面的格式来生成UML:
/**
* @model
*/
public interface PurchaseOrder
{
/**
* @model
*/
String getShipTo();
/**
* @model
*/
String getBillTo();
/**
* @model type="Item" containment="true"
*/
List getItems();
}
这里使用@model标记将PurhaseOrder确定为模型类,它包含了两个属性(shipTo和billTo)以及一个引用(items).注意shipTo和billTo这两个属性都有通过Java内省可用的模型信息,也就是说,他们是string类型的简单属性.其他模型信息均未显示在@model标记之后,因为只有不同于默认的信息才需要制定.
items引用需要一些非默认模型信息,因为引用是多重---多值引用(表现为(getItems()返回一个List),所以需要将引用的目标类型制定为type="Item",还需要指定containment="true"来表示我们希望采购订单成为项目的容器,并将它们串行化为子项目.
注意在注释后的接口中不需要setShipTo()和setBillTo()方法,对于get()方法的注释,不需要包括它们,一旦表示这些属性(默认为可以设置的属性),就会生成set()方法.如果它们不在接口里,就将它们合并到该接口.
4、Ecore "Big Picture"
我们先来回顾前面的知识:
- Ecore和它的XMI序列化格式是EMF的核心;
- EMF模型至少可以通过三种形式得到(UML、XML schema、Java 接口);
- 通过Ecore模型可以生成Java接口及其它形式的模型;
其实,通过XML schema定义模型有一个优势:给定schema后,可以序列化成持久模型的实例。因为XML schema不仅仅定义了模型,还指定了模型实例的持久格式。问题出来了:是否还有其它的持久模型格式呢?回答是肯定的,例如relational database (RDB) Schema等。Ecore的"big picture"如图5所示。
四、生成代码
EMF最主要的功能莫过于其自动代码生成能力了,能够极大提高工作效率。假设我们已经有了上面的模型,生成转换成Java代码呢?你只要新建EMF项目,它即自动加载了生成器。那么,EMF生成是的是什么样的代码呢?
首先,Ecore类(即EClass)相当于java的两个实体:接口及其实现类。例如对于EClass PurchaseOrder相当于java的:
public interface PurchaseOrder ...
public class PurchaseOrderImpl extends ... implements PurchaseOrder {
是这种设计方式,是因为我们认为这是类模型API(如文档对象模型DOM)的最好模式。
其次,每个生成的接口都直接或间接扩展了基接口EObject,如:
public interface PurchaseOrder extends EObject {
EObject是java.lang.Object的EMF等价物,即所有模型对象的基础。扩展的EObject包含下面三种行为:
- eClass()返回对象的元对象(是一个EClass)。
- eContainer() and eResource() 分别返回对象的包含对象及其资源。
- eGet(), eSet(), eIsSet(), and eUnset() 提供了访问交互对象的API。
然后,EObject还是另一个接口的扩展:
public interface EObject extends Notifier {
}
最后,根据类型及用户设定的属性生成代码。例如:
public String getShipTo()
{
return shipTo;
}
对于相应的set()会有点不同,它会对其它可能对此属性状态改变的观察者发出通知,如:
public void setShipTo(String newShipTo)
{
String oldShipTo = shipTo;
shipTo = newShipTo;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this,
Notification.SET,
POPackage.PURCHASE_ORDER__SHIP_TO,
oldShipTo, shipTo));
}
注意到当没有观察者时,为了避免调用eNotify()花费的高昂代价,EMF会添加一个eNotificationRequired()守卫条件。
五、总结
本篇由浅入深的介绍了EMF的相关知识,由于篇幅原因,不可能将全部的EMF知识都写在这里,感兴趣的读者可以通过参考书籍了解其它内容。
六、参考资料
1. Steinberg, D., Budinsky, F., Paternostro, M., Merks, E.: Eclipse Modeling Framework, 2nd Edition. Pearson Education (2008)
关于Eclipse中的开源框架EMF(Eclipse Modeling Framework)的更多相关文章
- 关于Eclipse中的开源框架EMF(Eclipse Modeling Framework),第三部分
Eclipse Modeling Framework(EMF)中包含了一个开放源代码的工具 JMerge,这个工具可以使代码生成更加灵活,可定制性更好.本文使用一个例子来展示如何将 JMerge 添加 ...
- eclipse中SSH三大框架环境搭建<三>
相关链接: eclipse中SSH三大框架环境搭建<一> eclipse中SSH三大框架环境搭建<二> 引言:通过上两篇文章我们已经可以掌握struts2和spring的环境的 ...
- eclipse中SSH三大框架环境搭建<二>
通过上一篇博客我们可以轻松搭建strtus2的环境,接下来由我来继续介绍spring的环境搭建以及spring注入的简单使用 相关链接:eclipse中SSH三大k框架环境搭建<一> ec ...
- eclipse中SSH三大框架环境搭建<一>
这里先简单介绍一下我用的三大框架版本以及下载地址 相关链接:eclipse中SSH三大框架环境搭建<二> eclipse中SSH三大框架环境搭建<三> struts-2.3.3 ...
- eclipse中配置c++开发环境 Eclipse + CDT + MinGW
转自eclipse中配置c++开发环境 Eclipse + CDT + MinGW 基本框架:Eclipse + CDT + MinGW 背景知识: CDT:CDT 是完全用 Java 实现的开放源码 ...
- 在Eclipse 中下载 开源中国码云上的项目
功能:使用开源中国代码托管(码云)来托管代码,本地的使用Eclipse,该如何配置? 步骤: 1/ 在码云 上建一个工程,(为了访问托管工程的权限) 2/ 在eclipse中打开名字叫做“Git ...
- Android中使用开源框架android-image-indicator实现图片轮播部署
之前的博文中有介绍关于图片轮播的实现方式,分别为(含超链接): 1.<Android中使用ViewFlipper实现屏幕切换> 2.<Android中使用ViewPager实现屏幕页 ...
- Android中使用开源框架PagerSlidingTabStrip实现导航标题
此开源框架官网地址:https://github.com/astuetz/PagerSlidingTabStrip 可以理解为配合ViewPager使用的交互式页面指示器控件. 话不多说,先上效果图: ...
- 02 eclipse中配置Web项目(含eclipse基本配置和Tomcat的配置)
eclipse搭建web项目 一.Eclipse基本配置 找到首选项: (一)配置编码 (二)配置字体 (三)配置jdk (四)配置Tomcat 二.Tomcat配置 三.切换视图,检查Tomcat ...
随机推荐
- 解决js获取数据跨域问题,jsonP
网上说了一些jsonp的示例,感觉都没用,最后研究了一下,调用腾讯的一个api.最后要加output=jsonp&callback=?这个,比较适用. var url = "http ...
- Leetcode OJ : Triangle 动态规划 python solution
Total Accepted: 31557 Total Submissions: 116793 Given a triangle, find the minimum path sum from ...
- HDU 2476 String painter (区间DP)
题意:给出两个串a和b,一次只能将一个区间刷一次,问最少几次能让a=b 思路:首先考虑最坏的情况,就是先将一个空白字符串刷成b需要的次数,直接区间DP[i][j]表示i到j的最小次数. 再考虑把a变成 ...
- HW6.25
import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...
- 数组(Array)
1. 数组(Array):相同类型数据的集合就叫做数组. 2. 数组的定义与赋值(系统会默认初始化) 普通数组: package com.li; public class Array{ public ...
- 【组队训练】2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest
好多oj都崩掉了,于是打了cf.. 开始开的最后一题...尼玛题好长终于看完了...神题不会.... I过了好多人..看了下,一眼题...随便敲了下,1A ]; int main(){ int n, ...
- Android实例-MediaPlayer播放音乐和视频(XE8+小米2)
结果: 1.播放视频需要手动放入MediaPlayerControl1控件,设置MediaPlayerControl1.MediaPlayer := MediaPlayer1; 2.播放声音文件正常, ...
- python 获取对象信息
当我们拿到一个对象的引用时,如何知道这个对象是什么类型.有哪些方法呢? 使用type() 首先,我们来判断对象类型,使用type()函数: 基本类型都可以用type()判断: >>> ...
- sonne_game网站开发03 spring-mvc+freemarker整合
今天的任务就是在spring+mybatis+springmvc的基础上,将freemarker整合进来. freemarker是什么? freemarker是一种模板引擎.它的目的是基于模板和数据, ...
- 如何创建一个有System用户权限的命令行
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:如何创建一个有System用户权限的命令行.