淺析Eclipse建模框架(EMF)及其動態能力 – JAVA編程語言程序開發技術文章

如果給定一個模型,那麼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(“https:///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模式,所以指定使用哪些資源來實現(反)串行化你的數據也是很重要的

發佈留言