首页 > 程序开发 > 软件开发 > Java >

浅析Eclipse建模框架(EMF)及其动态能力

2006-09-21

如果给定一个模型,那么EMF能够自动生成Java源代码-该源码允许你创建、查询、更新、串行化、反串行化、检验和追踪你的模型实例的变化。EMF提供了一组有效的反射API并且允许你用动态的(非生成的)模型进行工作。  一、

如果给定一个模型,那么EMF能够自动生成Java源代码-该源码允许你创建、查询、更新、串行化、反串行化、检验和追踪你的模型实例的变化。EMF提供了一组有效的反射API并且允许你用动态的(非生成的)模型进行工作。

  一、 引言

  Eclipse建模框架(EMF)是一个Java开源框架与代码生成工具-用于基于结构化的模型来构建工具和其它应用程序。在Eclipse平台在用户界面和文件级上提供一个强有力的集成框架的同时,EMF加强了这种能力来实现工具和应用程序之间良好粒度的数据分享。

  类似于其它的Java绑定框架,例如JAXB或XMLBeans,给定一个模型后,EMF就能够生成Java源代码-它允许你创建、查询、更新、反串行化以及串行化你的模型的实例。尽管多数Java绑定框架仅支持一个模型类,例如XML模式,而EMF支持从XML模式,UML类图(Rational Rose或UML2)以及被注解的Java接口中生成代码。除了模型代码,EMF还能生成一个完整的应用程序-它包括一个可定制的编辑器。

  EMF生成的代码有一个内建的改变通知机制并且支持跨文档参考。EMF提供一个反射API以存取你的模型实例并且允许你动态地创建模型。EMF支持模型约束校验。EMF提供强有力的代码生成工具来支持模型的重新生成和使用用户书写的代码进行合并。

  在本文中,我们将解释什么是EMF,并分析其基本框架。

  EMF最开始是一个对象管理组的(OMG)元对象设备(MOF)说明书的实现-它为面向对象的分析和设计提供一个标准化的元模型。在很长一段时间以来,EMF被用于实现大量的工具并且因此演变为一个有效的MOF API的一个核心子集的Java实现。

  在EMF中的类MOF核心元模型(一个模型的模型)被称作Ecore。在对当前的MOF 2.0的实现中,有一个类似的MOF模型的子集,称作Essential MOF(EMOF),它现在已经被独立出来。在Ecore和EMOF之间主要存在上些小的特别是命名上的区别,因此EMF能透明地读和写串行化的EMOF,从而允许工具间数据的标准交换。

  今天EMF已被广泛应用。例如,EMF被用于实现开源XML模式Infoset模型(XSD),服务数据对象(SDO),UML2以及Eclipse上的Web工具平台(WTP)工程。另外,EMF也被使用在商业化的产品中,例如Omondo EclipseUML以及IBM Rational和WebSphere产品等。

  二、 Ecore和反射API

  EMF中的一个关键接口是Eobject,它在概念上等价于java.lang.Object。所有的建模对象,无论是生成的与否,为了提供以下几个重要特征,都要实现这个接口:

  ·类似Java的Object.getClass(),通过使用eClass()方法,你能检索实例的元数据,也就是它的Eclass。

  ·在任何EMF建模的对象上,你都能使用反射API(eGet(),eSet())来存取它的数据。这在概念上等同于Java的java.lang.reflect.Method.invoke()方法,尽管效率更高些。

  ·从任何实例对象,你都可以通过使用eContainer()方法得到它的容器(parent)。

  ·EObject也扩展了Notifier,这允许你监视对象的数据的所有变化。

  如前面所提及,EMF有它自己的简单的元数据-称作Ecore。图1显示出Ecore元数据的完整的类层次结构图。在图1中,你可以看到EPackage包含关于模型类(EClass)和数据类型(EDataType)的信息。EClass描述一个建模的类,并且指定属性和参考以描述实例的数据。EAttribute描述简单数据,它由一个EDataType来指定。EReference描述一个类之间的关联;它的类型是一个Eclass。EFactory包含创建模型元素的方法。


图1.Ecore类层次结构:这个图像显示出Ecore元数据完整的类层次。

  为找到更多关于EMF和Ecore,请读在线概述或购买Eclipse建模框架(EMF)。EMF网站提供了若干文件来描述怎么使用EMF来从一个XML模式或UML图表生成Java代码。

  下面我将描述一个示例,它使用Ecore来创建一个简单公司模型,然后使用动态的EMF来创建,串行化和反串行化这个模型的实例。如果你想继续读下去并且你已经是一个Eclipse用户,请下载和安装EMF 2.1 SDK或任何可用的更新的版本,在EMF下载站点。如果不那样,你还可以下载独立包,它包括EMF jar文件,它没有任何对Eclipse的依赖性并且能被使用于一个独立的应用程序。
