emf开发_使用动态EMF建立元模型

2023-12-12 14:10

本文主要是介绍emf开发_使用动态EMF建立元模型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

emf开发

Eclipse Modeling Framework(EMF)描述了数据模型,并允许从不同类型的数据模型工件(例如XML Schema,RationalRose®模型,Ecore模型或Java注释)轻松生成代码。 在代码生成过程中,EMF生成器会创建模型代码,其中包括类型安全接口和数据模型的实现类。 但是,在某些情况下,应用程序不需要这些类型安全的接口和实现类。 相反,需要可以在应用程序组件之间共享或由应用程序组件进一步处理的数据对象。

在这种情况下,动态EMF派上用场,因为它允许应用程序开发人员在运行时以编程方式制造内存中的核心模型,动态地创建其实例,并使用EMF反射API访问模型实例元素。

为什么选择动态EMF?

Dynamic EMF的主要价值在于,它允许您在运行时仅用几行代码即可构建基于Ecore的模型,然后出于各种目的创建和访问此动态模型的实例。 以这种方式构建核心模型有助于避免在不需要接口和实现类时生成它们。

这种创建模型和模型实例的方法在(但不限于)以下场景中特别有用:

  • 不需要类型安全的接口或实现类 -只需在应用程序组件之间共享简单的数据对象。 在这种情况下,使用EMF代码生成器生成模型代码对于应用程序来说将是开销,因为它将不必要地维护和部署整个生成的接口/类集。 使用动态EMF,可以动态地创建和实例化包含动态类的核心模型。 然后,这些动态类的实例可用于共享数据或由应用程序组件进行进一步处理。
  • 数据模型仅在运行时已知 —在这种情况下,由于在开发时不知道数据模型,因此通过EMF代码生成器创建静态模型不是一个好的选择。 可以在运行时构建和实例化的动态核心模型将更适合此类情况下的应用程序需求。

创建动态内存核心模型

我们首先以编程方式构建基于动态Ecore的模型,然后创建该模型的动态实例。 稍后,我们将看到如何读写模型实例中存在的元素的值。

创建基于Ecore的动态模型/元模型

我们将考虑一个书店模型来演示动态Ecore模型的创建。 为了清楚起见,我们使用统一建模语言(UML)表示模型。

图1. BookStore模型
书店模型

我们首先创建一组核心模型元素,包括一个EcoreFactory实例,一个EcorePackage实例,两个EClass实例和一个EPackage实例。 参见清单1。

清单1.创建核心模型元素
/*
* Instantiate EcoreFactory
*/
EcoreFactory theCoreFactory = EcoreFactory.eINSTANCE;/*
* Create EClass instance to model BookStore class
*/
EClass bookStoreEClass = theCoreFactory.createEClass();
bookStoreEClass.setName("BookStore");/*
* Create EClass instance to model Book class
*/
EClass bookEClass = theCoreFactory.createEClass();
bookEClass.setName("Book");/*
* Instantiate EPackage and provide unique URI
* to identify this package
*/
EPackage bookStoreEPackage = theCoreFactory.createEPackage();
bookStoreEPackage.setName("BookStorePackage");
bookStoreEPackage.setNsPrefix("bookStore");
bookStoreEPackage.setNsURI("http:///com.ibm.dynamic.example.bookstore.ecore");

所述EcoreFactory提供方法来创建像模型元素EClassEAttributeEPackage等。使用的实例EcoreFactory ,我们创建了两个EClass实例:一个用于表示BookStore类和其它来表示Book类(如在指定的BookStore模型) 。 接下来,我们创建一个EPackage ,最终将在其中放置BookStoreBook类。 然后,我们定义bookStoreEPackage的名称和nsPrefix属性。 由于包的名称不必是唯一的,因此应向bookStoreEPackage提供URI以唯一标识它。 这是通过使用setNsURI()方法设置nsURI属性的值来完成的。

现在,我们为动态类创建BookStore数据模型指定的属性。 要为每个属性设置模型化的数据类型,我们实例化EcorePackage ,其中包含用于表示每种数据类型的元对象的访问器。 参见清单2。

