Preparing EMF Models for CDO

 

Author: Eike Stepper

Table of Contents

Creating an Ecore Model
Using the CDO Model Importer
Using the CDO Model Migrator
Migrating a GenModel Manually
Generating a Model
Modifying Generated Getters and Setters

1  Creating an Ecore Model

There's really not much to say about this step. The .ecore file for CDO models is the same as for pure EMF models. Use the Empty EMF Project New Wizard to create an initial project for your model:

Create an ordinary Ecore model file in the models folder. The model1 example model in the usual Ecore model editor looks like follows:

The XML representation of this Ecore model is:

company.ecore      
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ecore=
"http://www.eclipse.org/emf/2002/Ecore" name="company" nsURI="http://www.eclipse.org/emf/CDO/examples/company/1.0.0"
    nsPrefix=
"company">
  
<eClassifiers xsi:type="ecore:EClass" name="Addressable" abstract="true">
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="street" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="city" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="Company" eSuperTypes="#//Addressable">
    
<eStructuralFeatures xsi:type="ecore:EReference" name="categories" upperBound="-1"
        eType=
"#//Category" containment="true"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="suppliers" upperBound="-1"
        eType=
"#//Supplier" containment="true"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="customers" upperBound="-1"
        eType=
"#//Customer" containment="true"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="purchaseOrders" upperBound="-1"
        eType=
"#//PurchaseOrder" containment="true"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="salesOrders" upperBound="-1"
        eType=
"#//SalesOrder" containment="true"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="Supplier" eSuperTypes="#//Addressable">
    
<eStructuralFeatures xsi:type="ecore:EReference" name="purchaseOrders" upperBound="-1"
        eType=
"#//PurchaseOrder" eOpposite="#//PurchaseOrder/supplier"/>
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="preferred" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
        defaultValueLiteral=
"true"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="Customer" eSuperTypes="#//Addressable">
    
<eStructuralFeatures xsi:type="ecore:EReference" name="salesOrders" upperBound="-1"
        eType=
"#//SalesOrder" eOpposite="#//SalesOrder/customer"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="Order">
    
<eStructuralFeatures xsi:type="ecore:EReference" name="orderDetails" upperBound="-1"
        eType=
"#//OrderDetail" containment="true" eOpposite="#//OrderDetail/order"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="OrderDetail">
    
<eStructuralFeatures xsi:type="ecore:EReference" name="order" lowerBound="1" eType="#//Order"
        eOpposite=
"#//Order/orderDetails"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="product" eType="#//Product"/>
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="price" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloat"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="PurchaseOrder" eSuperTypes="#//Order">
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="date" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="supplier" lowerBound="1"
        eType=
"#//Supplier" eOpposite="#//Supplier/purchaseOrders"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="SalesOrder" eSuperTypes="#//Order">
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="id" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="customer" lowerBound="1"
        eType=
"#//Customer" eOpposite="#//Customer/salesOrders"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="Category">
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="categories" upperBound="-1"
        eType=
"#//Category" containment="true"/>
    
<eStructuralFeatures xsi:type="ecore:EReference" name="products" upperBound="-1"
        eType=
"#//Product" containment="true"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EClass" name="Product">
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="vat" eType="#//VAT" defaultValueLiteral="vat15"/>
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
        transient=
"true"/>
    
<eStructuralFeatures xsi:type="ecore:EAttribute" name="price" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloat"/>
  
</eClassifiers>
  
<eClassifiers xsi:type="ecore:EEnum" name="VAT">
    
<eLiterals name="vat0"/>
    
<eLiterals name="vat7" value="7"/>
    
<eLiterals name="vat15" value="15"/>
  
</eClassifiers>
</ecore:EPackage>

The model project should look similar to this, now:

2  Using the CDO Model Importer

The easiest way to create a CDO enabled GenModel is to use the CDO Migrator utility that is shipped with the CDO SDK. It includes a special Ecore Model Importer that adjusts all the GenModel properties needed to generated CDO native models. Right-click the Ecore model file and select New and Other... and choose the EMF Generator Model New Wizard:

On the next page, the Select a Model Importer page, select the Ecore model (CDO native) importer:

On the next page, the Ecore Import page, click the Load button:

On the next page, the Package Selection page, adjust the settings depending on your model and its referenced models:

After clicking the Finish button your model project should look similar to this (please note that the CDO marker file META-INF/CDO.MF has also been created by the importer):

3  Using the CDO Model Migrator

If you don't want to use the CDO Model Importer to automatically let a proper GenModel be created for you it is still rather easy to migrate an existing GenModel with the CDO Migrator:

In case the generator model was successfully migrated to CDO the following dialog box will appear:

Proceed with Generate The Model.

4  Migrating a GenModel Manually