三、 使用动态EMF能力

  一般地,如果你在开发期间创建了模型,那么典型情况下,你最好生成Java代码,因为在这种情况中你的应用程序会使用较少的内存并且提供更快的数据存取(或是使用生成的API或是使用反射API)。尽管生成Java代码满足了大多数应用程序的需要,但是情况并不总是如此。你可能需要处理数据,而不需要使用生成的实现类。例如,你可能不知道在开发时间你将要处理的数据的模型,这就使得生成的Java代码成为一个可怜的选项。

  动态的(也就是非生成的)类可以在运行时刻用几种方法来创建。让我们先开始使用Ecore API以编程地方式来创建一个公司模型。公司模型用于描述一个公司,它有一个名称和部门。每个部门由一个数字来唯一标志出并且它还有雇员,每个雇员有一个名称。在下面的代码显示出一个相应于该模型的Ecore元模型。

EcoreFactory ecoreFactory = EcoreFactory.eINSTANCE;
EcorePackage ecorePackage = EcorePackage.eINSTANCE;
//创建一Company类
EClass companyClass = ecoreFactory.createEClass();
companyClass.setName("Company");
//创建公司名
EAttribute companyName = ecoreFactory.createEAttribute();
companyName.setName("name");
companyName.setEType(ecorePackage.getEString());
companyClass.getEStructuralFeatures().add(companyName);
//创建一Employee类
EClass employeeClass = ecoreFactory.createEClass();
employeeClass.setName("Employee");
//在Employee类上添加一个名字属性
EAttribute employeeName = ecoreFactory.createEAttribute();
employeeName.setName("name");
employeeName.setEType(ecorePackage.getEString());
employeeClass.getEStructuralFeatures().add(employeeName);
//创建一Department类
EClass departmentClass = ecoreFactory.createEClass();
departmentClass.setName("Department");
//添加department标志数字
EAttribute departmentNumber = ecoreFactory.createEAttribute();
departmentNumber.setName("number");
departmentNumber.setEType(ecorePackage.getEInt());
departmentClass.getEStructuralFeatures().add(departmentNumber);
//department类能够包含到一个或多个employee的参考
EReference departmentEmployees = ecoreFactory.createEReference();
departmentEmployees.setName("employees");
departmentEmployees.setEType(employeeClass);
//指定它可能是一个或多个employee
departmentEmployees.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
departmentEmployees.setContainment(true);
departmentClass.getEStructuralFeatures().add(departmentEmployees);
//company能够包含到一个或多个departments的参考
EReference companyDepartments = ecoreFactory.createEReference();
companyDepartments.setName("department");
companyDepartments.setEType(departmentClass);
companyDepartments.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
companyDepartments.setContainment(true);
companyClass.getEStructuralFeatures().add(companyDepartments);
//创建一个包-描述company
EPackage companyPackage = ecoreFactory.createEPackage();
companyPackage.setName("company");
companyPackage.setNsPrefix("company");
companyPackage.setNsURI("http:///com.example.company.ecore");
companyPackage.getEClassifiers().add(employeeClass);
companyPackage.getEClassifiers().add(departmentClass);
companyPackage.getEClassifiers().add(companyClass);
通过使用反射API,你能创建并且初始化一个你的模型的实例:
//得到company工厂
EFactory companyFactory = companyPackage.getEFactoryInstance();
//使用工厂来创建company类的实例并且
//设置company名字
EObject company = companyFactory.create(companyClass);
company.eSet(companyName, "MyCompany");
//创建一个employee类的实例
EObject employee = companyFactory.create(employeeClass);
//使用反射API初始化employee的名字
employee.eSet(employeeName, "John");
//创建一个department类的实例
EObject department = companyFactory.create(departmentClass);
department.eSet(departmentNumber, new Integer(123));
//添加"John"到department
((List)department.eGet(departmentEmployees)).add(employee);
//添加department到company
((List)company.eGet(companyDepartments)).add(department);
四、 数据的串行化和反串行化

  为了串行化你的模型实例,你需要把一个你的实例模型的根对象放置到一个资源中。EMForg.eclipse.emf.ecore.resource.Resource接口描述了一个物理的存储位置(例如文件或URL)并且提供方法以串行化和装载数据。每一种资源都被存储在一个ResourceSet中-它代表了一个资源集合-这些资源被一起创建和加载并允许在它们当中进行参考引用。特别地,一个ResourceSet负责跟踪哪些资源已被装载并且保证这个ResourceSet中的资源不会被重复装载。

  因为EMF能够处理多重模型源,例如XML模式,所以指定使用哪些资源来实现(反)串行化你的数据也是很重要的
热点推荐