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

相关文章

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

使用Python实现网页表格转换为markdown

《使用Python实现网页表格转换为markdown》在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,本文将使用Python编写一个网页表格转Markdown工具,需... 在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,以便在文档、邮件或

Python使用pynput模拟实现键盘自动输入工具

《Python使用pynput模拟实现键盘自动输入工具》在日常办公和软件开发中,我们经常需要处理大量重复的文本输入工作,所以本文就来和大家介绍一款使用Python的PyQt5库结合pynput键盘控制... 目录概述:当自动化遇上可视化功能全景图核心功能矩阵技术栈深度效果展示使用教程四步操作指南核心代码解析

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

SpringCloud使用Nacos 配置中心实现配置自动刷新功能使用

《SpringCloud使用Nacos配置中心实现配置自动刷新功能使用》SpringCloud项目中使用Nacos作为配置中心可以方便开发及运维人员随时查看配置信息,及配置共享,并且Nacos支持配... 目录前言一、Nacos中集中配置方式?二、使用步骤1.使用$Value 注解2.使用@Configur

如何基于Python开发一个微信自动化工具

《如何基于Python开发一个微信自动化工具》在当今数字化办公场景中,自动化工具已成为提升工作效率的利器,本文将深入剖析一个基于Python的微信自动化工具开发全过程,有需要的小伙伴可以了解下... 目录概述功能全景1. 核心功能模块2. 特色功能效果展示1. 主界面概览2. 定时任务配置3. 操作日志演示

Mac备忘录怎么导出/备份和云同步? Mac备忘录使用技巧

《Mac备忘录怎么导出/备份和云同步?Mac备忘录使用技巧》备忘录作为iOS里简单而又不可或缺的一个系统应用,上手容易,可以满足我们日常生活中各种记录的需求,今天我们就来看看Mac备忘录的导出、... 「备忘录」是 MAC 上的一款常用应用,它可以帮助我们捕捉灵感、记录待办事项或保存重要信息。为了便于在不同

如何Python使用设置word的页边距

《如何Python使用设置word的页边距》在编写或处理Word文档的过程中,页边距是一个不可忽视的排版要素,本文将介绍如何使用Python设置Word文档中各个节的页边距,需要的可以参考下... 目录操作步骤代码示例页边距单位说明应用场景与高级用China编程途小结在编写或处理Word文档的过程中,页边距是一个

SpringBoot项目Web拦截器使用的多种方式

《SpringBoot项目Web拦截器使用的多种方式》在SpringBoot应用中,Web拦截器(Interceptor)是一种用于在请求处理的不同阶段执行自定义逻辑的机制,下面给大家介绍Sprin... 目录一、实现 HandlerInterceptor 接口1、创建HandlerInterceptor实

使用JavaConfig配置Spring的流程步骤

《使用JavaConfig配置Spring的流程步骤》JavaConfig是Spring框架提供的一种基于Java的配置方式,它通过使用@Configuration注解标记的类来替代传统的XML配置文... 目录一、什么是 JavaConfig?1. 核心注解2. 与 XML 配置的对比二、JavaConf