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.setNscompanyPackage.setNsURI("http:///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模式,所以指定使用哪些資源來實現(反)串行化你的數據也是很重要的。通常,當你調用ResourceSet.createResource(URI)方法時,它查詢Resource.Factory.Registry來查找一個工廠-該工廠是為該URI而注冊的并且使用它來創建一個適當的資源實現。因此,在你(反)串行化你的數據以前,請確保你已注冊了適當的資源工廠實現。EMF提供若干Resource.Factory實現:
·對于XML數據,使用org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl。
·對于XMI數據,使用org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl。
·對于Ecore模型,使用org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl。
你的工具箱中有了這些EMF資源后,你就能使用下面的代碼來串行化你的數據:
//創建資源集和資源
ResourceSet resourceSet = new ResourceSetImpl();
//注冊XML資源工廠
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi",
new XMIResourceFactoryImpl());
Resource resource = resourceSet.createResource(URI.createFileURI("c:/temp/company.xmi"));
//添加根對象到資源
resource.getContents().add(company);
//串行化資源-你還能指定串行化
//選項,它定義在org.eclipse.emf.ecore.xmi.XMIResource中
resource.save(null);
company.xmi被串行化后的形式如下:
<?xml version="1.0" encoding="ASCII"?>
<company:Company xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:company="http:///com.example.company.ecore" name="MyCompany">
<department number="123">
<employees name="John"/>
</department>
</company:Company>
在反串行化過程中,XML數據的命名空間URI被用于定位所需要的Ecore包(它用于描述你的實例文檔的模型)。因此,在你嘗試裝載任何模型以前,請確保你已經為你的文檔將要使用的每個Ecore包注冊了命名空間URI:
//在本地資源注冊表中注冊包
resourceSet.getPackageRegistry().put(companyPackage.getNsURI(), companyPackage);
//加載資源
resource.load(null);
注重到局部的和全局的包(EPackage.Registry.INSTANCE)以及資源工廠(Resource.Factory.Registry.INSTANCE)的注冊差別也是很重要的。全局注冊是靜態的,因此任何應用程序在JVM生存期都能存取全局注冊并且可能覆蓋它。為確保你的注冊不會覆蓋全局注冊并且反過來也如此,典型地,你最好使用局部資源集合注冊。
五、 由XML模式生成動態的Ecore
如前所提及,假如你的模型是一個XML模式但是你沒有選擇生成Java類,那么,你可以通過使用XSDEcoreBuilder來動態地創建一個Ecore模型。這個示例使用了ipo.xsd:
XSDEcoreBuilder xsdEcoreBuilder = new XSDEcoreBuilder();
ResourceSet resourceSet = new ResourceSetImpl();
Collection eCorePackages =xsdEcoreBuilder.generate(URI.createFileURI("c:/temp/ipo.xsd"));
這個generate方法返回為這個模式中的每個URI生成的Ecore包。假如該模式導入了其它命名空間,那么將有多個Ecore包被返回。每個包是被注冊到本地的資源集中-用于實現模式轉換。因此,假如你使用同樣的資源集來裝載你的實例XML文檔的話,你就不需要自己注冊包。
因為XML模式包括更多概念而不僅僅是Ecore,例如通配符等,所以EMF使用Ecore EAnnotations來記錄到XML模式的映射。在數據(反)串行化期間,EMF需要處理這些注解。為了確保這些注解在(反)串行化期間被加以考慮,你必須使用XMLResource.ExtendedMetaData選項:
HashMap options = new HashMap();
options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE);
//請參考http://www.w3.org/TR/2004/PER-xmlschema-0-20040318/#ipo.xml
Resource resource = resourceSet.createResource(URI.createFileURI("c:/temp/ipo.xml"));
resource.load(options);
EMF 2.1還增加了一項新功能-它答應你在加載一個包含一個xsi:schemaLocation或xsi:noNamespaceSchemaLocation屬性的XML文檔時,不斷地把模式轉換成Ecore。同時,它也答應你加載一個沒有與之相關聯的模式的XML文檔。為了使用這一功能,你需要注冊 org.eclipse.emf.ecore.xmi.impl.GenericXMLResourceFactoryImpl:
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml",new GenericXMLResourceFactoryImpl());
六、 小結
本文向你簡短介紹了EMF,并解釋了幾個核心的EMF概念。同時,對于如何利用模式EMF的動態能力提供了相關示例。
新聞熱點
疑難解答