清单2.创建动态类的属性
/*
* Instantiate EcorePackage
*/
EcorePackage theCorePackage = EcorePackage.eINSTANCE;/*
* Create attributes for BookStore class as specified in the model
*/
EAttribute bookStoreOwner = theCoreFactory.createEAttribute();
bookStoreOwner.setName("owner");
bookStoreOwner.setEType(theCorePackage.getEString());
EAttribute bookStoreLocation = theCoreFactory.createEAttribute();
bookStoreLocation.setName("location");
bookStoreLocation.setEType(theCorePackage.getEString());
EReference bookStore_Books = theCoreFactory.createEReference();
bookStore_Books.setName("books");
bookStore_Books.setEType(bookEClass);
bookStore_Books.setUpperBound(EStructuralFeature.UNBOUNDED_MULTIPLICITY);
bookStore_Books.setContainment(true);/*
* Create attributes for Book class as defined in the model
*/
EAttribute bookName = theCoreFactory.createEAttribute();
bookName.setName("name");
bookName.setEType(theCorePackage.getEString());
EAttribute bookISBN = theCoreFactory.createEAttribute();
bookISBN.setName("isbn");
bookISBN.setEType(theCorePackage.getEInt());

接下来,我们需要将每个类的属性添加到相应类的eStructuralFeatures列表中。 最后,我们将两个类都放入动态包bookStoreEPackage 。 这样就完成了给定BookStore模型的元模型的创建。

清单3.将属性与各自的类相关联并将类放在动态包中
/*
* Add owner, location and books attributes/references
* to BookStore class
*/
bookStoreEClass.getEStructuralFeatures().add(bookStoreOwner);
bookStoreEClass.getEStructuralFeatures().add(bookStoreLocation);
bookStoreEClass.getEStructuralFeatures().add(bookStore_Books);/*
* Add name and isbn attributes to Book class
*/
bookEClass.getEStructuralFeatures().add(bookName);
bookEClass.getEStructuralFeatures().add(bookISBN);/*
* Place BookStore and Book classes in bookStoreEPackage
*/
bookStoreEPackage.getEClassifiers().add(bookStoreEClass);
bookStoreEPackage.getEClassifiers().add(bookEClass);

创建动态模型实例

创建了内存中的Ecore模型后,我们可以创建模型中存在的动态类的实例。 我们首先通过在bookStoreEPackage上调用getEFactoryInstance()方法来获得一个EFactory实例。

清单4.创建动态实例
/*
* Obtain EFactory instance from BookStoreEPackage 
*/
EFactory bookFactoryInstance = bookStoreEPackage.getEFactoryInstance();/*
* Create dynamic instance of BookStoreEClass and BookEClass
*/
EObject bookObject = bookFactoryInstance.create(bookEClass);
EObject bookStoreObject = bookFactoryInstance.create(bookStoreEClass);

如果该模型的实现是由EMF代码生成器生成的,它将为模型的包和工厂提供实现类。 正在初始化的生成包(通过其构造函数)注册生成的工厂,并实例化对生成的工厂类的eFactoryInstance引用。 因此,在生成的包上调用getEFactoryInstance()方法将返回相应的生成的工厂。 由于我们的动态核心模型中没有任何生成的工厂,也没有任何类型的生成的类,因此在bookStoreEPackage上调用getEFactoryInstance()方法将返回动态工厂EFactoryImpl的实例。

EFactoryImpl定义了create()操作,该操作创建并返回指定为参数的模型类的新实例。 对于生成的模型代码,此方法被生成的工厂覆盖,以创建和返回相应的生成的模型类的实例。 在动态元模型,因为没有生成的工厂/模型实现类,调用create()的方法EFactory实例将返回的实例EObjectImpl

读写动态模型

EObjectImpl类包含所有反射API的实现,可用于访问我们的动态类的属性,从而使您能够读写模型,如下所示。

清单5.获取/设置模型实例元素的值
/*
* Set the values of bookStoreObject attributes
*/
bookStoreObject.eSet(bookStoreOwner, "David Brown");
bookStoreObject.eSet(bookStoreLocation, "Street#12, Top Town, NY");
((List) bookStoreObject.eGet(bookStore_Books)).add(bookObject);/*
* Set the values of bookObject attributes
*/
bookObject.eSet(bookName, "Harry Potter and the Deathly Hallows");
bookObject.eSet(bookISBN, 157221);/*
* Read/Get the values of bookStoreObject attributes
*/
String strOwner =(String)bookStoreObject.eGet(bookStoreOwner);
String strLocation =(String)bookStoreObject.eGet(bookStoreLocation);/*
* Read/Get the values of bookObject attributes
*/
String strName =(String)bookObject.eGet(bookName);
Object iISBN = bookObject.eGet(bookISBN);

同样,可以在需要时在模型类上调用EObjectImpl类中实现的其他反射API( eIsSet()eUnSet() )。

序列化动态模型

可以使用EMF Persistence框架的四个基本接口对动态模型进行序列化: ResourceResourceSetResource.FactoryURIConverter 。 序列化的过程将取决于我们是否要在要反序列化的同一程序中序列化模型,或者是否希望在与加载或反序列化模型的程序无关的其他程序中序列化模型。

