本文主要是介绍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
提供方法来创建像模型元素EClass
, EAttribute
, EPackage
等。使用的实例EcoreFactory
,我们创建了两个EClass
实例:一个用于表示BookStore
类和其它来表示Book
类(如在指定的BookStore
模型) 。 接下来,我们创建一个EPackage
,最终将在其中放置BookStore
和Book
类。 然后,我们定义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框架的四个基本接口对动态模型进行序列化: Resource
, ResourceSet
, Resource.Factory
和URIConverter
。 序列化的过程将取决于我们是否要在要反序列化的同一程序中序列化模型,或者是否希望在与加载或反序列化模型的程序无关的其他程序中序列化模型。
如果要在同一程序中完成核心模型的序列化和反序列化,请执行以下操作; 如果不是,请转到清单7。要初始化序列化过程,我们首先注册XML资源工厂以处理具有任何扩展名的文件,如清单6所示。接下来,我们通过调用createResource()
在资源集中创建一个空资源。 createResource()
方法在ResourceSet
实例上,并将ResourceSet
的实际位置作为URI传递。 我们将EObject
( bookStoreEObject
)添加到该资源的内容列表中,并使用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
属性的序列化模型实例
反序列化/加载动态模型
现在,我们将看到如何加载刚刚序列化的动态模型实例文档。
如果核心模型的序列化和反序列化是在同一程序中完成的,则使用此反序列化过程。 在序列化过程中,我们首先在资源工厂实现中注册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建立元模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!