If you don't want to use the CDO Model Importer to automatically let a proper GenModel be created for you it is still rather easy to migrate an existing GenModel by hand.

The EMF generator model for your Ecore model is much like a usual GenModel except for the following four differences:

Note that you do not need to generate an editor if you want to use your model with the CDO User Interface A dedicated model editor is only needed if you plan to use your model with normal XML based files as well. Even in this scenario it could be simpler to use the EMF Reflective Model Editor though.

The XML representation of this GenModel is:

company.genmodel      
<?xml version="1.0" encoding="UTF-8"?>
<genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
    xmlns:genmodel=
"http://www.eclipse.org/emf/2002/GenModel" modelDirectory="/org.eclipse.emf.cdo.examples.company/src" creationIcons="false"
    editDirectory=
"/org.eclipse.emf.cdo.examples.company.edit/src" editorDirectory=""
    modelPluginID=
"org.eclipse.emf.cdo.examples.company" modelName="Company" editPluginClass="org.eclipse.emf.cdo.examples.company.provider.CompanyEditPlugin"
    editorPluginClass=
"" updateClasspath="false" rootExtendsClass="org.eclipse.emf.internal.cdo.CDOObjectImpl"
    reflectiveDelegation=
"true" codeFormatting="true" testsDirectory="" testSuiteClass="org.eclipse.emf.cdo.examples.company.tests.CompanyAllTests"
    importerID=
"org.eclipse.emf.importer.ecore" featureDelegation="Reflective" complianceLevel="8.0"
    providerRootExtendsClass=
"org.eclipse.emf.cdo.edit.CDOItemProviderAdapter" editPluginID="org.eclipse.emf.cdo.examples.company.edit"
    editorPluginID=
"org.eclipse.emf.cdo.examples.company.editor" testsPluginID="org.eclipse.emf.cdo.examples.company.editor"
    optimizedHasChildren=
"true" colorProviders="true" fontProviders="true" runtimeVersion="2.6">
  
<foreignModel>company.ecore</foreignModel>
  
<modelPluginVariables>CDO=org.eclipse.emf.cdo</modelPluginVariables>
  
<genPackages prefix="Company" basePackage="org.eclipse.emf.cdo.examples" disposableProviderFactory="true"
      extensibleProviderFactory=
"true" childCreationExtenders="true" ecorePackage="company.ecore#/">
    
<genEnums typeSafeEnumCompatible="false" ecoreEnum="company.ecore#//VAT">
      
<genEnumLiterals ecoreEnumLiteral="company.ecore#//VAT/vat0"/>
      
<genEnumLiterals ecoreEnumLiteral="company.ecore#//VAT/vat7"/>
      
<genEnumLiterals ecoreEnumLiteral="company.ecore#//VAT/vat15"/>
    
</genEnums>
    
<genClasses image="false" ecoreClass="company.ecore#//Addressable">
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Addressable/name"/>
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Addressable/street"/>
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Addressable/city"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//Company">
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Company/categories"/>
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Company/suppliers"/>
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Company/customers"/>
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Company/purchaseOrders"/>
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Company/salesOrders"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//Supplier">
      
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference company.ecore#//Supplier/purchaseOrders"/>
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Supplier/preferred"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//Customer">
      
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference company.ecore#//Customer/salesOrders"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//Order">
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Order/orderDetails"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//OrderDetail">
      
<genFeatures property="None" notify="false" createChild="false" ecoreFeature="ecore:EReference company.ecore#//OrderDetail/order"/>
      
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference company.ecore#//OrderDetail/product"/>
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//OrderDetail/price"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//PurchaseOrder">
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//PurchaseOrder/date"/>
      
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference company.ecore#//PurchaseOrder/supplier"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//SalesOrder">
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//SalesOrder/id"/>
      
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference company.ecore#//SalesOrder/customer"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//Category">
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Category/name"/>
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Category/categories"/>
      
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference company.ecore#//Category/products"/>
    
</genClasses>
    
<genClasses ecoreClass="company.ecore#//Product">
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Product/name"/>
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Product/vat"/>
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Product/description"/>
      
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute company.ecore#//Product/price"/>
    
</genClasses>
  
</genPackages>
</genmodel:GenModel>

5  Generating a Model

Generate the Java code for your model as you are used to do it:

The result of the generation can look similar to this (some artifacts are hidden to remove noise from the Package Explorer):

6  Modifying Generated Getters and Setters

If you want to modify the behavior of generated getters and setters (or have already done so in existing models) you might want to try dynamic feature delegation (introduced in EMF 2.5). With this pattern, the reflective methods like eGet still call your generated method like getX() and then that calls the dynamic reflective method like eDynamicGet. It effectively produces the same behavior as "Reflective" delegating but does so by delegating through your generated accessors allowing you to specialize those as you could when you used "None"...