如果要在同一程序中完成核心模型的序列化和反序列化,请执行以下操作; 如果不是,请转到清单7。要初始化序列化过程,我们首先注册XML资源工厂以处理具有任何扩展名的文件,如清单6所示。接下来,我们通过调用createResource()在资源集中创建一个空资源。 createResource()方法在ResourceSet实例上,并将ResourceSet的实际位置作为URI传递。 我们将EObjectbookStoreEObject )添加到该资源的内容列表中,并使用save()方法将资源复制到其持久性存储中。 (如果需要,资源集可以使用URIConverter来定位资源或将输入URI规范化为资源的实际URI。)

清单6.序列化动态模型实例
ResourceSet resourceSet = new ResourceSetImpl();
/*
* Register XML Factory implementation using DEFAULT_EXTENSION
*/
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new  XMLResourceFactoryImpl());/*
* Create empty resource with the given URI
*/
Resource resource = resourceSet.createResource(URI.createURI("./bookStore.xml"));/*
* Add bookStoreObject to contents list of the resource 
*/
resource.getContents().add(bookStoreObject);try{/** Save the resource*/resource.save(null);}catch (IOException e) {e.printStackTrace();}

动态模型的最终序列化实例如图2所示。

图2.动态模式的序列化实例
动态模式的序列化实例

如果要在不同的独立程序中进行核心模型的序列化和反序列化,请使用以下序列化过程; 如果不是,请返回清单6。在加载动态模型时,我们需要访问动态包bookStoreEPackage 。 如果要将模型装入序列化的同一程序中,则可以轻松完成此操作(请参阅下一节)。 但是,如果要在与序列化模型不同的程序中加载模型,则需要在序列化模型实例之前序列化动态Ecore模型,以便能够访问bookStoreEPackage

清单7.序列化元模型
ResourceSet metaResourceSet = new ResourceSetImpl();/*
* Register XML Factory implementation to handle .ecore files
*/
metaResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new  XMLResourceFactoryImpl());/*
* Create empty resource with the given URI
*/
Resource metaResource = \
metaResourceSet.createResource(URI.createURI("./bookStore.ecore"));/*
* Add bookStoreEPackage to contents list of the resource 
*/
metaResource.getContents().add(bookStoreEPackage);try {/** Save the resource*/metaResource.save(null);} catch (IOException e) {e.printStackTrace();}

我们首先注册一个XML资源工厂实现来处理带有Ecore扩展名的文件,因为核心模型将使用该扩展名进行序列化。 接下来,我们创建一个空资源,并将动态包bookStoreEPackage添加到此新创建资源的内容列表中。 最后,我们保存此资源。

生成的序列化动态核心模型或元模型如图3所示。

图3.序列化的动态核心模型
序列化动态核心模型

现在我们序列化模型实例文档:bookStore.xml。 唯一的区别是这次,实例文档使用附加属性xsi:schemaLocation进行了序列化。 加载程序将使用此属性来查找持久资源bookStore.ecore ,其中包含加载模型实例文档所需的序列化EPackage

清单8.使用xsi:schemaLocation属性序列化模型实例文档
ResourceSet resourceSet = new ResourceSetImpl();
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new  XMLResourceFactoryImpl());Resource resource = resourceSet.createResource(URI.createURI("./bookStore.xml"));
resource.getContents().add(bookStoreObject);/*
* Save the resource using OPTION_SCHEMA_LOCATION save option toproduce 
* xsi:schemaLocation attribute in the document
*/
Map options = new HashMap();
options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE);
try{resource.save(options);}catch (IOException e) {e.printStackTrace();}

序列化的模型实例文档bookstore.xml将带有xsi:schemaLocation属性,如下所示。

图4.具有xsi:SchemaLocation属性的序列化模型实例
具有xsi:SchemaLocation属性的序列化模型实例

反序列化/加载动态模型

现在,我们将看到如何加载刚刚序列化的动态模型实例文档。

如果核心模型的序列化和反序列化是在同一程序中完成的,则使用此反序列化过程。 在序列化过程中,我们首先在资源工厂实现中注册XML,以处理具有任何扩展名的文件。 之后,我们使用序列化模型时给定的相同名称空间URI,将动态bookStoreEPackage添加到包注册表中。 (此URI在我们生成的序列化模型实例文档中显示为xmlns:book=http:///com.ibm.dynamic.example.bookstore.ecore 。)

清单9.加载模型实例文档
ResourceSet load_resourceSet = new ResourceSetImpl();/*
* Register XML Factory implementation using DEFAULT_EXTENSION
*/
load_resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new XMLResourceFactoryImpl());/*
* Add bookStoreEPackage to package registry
*/
load_resourceSet.getPackageRegistry().put("http:///com.ibm.dynamic.example.bookstore.ecore",bookStoreEPackage);/*
* Load the resource using the URI
*/
Resource load_resource = load_resourceSet.getResource(URI.createURI("./bookStore.xml"),true);/*
* Read back the serialized instances of dynamic classes stored in the 
* resource
*/
EObject readBookStoreObject = (EObject)load_resource.getContents().get(0);
EObject readBookObject = (EObject)((EList)(readBookStoreObject.eGet(bookStore_Books))).get(0);System.out.println("Owner: " + readBookStoreObject.eGet(bookStoreOwner)+ "\nLocation: " + readBookStoreObject.eGet(bookStoreLocation)+ "\nBook:\n name: " + readBookObject.eGet(bookName) + "\t isbn: " + readBookObject.eGet(bookISBN));

