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

emf开发
(EMF)描述了数据模型,并允许从不同类型的数据模型工件(例如XML,?模型,Ecore模型或Java注释)轻松生成代码 。在代码生成过程中,EMF生成器会创建模型代码,其中包括类型安全接口和数据模型的实现类 。但是,在某些情况下,应用程序不需要这些类型安全的接口和实现类 。相反,需要可以在应用程序组件之间共享或由应用程序组件进一步处理的数据对象 。
在这种情况下,动态EMF派上用场,因为它允许应用程序开发人员在运行时以编程方式制造内存中的核心模型,动态地创建其实例,并使用EMF反射API访问模型实例元素 。
为什么选择动态EMF?
EMF的主要价值在于,它允许您在运行时仅用几行代码即可构建基于Ecore的模型,然后出于各种目的创建和访问此动态模型的实例 。以这种方式构建核心模型有助于避免在不需要接口和实现类时生成它们 。
这种创建模型和模型实例的方法在(但不限于)以下场景中特别有用:
创建动态内存核心模型
我们首先以编程方式构建基于动态Ecore的模型,然后创建该模型的动态实例 。稍后,我们将看到如何读写模型实例中存在的元素的值 。
创建基于Ecore的动态模型/元模型
我们将考虑一个书店模型来演示动态Ecore模型的创建 。为了清楚起见,我们使用统一建模语言(UML)表示模型 。
图1. 模型
我们首先创建一组核心模型元素,包括一个实例,一个实例,两个实例和一个实例 。参见清单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");
所述提供方法来创建像模型元素,,等 。使用的实例,我们创建了两个实例:一个用于表示类和其它来表示Book类(如在指定的模型)。接下来,我们创建一个,最终将在其中放置和Book类 。然后,我们定义的名称和属性 。由于包的名称不必是唯一的,因此应向提供URI以唯一标识它 。这是通过使用()方法设置nsURI属性的值来完成的 。
现在,我们为动态类创建数据模型指定的属性 。要为每个属性设置模型化的数据类型,我们实例化,其中包含用于表示每种数据类型的元对象的访问器 。参见清单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());
接下来,我们需要将每个类的属性添加到相应类的列表中 。最后,我们将两个类都放入动态包。这样就完成了给定模型的元模型的创建 。
清单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模型后,我们可以创建模型中存在的动态类的实例 。我们首先通过在上调用()方法来获得一个实例 。
清单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代码生成器生成的,它将为模型的包和工厂提供实现类 。正在初始化的生成包(通过其构造函数)注册生成的工厂,并实例化对生成的工厂类的引用 。因此,在生成的包上调用()方法将返回相应的生成的工厂 。由于我们的动态核心模型中没有任何生成的工厂,也没有任何类型的生成的类,因此在上调用()方法将返回动态工厂的实例 。
定义了()操作,该操作创建并返回指定为参数的模型类的新实例 。对于生成的模型代码,此方法被生成的工厂覆盖,以创建和返回相应的生成的模型类的实例 。在动态元模型,因为没有生成的工厂/模型实现类,调用()的方法实例将返回的实例。
读写动态模型
类包含所有反射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);
同样,可以在需要时在模型类上调用类中实现的其他反射API( ()和() ) 。
序列化动态模型
可以使用EMF 框架的四个基本接口对动态模型进行序列化:,,.和。序列化的过程将取决于我们是否要在要反序列化的同一程序中序列化模型,或者是否希望在与加载或反序列化模型的程序无关的其他程序中序列化模型 。
如果要在同一程序中完成核心模型的序列化和反序列化,请执行以下操作; 如果不是,请转到清单7 。要初始化序列化过程,我们首先注册XML资源工厂以处理具有任何扩展名的文件,如清单6所示 。接下来,我们通过调用()在资源集中创建一个空资源 。()方法在实例上,并将的实际位置作为URI传递 。我们将 ()添加到该资源的内容列表中,并使用save()方法将资源复制到其持久性存储中 。(如果需要,资源集可以使用来定位资源或将输入URI规范化为资源的实际URI 。)
清单6.序列化动态模型实例
ResourceSet resourceSet = new ResourceSetImpl();/** Register XML Factory implementation using DEFAULT_EXTENSION*/resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", newXMLResourceFactoryImpl());/** 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 。在加载动态模型时,我们需要访问动态包。如果要将模型装入序列化的同一程序中,则可以轻松完成此操作(请参阅下一节) 。但是,如果要在与序列化模型不同的程序中加载模型,则需要在序列化模型实例之前序列化动态Ecore模型,以便能够访问。
清单7.序列化元模型
ResourceSet metaResourceSet = new ResourceSetImpl();/** Register XML Factory implementation to handle .ecore files*/metaResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", newXMLResourceFactoryImpl());/** 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扩展名的文件,因为核心模型将使用该扩展名进行序列化 。接下来,我们创建一个空资源,并将动态包添加到此新创建资源的内容列表中 。最后,我们保存此资源 。
生成的序列化动态核心模型或元模型如图3所示 。
图3.序列化的动态核心模型
现在我们序列化模型实例文档:.xml 。唯一的区别是这次,实例文档使用附加属性xsi:进行了序列化 。加载程序将使用此属性来查找持久资源.ecore,其中包含加载模型实例文档所需的序列化。
清单8.使用xsi:属性序列化模型实例文档
ResourceSet resourceSet = new ResourceSetImpl();resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", newXMLResourceFactoryImpl());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();}
序列化的模型实例文档.xml将带有xsi:属性,如下所示 。
图4.具有xsi:属性的序列化模型实例
反序列化/加载动态模型
现在,我们将看到如何加载刚刚序列化的动态模型实例文档 。
如果核心模型的序列化和反序列化是在同一程序中完成的,则使用此反序列化过程 。在序列化过程中,我们首先在资源工厂实现中注册XML,以处理具有任何扩展名的文件 。之后,我们使用序列化模型时给定的相同名称空间URI,将动态添加到包注册表中 。(此URI在我们生成的序列化模型实例文档中显示为xmlns:book=。)
清单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));
在我们的程序包在程序包注册表中注册后,我们通过在资源集实例上调用()方法来加载资源 。这将使用我们作为参数传递给()方法的URI加载模型实例文档 。最后,我们使用反射API访问文档中的序列化实例,如上所示 。
如果核心模型的序列化和反序列化是在不同的独立程序中完成的,请遵循此过程 。在这里,加载实例文档的过程保持不变,除了我们不必将动态添加到的包注册表中 。这是因为当我们加载实例文档.xml时,加载程序会在实例文档的xsi:属性中找到命名空间URI,以打包URI映射 。使用此映射,加载程序将自动加载包含动态的序列化.ecore模型 。装入此动态包之后,可以使用反射EMF的API以通常的方式访问序列化的实例,如清单9所示 。
局限性
与通过EMF生成器生成的模型相比,使用动态EMF构建的模型要慢一些,并占用更多空间 。这是因为动态模型依靠类提供的反射API的动态实现来获取和设置实例的动态功能 。例如,动态模型将使用较慢的eGet( )方法,而不是所生成的核心模型使用较快的(生成的) ()方法 。此外,动态设置在动态模型实例中需要额外的空间,如果使用EMF代码生成器生成模型代码则不需要 。
结论
您学习了如何使用动态EMF构建基于Ecore的模型,该模型可以在没有相应Java实现类的情况下即时创建和实例化 。在通过EMF代码生成器生成部分应用程序模型代码,而使用 EMF构建其余模型代码的情况下,这种构建模型的方法的使用变得特别有趣 。在这种情况和类似情况下,如果有效利用动态EMF,则可以使应用程序以反射方式共享数据大有帮助 。同时,它可以减少生成的实现代码,否则在模型发展时将需要对其进行维护 。
翻译自:
【emf开发_使用动态EMF建立元模型】emf开发