public interface PurchaseOrder {
String getShipTo();
void setShipTo(String value);
String getBillTo();
void setBillTo(String value);
List<Item> getItems(); // containment reference }
The Eclipse Modeling Framework
Gerson Sunyé gerson.sunye@univ-nantes.fr
Introduction
Defining a Model with EMF
EMF Architecture
The Ecore Modeling Language
Code Generation
Programming with EMF
Summary
Allows us to generate some of the code that we write over and over, paving the way for more complex systems
EMF Models are meant to be mixed with hand-written code
It’s real, proven technology (since 2002)
Current version: 2.31.0 (2022)
Contrary to the belief of many programmers, modeling is useful for more than just documentation
Almost every application manipulates some data model
Defined using UML, XML Schema, some other definition language, or implicitly in Java™
EMF aims to extract this intrinsic "model" and generate some of the implementation code
Improves productivity
Focus on the evolution and promotion of model-based development technologies.
Main technologies:
Core: EMF
Server and storage: CDO, EMFStore, Net4j, Teneo, Model Transaction
User interface: EMF Client Platform, EMF Forms, Extended Editing Framework
Graphical modeling: Sirius, GMF, Graphiti - (…)
Modeling Tools: Business Process Metamodel and Notation, EcoreTools, eTrice, MoDisco, OCL, Papyrus, Sphinx, Unified Modeling Language 2.0, XML Schema Definition
Transformation: Acceleo, ATL, Epsilon, JET, Model-to-Model Transformation, Xpand
Textual Modeling: Xtext
Web Modeling: JSON Forms
Others: EMF Compare, EMF Diff/Merge, Dawn, Amalgam, Validation Framework
Web Tools Platform (WTP)
Data Tools Platform (DTP)
Business Intelligence and Reporting Tools (BIRT)
SOA Tools Platform (STP)…
Large open source user community
Introduction
Defining a Model with EMF
EMF Architecture
The Ecore Modeling Language
Code Generation
Programming with EMF
Summary
Object attributes
References between objects
Operations available on each object
Simple constraints (e.g. multiplicity) on objects and references
Essentially, a simplified UML Class Diagram
Java Interfaces
UML Class Diagram
XML Schema
Ecore Textual Languages: KM3, Emfatic, OCLinEcore
Choose the one matching your perspective or skills and EMF can create the others, as well as the implementation code
public interface PurchaseOrder {
String getShipTo();
void setShipTo(String value);
String getBillTo();
void setBillTo(String value);
List<Item> getItems(); // containment reference }
public interface Item {
String getProductName();
void setProductName(String value);
int getQuantity();
void setQuantity(int value)
float getPrice();
void setPrice(float value); }
Classes can be defined completely by a subset of members, supplemented by annotations
Built-in support for Rational Rose®
UML2 support available with UML2 (from MDT)
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/SimplePO" xmlns:po="http://www.example.com/SimplePO">
<xsd:complexType name="PurchaseOrder">
<xsd:sequence>
<xsd:element name="shipTo" type="xsd:string"/>
<xsd:element name="billTo" type="xsd:string"/>
<xsd:element name="items" type="po:Item" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Item">
<xsd:sequence>
<xsd:element name="productName" type="xsd:string"/>
<xsd:element name="quantity" type="xsd:int"/>
<xsd:element name="price" type="xsd:float"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
class PurchaseOrder {
attr String shipTo;
attr String billTo;
val Item[*] items;
}
class Item {
attr String productName;
attr Integer quantity;
attr Float price;
}
class PurchaseOrder {
attribute shipTo : String;
attribute billTo : String;
property items : Item[*];
}
class Item {
attribute productName : String;
attribute quantity : Integer;
attribute price : Float;
}
All forms provide the same information:
Different visualization/representation
The application’s data "model" or structure
Model importers can be added for different model representations (e.g. RDB Schema)
From a model definition, EMF can generate:
Java implementation code, including UI
XML Schemas
Eclipse plug-in artifacts
Introduction
Defining a Model with EMF
EMF Architecture
The Ecore Modeling Language
Code Generation
Programming with EMF
Summary
Introduction
Defining a Model with EMF
EMF Architecture
The Ecore Modeling Language
Code Generation
Programming with EMF
Summary
Core Runtime
Notification framework
Ecore metamodel
Persistence (XML/XMI), validation, change model
EMF.Edit
Support for model-based editors and viewers
Default reflective editor
Codegen
Code generator for application models and editors
Extensible model importer/exporter framework
Application models (e.g. purchase order model) are instances of Ecore
Follows OMG XML Metadata Interchange (XMI) standard
Common file extension: .ecore
<eClassifiers xsi:type="ecore:EClass"
name="PurchaseOrder">
<eStructuralFeatures xsi:type="ecore:EReference"
name="items" eType="#//Item"
upperBound="-1" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EAttribute"
name="shipTo" eType="ecore:EDataType http:...Ecore#//EString"/>
...
</eClassifiers>
Customizable, JSP-like templates (JET)
JDT-integrated, command-line or Ant
Full support for regen and merge
Sample Ecore editor (in EMF)
Ecore Tools graphical editor (from EMFT)
Ecore is EMF’s (meta-) modeling language
Ecore models can represent both:
application data models
abstract syntax from other modeling languages (meta-models)
EClasses represent modeling language concepts
ECLasses have:
EAttributes representing their structure
EReferences to other classes
EAttributes describe the structure and values of instances o EClass
EAttrributes have types: EString
, EChar
, EInt
, EDouble
, EBoolean
, etc.
EReferences represent a reference from an instance of an ECLass to an instance of another EClass
EReferences may be containments and also bidirectionals
Particularity of Ecore: Containment EReferences must form a tree:
Introduction
Defining a Model with EMF
EMF Architecture
The Ecore Modeling Language
Code Generation
Programming with EMF
Summary
Codegen reads Ecore instances (models) and generate Java classes
The Ecore classes and the generated classes share the same super-classes
Includes get/set accessors for attributes and references
public interface PurchaseOrder extends EObject {
String getShipTo();
void setShipTo(String value);
String getBillTo();
void setBillTo(String value);
EList<Item> getItems();
}
public class PurchaseOrderImpl extends EObjectImpl
implements PurchaseOrder {
...
}
EObject
is also a Notifier:Sends notification whenever an attribute or reference is changed
Observers can update views, dependent objects
Observers are also adapters
Adapter adapter = ...
purchaseOrder.eAdapters().add(adapter);
Efficient notification from set methods
public String getBillTo() {
return billTo;
}
public void setBillTo(String newBillTo) {
String oldBillTo = BillTo;
billTo = newBillTo;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, … , oldBillTo, billTo);
}
Bidirectional reference imposes invariant: po.getNext().getPrevious() == po
public interface PurchaseOrder {
// ()...)
PurchaseOrder getNext();
void setNext(PurchaseOrder value);
PurchaseOrder getPrevious();
void setPrevious(PurchaseOrder value);
}
Multi-step procedure implemented using InternalEObject
methods:
eInverseRemove()
eInverseAdd()
Framework list implementations and generated setters directly invoke them on target objects as needed
Notifications accumulated using a NotificationChain and fired off at the end
Not used to implement the handshaking
p1.setNext(p3);
Notification is send.
Factory to create instances of model classes
POFactory factory = POFactory.eINSTANCE;
PurchaseOrder order = factory.createPurchaseOrder();
Package provides access to metadata
POPackage poPackage = POPackage.eINSTANCE;
EClass itemClass = POPackage.Literals.ITEM;
//or poPackage.getItem()
EAttribute priceAttr = POPackage.Literals.ITEM__PRICE;
//or poPackage.getItem_Price()
//or itemClass.getEStructuralFeature(POPackage.ITEM__PRICE)
All EMF classes implement EObject
interface
Provides an efficient API for manipulating objects reflectively
Used by framework (e.g. persistence framework, copy utility, editing commands)
Key to integrating EMF-based tools and applications
public interface EObject {
EClass eClass();
Object eGet(EStructuralFeature sf);
void eSet(EStructuralFeature sf, Object val);
...
}
Efficient generated switch-based implementation of reflective methods
public Object eGet(int featureID, ...) {
switch (featureID) {
case POPackage.PURCHASE_ORDER__ITEMS: return getItems();
case POPackage.PURCHASE_ORDER__SHIP_TO: return getShipTo();
case POPackage.PURCHASE_ORDER__BILL_TO: return getBillTo();
...
}
...
}
Model
Interfaces and classes
Package (metadata)
Factory
Switch utility
Adapter factory base
Validator
Custom resource
XML Processor
Manifests, plug-in classes, properties, icons…
Edit (UI Independent)
Item providers
Item provider adapter factory
Editor
Model Wizard
Editor
Action bar contributor
Advisor (RCP)
Tests
Test cases
Test suite
Stand-alone example
The EMF generator is a merging generator
/** * <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getName() {
return name;
}
@generated
elements are replaced/removed
To preserve changes mark @generated NOT
Generated methods can be extended through redirection
public String getName() {
return format(getNameGen());
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public String getNameGen() {
return name;
}
Introduction
Defining a Model with EMF
EMF Architecture
The Ecore Modeling Language
Code Generation
Programming with EMF
Summary
Persisted data is referred to a resource
Objects can be spread out among a number of resources, within a resource set
Proxies represent referenced objects in other resources
Context for multiple resources that may have references among them
Usually just an instance of ResourceSetImpl
Provides factory method for creating new resources in the set
ResourceSet rs = new ResourceSetImpl();
URI uri = URI.createFileURI("/tmp/po.xml");
Resource resource = rs.createResource(uri);
Also provides access to the registries, URI converter and default load options for the set
Returns a resource factory for a given type of resource
Based on URI scheme, filename extension or content type
Determines the format for save/load
If no registered resource factory found locally, delegates to global registry: Resource.Factory.Registry.INSTANCE
Returns the package identified by a given namespace URI
Used during loading to access factory for instantiating classes
If no registered package found locally, delegates to global registry: EPackage.Registry.INSTANCE
Convert to and from persistent form via save()
and load()
Access contents of resource via getContents()
URI uri = URI.createFileURI("/tmp/po.xml");
Resource resource = rs.createResource(uri);
resource.getContents().add(p1);
resource.save(null);
Other, customized implementations, too (e.g. XMI, EMOF)
<PurchaseOrder>
<shipTo>John Doe</shipTo>
<next>p2.xml#p2</next>
</PurchaseOrder>
A DocumentRoot class is included in models created from XML Schema
Includes one containment reference per global element
<xsd:schema ... >
<xsd:element name="order" type="po:PurchaseOrder">
<xsd:element name="item" type="po:Item">
...
</xsd:schema>
Use an XMLResource with extended metadata enabled (e.g. use the resource factory generated with your model)
Use an instance of the DocumentRoot in the resource’s contents
Set the appropriate reference to select the root element
PurchaseOrder p1 = ...
URI uri = URI.createFileURI("/tmp/order.po");
resource resource = rs.createResource(uri);
DocumentRoot root = POFactory.eINSTANCE.createDocumentRoot();
resource.getContents().add(root);
root.setOrder(p1);
resource.save(null);
Setting an attribute using generated API
PurchaseOrder po = ...
po.setBillTo("123 Elm St.");
Using reflective API
EObject po = ...
EClass poClass = po.eClass();
po.eSet(poClass.getEStructuralFeature("billTo"), "123 Elm St.");
An Ecore model can also be defined at runtime using Ecore API or loaded from persistent form
No generated code required
Dynamic implementation of reflective EObject API provides same runtime behavior as generated code
Can create dynamic subclasses of generated classes
The framework treats all model instances the same, whether generated or dynamic
The change model represents changes to instances of any EMF model
Adapter that creates change description based on notifications, to describe reverse delta
Provides transaction capability
ChangeRecorder changeRecorder =
new ChangeRecorder(resourceSet);
try {
// modifications within resource set
}
catch (Exception e) {
changeRecorder.endRecording().apply();
}
Models can define named constraints and invariants for batch validation
Invariant
Defined directly on class, as <> operation
Stronger statement about validity than a constraint
Constraint
Externally defined via a validator
Invariants and constraints are invoked by a validator, which is generated for a package, if needed
Bodies of invariants and constraints are usually hand-coded
EObjectValidator
validates basic constraints on all EObjects
(multiplicity, data type values, etc.)
Used as base of generated validators and directly for packages without additional constraints defined.
In XML Schema, constraints can be defined as facets on simple types
Full implementation generated in validator
<xsd:simpleType name="SKU">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[A-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
Diagnostician.validate()
is the usual entry point
Detailed results accumulated as Diagnostics
Diagnostician validator = Diagnostician.INSTANCE;
Diagnostic diagnostic = validator.validate(order);
if (diagnostic.getSeverity() == Diagnostic.ERROR) {
// handle error
}
for (Diagnostic child : diagnostic.getChildren()) {
// handle child diagnostic
}
Class EcoreUtil
provides various static convenience utilities for working with EObjects
Copying
EObject copy = EcoreUtil.copy(original);
Testing equality
boolean equal = EcoreUtil.equals(eObject1, eObject2);
Also, cross referencing, contents/container navigation, annotation, proxy resolution, adapter selection, and more…
Introduction
Defining a Model with EMF
EMF Architecture
The Ecore Modeling Language
Code Generation
Programming with EMF
Summary
EMF is low-cost modeling for the Java mainstream
Leverages the intrinsic model in an application
No high-level modeling tools required
Mixes modeling with programming to maximize the effectiveness of both
Boosts productivity and integrates integration
The foundation for model-driven development and data integration in Eclipse
EMF for Eclipse Theia (Eclipse on the Cloud)
Inspired by VSCode!
Main components:
Model Server (REST API)
Ecore tools
EMF documentation in Eclipse Help
Overviews, tutorials, API reference
EMF project Web site
Downloads, documentation, FAQ, newsgroup, Bugzilla, Wiki
Eclipse Modeling Framework, by Frank Budinsky et al.
ISBN: 0131425420
Rough cut of second edition available