在我们的程序包在程序包注册表中注册后,我们通过在资源集实例上调用getResource()方法来加载资源。 这将使用我们作为参数传递给getResource()方法的URI加载模型实例文档。 最后,我们使用反射API访问文档中的序列化实例,如上所示。

如果核心模型的序列化和反序列化是在不同的独立程序中完成的,请遵循此过程。 在这里,加载实例文档的过程保持不变,除了我们不必将动态bookStoreEPackage添加到ResourceSet的包注册表中。 这是因为当我们加载实例文档bookStore.xml时,加载程序会在实例文档的xsi:schemaLocation属性中找到命名空间URI,以打包URI映射。 使用此映射,加载程序将自动加载包含动态bookStoreEPackage的序列化bookStore.ecore模型。 装入此动态包之后,可以使用反射EMF的API以通常的方式访问序列化的实例,如清单9所示。

局限性

与通过EMF生成器生成的模型相比,使用动态EMF构建的模型要慢一些,并占用更多空间。 这是因为动态模型依靠EObjectImpl类提供的反射API的动态实现来获取和设置实例的动态功能。 例如,动态模型将使用较慢的eGet(EstructuralFeature myFeature)方法,而不是所生成的核心模型使用较快的(生成的) getMyFeature()方法。 此外,动态设置在动态模型实例中需要额外的空间,如果使用EMF代码生成器生成模型代码则不需要。

结论

您学习了如何使用动态EMF构建基于Ecore的模型,该模型可以在没有相应Java实现类的情况下即时创建和实例化。 在通过EMF代码生成器生成部分应用程序模型代码,而使用Dynamic EMF构建其余模型代码的情况下,这种构建模型的方法的使用变得特别有趣。 在这种情况和类似情况下,如果有效利用动态EMF,则可以使应用程序以反射方式共享数据大有帮助。 同时,它可以减少生成的实现代码,否则在模型发展时将需要对其进行维护。


翻译自: https://www.ibm.com/developerworks/opensource/library/os-eclipse-dynamicemf/index.html

emf开发

这篇关于emf开发_使用动态EMF建立元模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/484908

相关文章

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

Python Transformer 库安装配置及使用方法

《PythonTransformer库安装配置及使用方法》HuggingFaceTransformers是自然语言处理(NLP)领域最流行的开源库之一,支持基于Transformer架构的预训练模... 目录python 中的 Transformer 库及使用方法一、库的概述二、安装与配置三、基础使用:Pi

关于pandas的read_csv方法使用解读

《关于pandas的read_csv方法使用解读》:本文主要介绍关于pandas的read_csv方法使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录pandas的read_csv方法解读read_csv中的参数基本参数通用解析参数空值处理相关参数时间处理相关

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

SpringBoot条件注解核心作用与使用场景详解

《SpringBoot条件注解核心作用与使用场景详解》SpringBoot的条件注解为开发者提供了强大的动态配置能力,理解其原理和适用场景是构建灵活、可扩展应用的关键,本文将系统梳理所有常用的条件注... 目录引言一、条件注解的核心机制二、SpringBoot内置条件注解详解1、@ConditionalOn

Python中使用正则表达式精准匹配IP地址的案例

《Python中使用正则表达式精准匹配IP地址的案例》Python的正则表达式(re模块)是完成这个任务的利器,但你知道怎么写才能准确匹配各种合法的IP地址吗,今天我们就来详细探讨这个问题,感兴趣的朋... 目录为什么需要IP正则表达式?IP地址的基本结构基础正则表达式写法精确匹配0-255的数字验证IP地

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Spring LDAP目录服务的使用示例

《SpringLDAP目录服务的使用示例》本文主要介绍了SpringLDAP目录服务的使用示例... 目录引言一、Spring LDAP基础二、LdapTemplate详解三、LDAP对象映射四、基本LDAP操作4.1 查询操作4.2 添加操作4.3 修改操作4.4 删除操作五、认证与授权六、高级特性与最佳