Más contenido relacionado La actualidad más candente (20) Similar a Building RESTful Java Applications with EMF (20) Building RESTful Java Applications with EMF1. Building RESTful Java™ Applications
with EMF
Marcelo Paternostro, IBM
Kenn Hussey, Embarcadero Technologies
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 1
2. Model Driven Software Development
• Software is focused on manipulating data
• Data has abstract structure
– It can be described at a high level
– It can be represented in different ways
– It’s always a model of something
• The description of the data is yet more data
– It’s commonly referred to as metadata
– Meta is a bit confusing
– The model of a model is a model
• Whether it’s recognized or not, models drive
software development
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 2
3. What is REST?
• Representational State Transfer is a style of software
architecture for distributed hypermedia systems such as the
World Wide Web
• The term was introduced in the doctoral dissertation of Roy
Fielding, one of the principal authors of the Hypertext
Transfer Protocol™ (HTTP™) specification, in 2000, and has
come into widespread use in the networking community
• Strictly speaking, REST refers to a collection of network
architecture principles that outline how resources are defined
and addressed
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 3
4. REST is Not Just for the Web
• The term REST is often used in a looser sense to describe any
simple interface that transmits domain-specific data over
HTTP without an additional messaging layer such as SOAP or
session tracking via HTTP cookies
• In fact, it is possible to design any enterprise software system
in accordance with Fielding's REST architectural style
without using the HTTP protocol and without interacting
with the World Wide Web
• Systems that follow the principles of REST often referred to as
RESTful
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 4
5. REST Principles
• Proponents of REST argue that the Web enjoyed the
scalability and growth that it has had as a direct result of a
few key design principles
– application state and functionality are divided into resources
– every resource is uniquely addressable using a universal syntax for use
in hypermedia links
– all resources share a uniform interface for the transfer of state
between client and resource, consisting of a constrained set of
content types and a constrained set of well-defined operations
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 5
6. CRUD
• The four basic operations of persistent storage –
create, read, update and delete – are a major part of nearly
all computer software
• The acronym CRUD refers to all of the major functions that
need to be implemented in a relational database application
or RESTful application to consider it complete
• We’ll look at how Java applications based on these
operations, and the REST principles in general, are supported
by EMF APIs and suggest some best practices for working
with resources in EMF
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 6
7. Eclipse Modeling Framework
• A simple, pragmatic, Java-based framework that
provides
– The Ecore API for describing models
– The EObject API for manipulating instances
– A resource framework for RESTful persistence
– A generator framework for producing development
artifacts
– A runtime along with utilities for
traversing, indexing, copy, change recording, and so on
– Tools for working with models and their instances
• EMF was used to develop EMF
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 7
8. A Brief History of EMF
• Started at IBM in the late 90’s
– It supported Object Management Group™ (OMG™) specifications
– It implemented Meta Object Facility (MOF™)
– It used XML™ Metadata Interchange (XMI®)
– It’s closely related to Java Metadata Interface (JMI)
• Problems surfaced for adopters
– The MOF model was far too complex
– The generated code and runtime were bloated and performed poorly
• “ETools Modeling Framework” (EMF) was kicked off in 2000
– Boiled MOF down to its essential components, resulting in Ecore
– Revamped the runtime and tools to make them lean and mean
• Contributed to Eclipse in September 2002
– Rebranded as the Eclipse Modeling Framework
– Fed back to OMG resulting in Essential MOF/Complete MOF split
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 8
9. Ecore: The Model of Models
• A simple model for describing models
– Classification of objects
– Attributes of those objects
– Relationships/associations between those objects
– Operations on those objects
– Simple constraints on those objects, and their attributes
and relationships
• Ecore is self describing, i.e., it is its own model
• Models higher up in the meta levels tend to all look
the same
– They begin to conform to our mental model
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 9
10. Relationship of Ecore to Other Models
UML® XML Schema
Ecore
Java
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 10
11. A Model is a Model is a Model
UML XML Schema
<xsd:complexType name=quot;Nodequot;>
<xsd:sequence>
<xsd:element
Ecore
name=quot;childrenquot;
type=quot;tree:Nodequot;
minOccurs=quot;0quot;
maxOccurs=quot;unboundedquot;
ecore:opposite=quot;parentquot;/>
</xsd:sequence>
<xsd:attribute
name=quot;labelquot;
type=quot;xsd:stringquot;/>
</xsd:complexType>
Java
public interface Node {
String getLabel();
void setLabel(String value);
List<Node> getChildren();
Node getParent();
void setParent(Node value);
} // Node
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 11
13. Ecore Data Types
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 13
14. Ecore Annotations and EObject
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 14
16. The Tree Ecore Model
EPackage
name tree
nsURI http://www.example.org/tree
eClassifiers Node
EClass
name Node
eStructuralFeatures label, children, parent
EAttribute EReference EReference
name label name children name parent
eType EString eType Node eType Node
lowerBound 0 lowerBound 0 lowerBound 0
upperBound 0 upperBound -1 upperBound 1
containment true containment false
eOpposite parent eOpposite children
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 16
17. The Tree Ecore Model Serialized as XMI
<?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?>
<ecore:EPackage xmi:version=quot;2.0quot;
xmlns:xmi=quot;http://www.omg.org/XMIquot;
xmlns:xsi=quot;http://www.w3.org/2001/XMLSchema-instancequot;
xmlns:ecore=quot;http://www.eclipse.org/emf/2002/Ecorequot;
name=quot;treequot;
nsURI=quot;http://www.example.org/treequot;
nsPrefix=quot;treequot;>
<eClassifiers xsi:type=quot;ecore:EClassquot; name=quot;Nodequot;>
<eStructuralFeatures xsi:type=quot;ecore:EAttributequot; name=quot;labelquot;
eType=quot;ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EStringquot;/>
<eStructuralFeatures xsi:type=quot;ecore:EReferencequot; name=quot;childrenquot; upperBound=quot;-1quot;
eType=quot;#//Nodequot; containment=quot;truequot; eOpposite=quot;#//Node/parentquot;/>
<eStructuralFeatures xsi:type=quot;ecore:EReferencequot; name=quot;parentquot;
eType=quot;#//Nodequot; eOpposite=quot;#//Node/childrenquot;/>
</eClassifiers>
</ecore:EPackage>
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 17
18. The Tree Ecore Model Serialized as EMOF
<?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?>
<emof:Package xmi:version=quot;2.0quot;
xmlns:xmi=quot;http://www.omg.org/XMIquot;
xmlns:emof=quot;http://schema.omg.org/spec/MOF/2.0/emof.xmlquot;
xmi:id=quot;treequot;
name=quot;treequot;
uri=quot;http://www.example.org/treequot;>
<ownedType xmi:type=quot;emof:Classquot; xmi:id=quot;tree.Nodequot; name=quot;Nodequot;>
<ownedAttribute xmi:id=quot;tree.Node.labelquot; name=quot;labelquot;
isOrdered=quot;truequot; lower=quot;0quot;>
<type xmi:type=quot;emof:PrimitiveTypequot;
href=quot;http://schema.omg.org/spec/MOF/2.0/emof.xml#Stringquot;/>
</ownedAttribute>
<ownedAttribute xmi:id=quot;tree.Node.childrenquot; name=quot;childrenquot;
isOrdered=quot;truequot; lower=quot;0quot; upper=quot;*quot; type=quot;tree.Nodequot;
isComposite=quot;truequot; opposite=quot;tree.Node.parentquot;/>
<ownedAttribute xmi:id=quot;tree.Node.parentquot; name=quot;parentquot;
isOrdered=quot;truequot; lower=quot;0quot; type=quot;tree.Nodequot;
opposite=quot;tree.Node.childrenquot;/>
</ownedType>
<xmi:Extension extender=quot;http://www.eclipse.org/emf/2002/Ecorequot;>
<nsPrefix>tree</nsPrefix>
</xmi:Extension>
</emof:Package>
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 18
19. A Tree Instance Model
Node
label Root
children A, B
parent
Node Node
label A label B
children X children Y
parent Root parent Root
Node Node
label X label Y
children children
parent A parent B
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 19
20. A Tree Instance Model Serialized as XMI
<tree:Node xmi:version=quot;2.0quot;
xmlns:xmi=quot;http://www.omg.org/XMIquot;
xmlns:tree=quot;http://www.example.org/treequot;
label=quot;rootquot;>
<children label=quot;Aquot;>
<children label=quot;Xquot;/>
</children>
<children label=quot;Bquot;>
<children label=quot;Yquot;/>
</children>
</tree:Node>
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 20
21. The EMF Generator Model
• The GenModel is a decorator for tailoring the generated code
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 21
23. EMF in Action
• Demo time!
– Show how to create the Ecore Tree model from scratch
using the Sample Ecore Editor
– Show how to use Ecore Tools for diagrams
– Show how to exploit dynamic models to create Tree
instances
– Demonstrate the interchangeable nature of models
• Generate the Java realization
• Export to XML Schema
• Show how these round trip
• Show how to run the example
• Show how to run the generated editor
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 23
24. Completing the Picture
• To show the full generation picture, we need examples
of EDataTypes, EEnums, and EOperations
• An EDataType is effectively just a named alias for some
existing Java class
– Most data types support conversion to and from a string
representation in order to support persistence
– Values of data types generally should be treated as immutable
leaves
• An EEnum is a specialized EDataType that specifies a list
of EEnumLiterals which exhaustively enumerates all
possible values of the data type
• An EOperation is simply the specification of the
signature of an operation that can be invoked on a class
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 24
25. A Richer Tree Ecore Model
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 25
26. Generated EPackage
package org.example.tree;
// ...
public interface TreePackage extends EPackage
{
String eNAME = quot;treequot;;
String eNS_URI = quot;http://www.example.org/treequot;;
String eNS_PREFIX = quot;treequot;;
TreePackage eINSTANCE = TreePackageImpl.init();
// ...
interface Literals
{
// ...
}
}
package org.example.tree.impl;
// ...
public class TreePackageImpl
extends EPackageImpl
implements TreePackage
{
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 26
27. Generated EFactory
package org.example.tree;
// ...
public interface TreeFactory extends EFactory
{
TreeFactory eINSTANCE = TreeFactoryImpl.init();
// ...
}
package org.example.tree.impl;
// ...
public class TreeFactoryImpl
extends EFactoryImpl
implements TreeFactory
{
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 27
28. Generated EPackage Utility Classes
package org.example.tree.util;
// ...
public class TreeAdapterFactory
extends AdapterFactoryImpl
{
// ...
}
package org.example.tree.util;
// ...
public class TreeSwitch<T>
{
// ...
}
package org.example.tree.util;
// ...
public class TreeResourceImpl
extends XMIResourceImpl
{
// ...
}
package org.example.tree.util;
// ...
public class TreeResourceFactoryImpl
extends ResourceFactoryImpl
{
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 28
29. Generated EClass
package org.example.tree;
// ...
public interface Node
extends EObject
{
// ...
}
package org.example.tree.impl;
// ...
public class NodeImpl
extends EObjectImpl
implements Node
{
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 29
30. Generated EClass Impact
TreePackage
public interface //...
{
int NODE = 0;
EClass getNode();
// ...
interface Literals
{
EClass NODE = eINSTANCE.getNode();
// ...
}
}
public interface TreeFactory //...
{
Node createNode();
// ...
}
public class TreeSwitch<T>
{
public T caseNode(Node object);
// ...
}
public class TreeAdapterFactory //...
{
public Adapter createNodeAdapter();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 30
31. Generated EStructuralFeature
public interface Node // ...
{
String getLabel();
void setLabel(String value);
// ...
}
public class NodeImpl // ...
{
protected static final String LABEL_EDEFAULT = null;
protected String label = LABEL_EDEFAULT;
public String getLabel()
{
return label;
}
public void setLabel(String newLabel)
{
String oldLabel = label;
label = newLabel;
// ...
}
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 31
32. Generated EStructuralFeature Impact
public interface TreePackage //...
{
int NODE__LABEL = 0;
EAttribute getNode_Label();
// ...
interface Literals
{
EAttribute NODE__LABEL = eINSTANCE.getNode_Label();
// ...
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 32
33. Generated EOperation
public interface Node // ...
{
boolean hasChildren();
// ...
}
public class NodeImpl // ...
{
public boolean hasChildren()
{
// TODO: implement this method
// Ensure that you remove @generated or mark it @generated NOT
throw new UnsupportedOperationException();
}
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 33
34. Generated EDataType Impact
public interface TreePackage //...
{
int LABEL= 2;
EDataType getLabel();
// ...
interface Literals
{
EDataType LABEL = eINSTANCE.getLabel();
// ...
}
}
public class TreeFactoryImpl //...
{
public String createLabelFromString
(EDataType eDataType, String initialValue)
{
return
(String)super.createFromString(eDataType, initialValue);
}
public String convertLabelToString
(EDataType eDataType, Object instanceValue)
{
return
super.convertToString(eDataType, instanceValue);
}
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 34
35. Generated EEnum
package org.example.tree;
// ...
public enum NodeKind implements Enumerator
{
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 35
36. Generated EEnum Impact
TreePackage
public interface //...
{
int NODE_KIND = 1;
EEnum getNodeKind();
// ...
interface Literals
{
EEnum NODE_KIND = eINSTANCE.getNodeKind();
// ...
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 36
37. Generated EEnumLiteral
public enum NodeKind // ...
{
SINGLETON(0, quot;Singletonquot;, quot;Singletonquot;),
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 37
38. Generated Project-level Artifacts
• In addition to the generated Java code, generated
projects also include the following artifacts
– A MANIFEST.MF
• Information used by Equinox/OSGI and the Plugin
Development Environment PDE to manage
dependencies and classpaths
– A plugin.xml
• Information used by Equinox to manage extension
points
– A plugin.properties
• Properties that need to be translated
– A build.properties
• Information used to produce a deployed binary result
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 38
39. Generated Manifest
• The generated MANIFEST.MF is not regenerated
once the corresponding plugin.xml exists so you
can tailor it as needed
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.example.tree;singleton:=true
Bundle-Version: 1.0.0
Bundle-ClassPath: .
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Export-Package: org.example.tree,
org.example.tree.impl,
org.example.tree.util
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.emf.ecore;visibility:=reexport,
org.eclipse.emf.ecore.xmi;visibility:=reexport
Bundle-ActivationPolicy: lazy
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 39
40. Generated Plug-in XML
• The generated plugin.xml is not regenerated so you can
tailor it as needed
– But keep in mind that it contains extension points with data that
might change when your model name changes
<plugin>
<extension point=quot;org.eclipse.emf.ecore.generated_packagequot;>
<package
uri=quot;http://www.example.org/treequot;
class=quot;org.example.tree.TreePackagequot;
genModel=quot;model/Tree.genmodelquot;/>
</extension>
<extension point=quot;org.eclipse.emf.ecore.extension_parserquot;>
<parser
type=quot;treequot;
class=quot;org.example.tree.util.TreeResourceFactoryImplquot;/>
</extension>
</plugin>
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 40
41. Generated Build and Plug-in Properties
• The generated plugin.properties supports merging
– Any property not already defined is added
– Any property already defined retains it’s value
pluginName = Tree Model
providerName = www.example.org
• The generated build.properties will not be modified
once it exists it can be tailored as desired
bin.includes = .,
model/,
META-INF/,
plugin.xml,
plugin.properties
jars.compile.order = .
source.. = src/
output.. = bin/
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 41
42. Modifying Generated Code
• EMF’s generator supports merging generated changes with
hand written changes
– All generated code is marked with @generated
• Anything so marked will be updated or even deleted during
subsequent regeneration
• Everything else is safe
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public NodeKind getKind()
{
return
getParent() == null ?
getChildren().isEmpty() ? NodeKind.SINGLETON : NodeKind.ROOT :
getChildren().isEmpty() ? NodeKind.LEAF : NodeKind.INTERMEDIATE;
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 42
43. Modifying Generated Javadoc
• Javadoc containing “user-doc” sections support merging
– The text inside that section will be preserved
– The text outside that section will be updated
– The feature accessor has a comment that should be changed
/**
* Returns the value of the '<em><b>Label</b></em>' attribute.
* <!-- begin-user-doc -->
* <p>
* If the meaning of the '<em>Label</em>' attribute isn't clear,
* there really should be more of a description here...
* </p>
* <!-- end-user-doc -->
* @return the value of the '<em>Label</em>' attribute.
* @see #setLabel(String)
* @see org.example.tree.TreePackage#getNode_Label()
* @model dataType=quot;org.example.tree.Label‚
* @generated
*/
String getLabel();
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 43
44. Augmenting Generated Methods
• A generated method can be renamed by adding a “Gen”
suffix and then the original signature can be used to provide
additional behavior
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setLabelGen(String newLabel)
{
String oldLabel = label;
label = newLabel;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, TreePackage.NODE__LABEL, oldLabel, label));
}
public void setLabel(String newLabel)
{
setLabelGen(newLabel == null ? null : newLabel.intern());
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 44
45. Creating a Tree Instance Model
Node
TreeFactory tree =
TreeFactory.eINSTANCE; label Root
Node root = tree.createNode(); children A,
AB
root.setLabel(quot;Rootquot;);
parent
Node a = tree.createNode();
a.setLabel(quot;Aquot;);
Node Node
root.getChildren().add(a);
label A label B
Node x = tree.createNode();
children X children Y
x.setLabel(quot;Xquot;);
parent Root parent Root
a.getChildren().add(x);
Node b = tree.createNode();
b.setLabel(quot;Bquot;);
Node Node
root.getChildren().add(b);
label X label Y
Node y = tree.createNode();
children children
y.setLabel(quot;Yquot;);
parent A parent B
b.getChildren().add(y);
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 45
46. Notifiers, Adapters, and Notification
public interface Notifier public interface Adapter
{ {
EList<Adapter> eAdapters(); void notifyChanged(Notification notification);
void eNotify(Notification notification); // ...
boolean eDeliver(); }
void eSetDeliver(boolean deliver);
}
int SET = 1;
public interface Notification
int UNSET = 2;
{
int ADD = 3;
Object getNotifier();
int REMOVE = 4;
int getEventType();
int ADD_MANY = 5;
Object getFeature();
int REMOVE_MANY = 6;
Object getOldValue();
int MOVE = 7;
Object getNewValue();
int REMOVING_ADAPTER = 8;
int getPosition();
notifier.eAdapters().add
int RESOLVE = 9;
// ...
(new AdapterImpl()
int EVENT_TYPE_COUNT = 10;
}
{
@Override
public void notifyChanged(Notification notification)
{
// Process notifications produced by the notifier.
}
});
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 46
47. EObject Reflection
• EObject is EMF’s equivalent to java.lang.Object
– Just as java.lang.Object has getClass() to determine the object’s
runtime java.lang.Class, EObject has eClass() to determine the
object’s runtime EClass
– An EObject knows the EObject that contains it as well as the specific
containment EReference by which it is referenced
– An EObject knows all its contained children
• An EObject is a notifier
– Changes to its features fire notifications
public interface EObject extends Notifier
{
EClass eClass();
EObject eContainer();
EReference eContainmentFeature();
EList<EObject> eContents();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 47
48. EObject Notification
• Generated set (and unset) method as well as
EMF’s specialized list implementations all produce
notifications
– The logic is optimized to produce them if and only if there
are listeners
public void setLabel(String newLabel)
{
String oldLabel = label;
label = newLabel;
if (eNotificationRequired())
eNotify
(new ENotificationImpl
(this, Notification.SET, TreePackage.NODE__LABEL, oldLabel, label));
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 48
49. References and Referential Integrity
• Ecore models associations as a pair of references related as opposites
– Such references are referred to as bidirectional
– EMF enforces the referential integrity of such references via the handshaking
protocol provided by InternalEObject’s eInverseAdd and eInverseRemove
• A containment reference induces a tree structure
– It is implicitly bidirectional even if there is no explicitly defined opposite
– EObject’s eContainer() is the implicit opposite of a containment reference
• A container reference is the explicit opposite of a containment reference
– It is effectively derived from EObject.eContainer()
• Any other type of reference is referred to as a cross reference
– It specifies cross links between the objects in the tree structure induced by
containment and container references
• When an object is added to a containment reference it is removed from
its current containment reference
– Referential integrity is enforced, i.e., there can only be one eContainer()
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 49
50. Updating a Tree Instance Model
Node
b.getChildren().set(0, x);
label Root
children A,
AB
Notifier Feature Type Old New
parent
SET
b children y x
SET
y parent b
Node Node
SET
x parent a b
label A label B
REMOVE
a children x
children X children X
Y
parent Root parent Root
Node Node
label X label Y
children children
parent B
A parent B
Friday, March 20, 2009
© Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 50
51. Exercise 1
Code Generation
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 51
52. RESTful Persistence
• The principles of representation state transfer
underlie EMF’s persistence architecture
– Models are stored in one or more resources
– Each resource is addressed via a Uniform Resource
Identifier, i.e., a URI
– A resource supports save, load, unload, and delete
– Specialized resources support arbitrary content types
– Transfer of state is uniformly handled by a stateless URI
converter that supports
• Any scheme accessible as a URL
• Any scheme registered with Eclipse File System (EFS)
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 52
53. Uniform Resource Identifiers
• A URI is effectively a string with a well-defined
structure
– Supported by org.eclipse.emf.common.util.URI
• It predates java.net.URI
• They are immutable
• They are created by static factory methods
public final class URI
{
public static URI createURI(String uri);
public static URI createFileURI(String pathName);
public static URI createPlatformResourceURI(String pathName, boolean encode);
public static URI createPlatformPluginURI(String pathName, boolean encode);
// …
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 53
54. Hierarchical URIs
• A URI typically consists of /-separated components
– [scheme:][//authority][/path][?query][#fragment]
– E.g.,
• http://www.eclipse.org/modeling/emf/?project=emf#related
• file://c:/workspace/project/file.extension#id
• platform:/resource/project/file.extension#id
public final class URI
{
public boolean isHierarchical();
public String scheme();
public String authority();
public String[] segments();
public String path();
public String query();
public String fragment();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 54
55. Absolute and Relative URIs
• An absolute URI starts with a scheme
– Always uses absolute URIs to identify resources!
– Relative URIs are useful within resources for referring to
other resources within the same authority
• This supports moving groups of related resources
– Examples of relative URIs
• #id
• ../directory/file.extension
• file.extension
public final class URI
{
public boolean isRelative();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 55
56. Resolving and De-resolving URIs
• De-resolving an absolute URI against a base
absolute URI yields the URI relative to that base
– e.g., de-resolving platform:/resource/a/foo.html against
platform:/resource/b/bar.html yields ../a/foo.html
• Resolving a relative URI against a base absolute URI
yields the absolute URI relative to that base
– e.g., resolving ../a/foo.html against
platform:/resource/b/bar.html yields platform:/resource/a/foo.html
public final class URI
{
public URI resolve(URI base);
public URI deresolve(URI base);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 56
57. URIs to Access the File System
• A file system path is OS-specific!
– It is not a URI and is not a separator in a URI
– Use createFileURI to convert a file system path to a URI
• The path c:afoo.html becomes file:/c:/a/foo.html
– Use toFileString to convert back to a file system path
– Ensure your file system path is also absolute
• URI.createFileURI(new java.io.File(<path>).getAbsolutePath());
public final class URI
{
public static URI createFileURI(String pathName)
public boolean isFile();
public String toFileString();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 57
58. URIs to Access the Eclipse Workspace
• Use platform resource URIs to access the workspace
– platform:/resource/project[/relative-path]
– Be sure to encode the path
• URI.createPlatformResourceURI(iFile.getPath().toString(), true)
– Use workspaceRoot.getFile(new Path(uri.toPlatformResourceString(true)))
to convert back to an IFile
public final class URI
{
public static URI createPlatformResourceURI(String pathName, boolean encode);
public boolean isPlatformResource();
public String toPlatformString(boolean decode);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 58
59. URIs to Access the Eclipse Installation
• Use platform plug-in URIs to access the installation
– platform:/plugin/plugin-id[/relative-path]
– Be sure to encode the path
• URI.createPlatformPluginURI(<plugin-path>, true);
public final class URI
{
public static URI createPlatformPluginURI(String pathName, boolean encode);
public boolean isPlatformPlugin();
public String toPlatformString(boolean decode);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 59
60. URIs to Access an Archive
• Use archive URIs to access zipped or jarred content
– archive:absolute-uri{!/relative-path}+
– E.g., archive:file:/c:/my.zip!/a/foo.zip!/b/bar.html
public final class URI
{
public boolean isArchive();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 60
61. URI Converter
• All access to the state associated with a URI is
directed to a URI converter
– It supports URI normalization
• Relative URIs are made absolute
• URI mappings are applied
– There is a global URI converter instance
• Implementations should extend ExtensibleURIConverterImpl
public interface URIConverter
{
URI normalize(URI uri);
URIConverter INSTANCE = new ExtensibleURIConverterImpl();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 61
62. URI Converter Remapping
• A URI map provides support for redirection
– Instance mappings, e.g.,
• http://www.example.org/foo.html ->
platform:/plugin/org.example/foo.html
– Folder mappings (URIs ending with /), e.g.,
• http://www.example.org/ ->
platform:/plugin/org.example/
– There’s a global instance that can be populated by the
org.eclipse.emf.ecore.uri_mapping extension point
public interface URIConverter
{
Map<URI, URI> getURIMap();
Map<URI, URI> URI_MAP = /**/;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 62
63. URI Converter Input and Output
• The URI converter acts as a factory for creating input
and output streams
– Arbitrary client-defined options can be passed along
– An OPTION_RESPONSE can be used to pass in a map to be populated
with additional information
• The RESPONSE_TIME_STAMP_PROPERTY will be updated with the
time stamp of the resource at the time the stream was created
public interface URIConverter
{
String OPTION_RESPONSE = quot;RESPONSEquot;;
String RESPONSE_TIME_STAMP_PROPERTY = quot;TIME_STAMPquot;;
InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException;
OutputStream createOutputStream(URI uri, Map<?, ?> options) throws IOException;
//...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 63
64. URI Converter Deletion and Existence
• The URI converter can test whether there is any
state associated with a URI
– This is generally more efficient than fetching an input
stream, which could fail due to insufficient permission
• The state associated with a URI can be deleted
– This was added in 2.4 to support the full create, read,
update, delete (CRUD) life cycle
public interface URIConverter
{
boolean exists(URI uri, Map<?, ?> options);
void delete(URI uri, Map<?, ?> options) throws IOException;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 64
65. URI Converter
• Attributes associated with the state of a URI can be
fetched and stored
– An OPTION_REQUESTED_ATTRIBUTES map specifies the
attributes to be fetched
public interface URIConverter
{
String ATTRIBUTE_TIME_STAMP = quot;timeStampquot;;
long NULL_TIME_STAMP = -1;
String ATTRIBUTE_LENGTH = quot;lengthquot;;
String ATTRIBUTE_READ_ONLY = quot;readOnlyquot;;
String ATTRIBUTE_EXECUTABLE = quot;executablequot;;
String ATTRIBUTE_ARCHIVE = quot;archivequot;;
String ATTRIBUTE_HIDDEN = quot;hiddenquot;;
String ATTRIBUTE_DIRECTORY = quot;directoryquot;;
String OPTION_REQUESTED_ATTRIBUTES = quot;requestedAttributesquot;;
Map<String, ?> getAttributes(URI uri, Map<?, ?> options);
void setAttributes(URI uri, Map<String, ?> attributes, Map<?, ?> options) throws IOException;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 65
66. URI Converter Content Description
• A URI converter can be asked to provide a content
description of the state associated with a URI
– The result is a map of properties describing the content
• The content description is typically determined by
analyzing the input stream the URI
– This analysis is done by content handlers
– There is a configurable list of these handlers
public interface URIConverter
{
Map<String, ?> contentDescription(URI uri, Map<?, ?> options) throws IOException;
EList<ContentHandler> getContentHandlers();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 66
67. URI Converter Delegation To URI Handlers
• All the work of the URI converter is delegated to a
URI handler
– URIs are normalized before the handler is determined
– The getURIHandler method determines the
appropriate handler for the given URI
– There is a configurable list of URI handlers
• Initially populated with URIHandler.DEFAULTS
public interface URIConverter
{
EList<URIHandler> getURIHandlers();
URIHandler getURIHandler(URI uri);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 67
68. URI Handler
• The full complement of URI converter methods are
supported for delegation
• The canHandle method indicates whether the handler is
applicable for the given URI
• Facilitates composition of specialized URI converter behavior
public interface URIHandler
{
boolean canHandle(URI uri);
InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException;
OutputStream createOutputStream(URI uri, Map<?, ?> options) throws IOException;
void delete(URI uri, Map<?, ?> options) throws IOException;
Map<String, ?> contentDescription(URI uri, Map<?, ?> options) throws IOException;
boolean exists(URI uri, Map<?, ?> options);
Map<String, ?> getAttributes(URI uri, Map<?, ?> options);
void setAttributes(URI uri, Map<String, ?> attributes, Map<?, ?> options) throws IOException;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 68
69. URI Handler
• Default URI handlers support the Eclipse workspace,
the file system, the Eclipse File System, nested
archives, and arbitrary URLs
public interface URIHandler
{
List<URIHandler> DEFAULT_HANDLERS =
Collections.unmodifiableList
(Arrays.asList
(new URIHandler []
{
new PlatformResourceURIHandlerImpl(),
new FileURIHandlerImpl(),
new EFSURIHandlerImpl(),
new ArchiveURIHandlerImpl(),
new URIHandlerImpl()
}));
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 69
70. Content Handler
• The URI converter creates an input stream along with an
empty context and delegates to each content handler for
which canHandle returns true
– The context cashes state to reduce duplicate computation costs
• Other than validity and content type, only the requested
properties in the map supplied in the options are computed
public interface ContentHandler
{
boolean canHandle(URI uri);
String OPTION_REQUESTED_PROPERTIES = quot;REQUESTED_PROPERTIESquot;;
Map<String, ?> contentDescription
(URI uri,
InputStream inputStream,
Map<?, ?> options,
Map<Object, Object> context) throws IOException;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 70
71. Content Handler Validity Determination
• Content validity is a three state result
– The URI converter returns the description of the first handler that
yields a valid description
– Failing that, it returns the first indeterminate description
– Only when invalid is the content type not included in the description
public interface ContentHandler
{
String VALIDITY_PROPERTY = quot;org.eclipse.emf.ecore:validityquot;;
enum Validity
{
INVALID,
INDETERMINATE,
VALID
}
String CONTENT_TYPE_PROPERTY = quot;org.eclipse.emf.ecore:contentTypequot;;
String UNSPECIFIED_CONTENT_TYPE = quot;quot;;
Map<String, Object> INVALID_CONTENT_DESCRIPTION = /**/;
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 71
72. Content Handler Encodings
• Two standard description properties are supported
– The character set used to encode the content
– The byte order marker at the start of the stream
public interface ContentHandler
{
String CHARSET_PROPERTY = quot;org.eclipse.core.runtime:charsetquot;;
String BYTE_ORDER_MARK_PROPERTY = quot;org.eclipse.core.runtime:bomquot;;
enum ByteOrderMark
{
UTF_8,
UTF_16BE,
UTF_16LE;
public byte [] bytes();
public static ByteOrderMark read(InputStream inputStream) throws IOException;
}
// ..
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 72
73. Content Handler Registration
• There is a registry of content handlers populated by the
org.eclipse.emf.ecore.content_handler extension point
– Handlers are sorted and applied based on priority
– A flattened list view based on priority is provided
– A single default handler that delegates to the platform is registered by EMF
so that org.eclipse.core.contenttype.contentTypes registrations are exploited
public interface ContentHandler
{
interface Registry extends SortedMap<Integer, List<ContentHandler>>
{
int VERY_HIGH_PRIORITY = -10000;
int HIGH_PRIORITY = -1000;
int NORMAL_PRIORITY = 0;
int LOW_PRIORITY = 1000;
int VERY_LOW_PRIORITY = 10000;
void put(int priority, ContentHandler contentHandler);
List<ContentHandler> contentHandlers();
Registry INSTANCE = new ContentHandlerRegistryImpl();
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 73
74. Resource Set
• A resource set acts as a container for resources
– The relationship from resource set to resource is
effectively bidirectional containment
• A resource set is a notifier
– Changes to the resources list fire notifications for the
RESOURCE_SET__RESOURCES feature
public interface ResourceSet extends Notifier
{
int RESOURCE_SET__RESOURCES = 0;
EList<Resource> getResources();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 74
75. Resource
• A resource acts as a container for EObjects
– The relationship from resource to EObject is effectively bidirectional
containment
• A resource knows its containing resource set
• A resource is a notifier
– Changes to its features fire notifications
public interface EObject
public interface Resource extends Notifier //...
{
{
Resource eResource();
int RESOURCE__RESOURCE_SET = 0;
// ...
ResourceSet getResourceSet(); }
int RESOURCE__URI = 1;
URI getURI();
void setURI(URI uri);
int RESOURCE__CONTENTS = 2;
EList<EObject> getContents();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 75
76. Tree Iterators over the Containment Tree
• Resource set’s resources, a resource’s contents, and an
EObject’s eContents() collectively induce a tree structure
that can be walked by a tree iterator, which is simply an
iterator that supports branch pruning
public interface ResourceSet // ...
{
TreeIterator<Notifier> getAllContents();
// ...
}
public interface Resource
public interface TreeIterator<E> // ...
{
extends Iterator<E>
TreeIterator<EObject> getAllContents();
{
// ...
void prune(); }
}
public interface EObject //...
{
TreeIterator<EObject> eAllContents();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 76
77. Resource Set
• A resource set provides a complete context
– A URI converter for accessing the state of the resources
– A resource factory registry for determining the
appropriate factory when creating new resources
– A package registry for determining the appropriate
package to associate with a namespace URI
public interface ResourceSet extends Notifier
{
URIConverter getURIConverter();
Resource.Factory.Registry getResourceFactoryRegistry();
EPackage.Registry getPackageRegistry();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 77
78. Resource Factory
• A resource factory creates a resource given a URI
– It is responsible for creating and configuring new
resources
• Resource factories are maintained in resource
factory registries
public interface Resource // ...
{
interface Factory
{
Resource createResource(URI uri);
// ...
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 78
79. Resource Factory Registry
• A resource factory registry determines the appropriate
factory given a URI and a content type
– For null content type, no lookup based on content type is performed
– For URIHandler.UNSPECIFIED_CONTENT_TYPE, the content type is
computed lazily when first required
– A resource set’s local resource factory registry delegates to the global
instance when local lookup yields no match
public interface Resource // ...
{
interface Factory
{
interface Registry
{
Factory getFactory(URI uri, String contentType);
Registry INSTANCE = new ResourceFactoryRegistryImpl();
// ...
}
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 79
80. Protocol Resource Factory Registration
• Registration based on URI scheme is supported
– The org.eclipse.emf.ecore.protocol_parser extension point
is used to register such a factory with the global factory
registry instance
– This mechanism is rarely used and is not very RESTful
public interface Resource // ... public final class URI
{ {
interface Factory public String scheme();
{ // ...
interface Registry }
{
Map<String, Object> getProtocolToFactoryMap();
// ...
}
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 80
81. File Extension Resource Factory Registration
• Registration based on URI file extension is
supported
– The org.eclipse.emf.ecore.extension_parser extension point is used
to register such a factory with the global factory registry instance
– A registration against the default extension matches any extension
– This mechanism is commonly used, efficient, but not very RESTful
public interface Resource // ... public final class URI
{ {
interface Factory public String fileExtension();
{ // ...
interface Registry }
{
String DEFAULT_EXTENSION = quot;*quot;;
Map<String, Object> getExtensionToFactoryMap();
// ...
}
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 81
82. Content Type Resource Factory Registration
• Registration based on content type is supported
– The org.eclipse.emf.ecore.content_parser extension point is used to
register such a factory with the global factory registry instance
– A registration against the default content type matches any content
type
– This is new to 2.4 and is more RESTful
public interface Resource // ...
{
interface Factory
{
interface Registry
{
String DEFAULT_CONTENT_TYPE_IDENTIFIER = quot;*quot;;
Map<String, Object> getContentTypeToFactoryMap();
}
} // ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 82
83. Package Registry
• A package registry determines the appropriate EPackage or EFactory
given a namespace URI
– The org.eclipse.emf.ecore.generated_package/dynamic_package extension points are
used to register generated/dynamic packages with the global registry
– The org.eclipse.emf.ecore.factory_override extension point is used to register a
factory that overrides the generated default
– A resource set’s local package registry delegates to the global instance when local
lookup yields no match
• The org.eclipse.emf.ecore.package_registry_implementation can be used once to
override the default implementation of the global instance
public interface EPackage // ...
{
interface Registry
{
EPackage getEPackage(String nsURI);
EFactory getEFactory(String nsURI);
Registry INSTANCE = EPackageRegistryImpl.createGlobalRegistry();
// ...
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 83
84. Creating a New Resource
• A resource set acts as a factory for creating
resources
– Specifying no content type is equivalent to specifying null
– The resource set’s resource factory registry is consulted to
determine the appropriate factory
– That factory is used to create the resource
– That resource is added to the list of resources
public interface ResourceSet // ...
{
Resource createResource(URI uri);
Resource createResource(URI uri, String contentType);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 84
85. Populating a New Resource
• A newly created resource is initially considered not
loaded
– Adding an object to the contents list will change the state
to indicate that it is considered loaded
public interface Resource // ...
{
int RESOURCE__IS_LOADED = 4;
boolean isLoaded();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 85
86. Saving a Resource
• Resource has two save methods
– The save method without an output stream argument
uses the URI converter of the containing resource set to
create an output stream from the resource’s URI and then
calls the second save method, after which it closes the
stream
– The second save method writes a representation of the
contained objects into the output stream
public interface Resource // ...
{
void save(Map<?, ?> options) throws IOException;
void save(OutputStream outputStream, Map<?, ?> options) throws IOException;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 86
87. Saving a Tree Model Instance
ResourceSet resourceSet = ResourceSet
new ResourceSetImpl(); resources
Resource resource =
resourceSet.createResource
Resource
(URI.createFileURI
resourceSet
<?xml version=quot;1.0quot; encoding=quot;ASCIIquot;?>
(quot;c:/Root.treequot;));
uri file:/c:/Root.tree
<tree:Node xmi:version=quot;2.0quot;
TreeFactory tree = contents
TreeFactory.eINSTANCE; xmlns:xmi=quot;http://www.omg.org/XMIquot;
xmlns:tree=quot;http://www.example.org/treequot;
Node root = tree.createNode(); Node
label=quot;Rootquot;>
eContainer
root.setLabel(quot;Rootquot;); <children label=quot;Aquot;/>
eResource
</tree:Node>
resource.getContents().add(root); label Root
children A
Node a = tree.createNode();
parent
a.setLabel(quot;Aquot;);
root.getChildren().add(a); Node
eContainer
resource.save(null);
eResource
label A
children
parent Root
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 87
88. Explicitly Loading a Resource
• Resource has two load methods
– The load method without an input stream argument uses
the URI converter of the containing resource set to create
an input stream from the resource’s URI and then calls the
second load method, after which it closes the stream
– The second load method reads the representation and
adds the resulting objects to the contents
– Resources are usually not loaded explicitly
public interface Resource // ...
{
void load(Map<?, ?> options) throws IOException;
void load(InputStream inputStream, Map<?, ?> options) throws IOException;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 88
89. Demand Loading a Resource
• Resources are typically demand loaded into a
resource set rather than being explicitly loaded
– The existing list of resources is first considered for a match
– If there isn’t one, a new resource is created as before
– If the matched resource isn’t already loaded or a new resource is
created, that resource is loaded
• The default load options are passed to the load method
public interface ResourceSet // ...
{
Map<Object, Object> getLoadOptions();
Resource getResource(URI uri, boolean loadOnDemand);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 89
90. Loading a Tree Model Instance
ResourceSet resourceSet = ResourceSet
new ResourceSetImpl(); resources
Resource resource =
resourceSet.getResource
Resource
(URI.createFileURI(quot;c:/Root.treequot;),
resourceSet
<?xml version=quot;1.0quot; encoding=quot;ASCIIquot;?>
true);
uri file:/c:/Root.tree
<tree:Node xmi:version=quot;2.0quot;
Node root = contents
xmlns:xmi=quot;http://www.omg.org/XMIquot;
(Node)resource.getContents().get(0);
xmlns:tree=quot;http://www.example.org/treequot;
root.setLabel(root.getLabel() + quot;'quot;); Node
label=quot;Root'quot;>
eContainer
Node a = root.getChildren().get(0);
<children label=quot;A'quot;/>
eResource
</tree:Node>
a.setLabel(a.getLabel() + quot;'quot;); label Root’
Root
children A’
A
resource.save(System.out, null);
parent
Node
eContainer
eResource
label A’
A
children
parent Root’
Root
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 90
91. Resource Time Stamps
• Both loading and saving update a resource’s time stamp
– When loading, it’s the time stamp of the resource when the input
stream is opened
– When saving, it’s the time stamp of the resource after the output
stream is closed
– When populating a new resource, it’s the time stamp of the clock
when the first object is added
• This can be used to implement optimistic concurrency or to
detect external changes
public interface Resource // ...
{
int RESOURCE__TIME_STAMP = 8;
long getTimeStamp();
void setTimeStamp(long timeStamp);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 91
92. Resource Modification Tracking
• A resource can track modification of its contents
– It’s implemented using adapters on the tree of content
– It’s quite expensive and hence is optional and not enabled by default
– Typically the state of the command stack is used to track changes
• This provides better support for undo reversing a modification
public interface Resource // ...
{
int RESOURCE__IS_TRACKING_MODIFICATION = 5;
boolean isTrackingModification();
void setTrackingModification(boolean isTrackingModification);
int RESOURCE__IS_MODIFIED = 3;
boolean isModified();
void setModified(boolean isModified);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 92
93. Resource Diagnostics
• Problems encountered when loading a resource are
recorded as diagnostics describing the problem
public interface Resource // ...
{
int RESOURCE__ERRORS = 6;
EList<Diagnostic> getErrors();
int RESOURCE__WARNINGS = 7;
EList<Diagnostic> getWarnings();
interface Diagnostic
{
String getMessage();
String getLocation();
int getLine();
int getColumn();
}
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 93
94. Resource Unloading
• A resource can be unloaded to discard any changes
– It returns to the state it was in when first created
– All the contained objects are converted to proxies so that
references to them will try to resolve again
– The resource can subsequently be loaded again
public interface Resource // ...
{
void unload();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 94
95. Resource Deletion
• A resource can be deleted
– The resource set’s URI converter is used to delete the
state associated with the resource’s URI
– Then the resource is unloaded, hence converting all its
contents to proxies
– Finally the resource is removed from the resource set
public interface Resource // ...
{
void delete(Map<?, ?> options) throws IOException;
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 95
96. Containment References Revisited
• In order to persist an object, it must be contained by
a resource, i.e.,
– It must either be directly a member of a resource’s
contents list
– Or it must be possible to reach such a direct member
object by walking up the eContainer() chain
– Typically eResource() and eContainer() are mutually
exclusive
• That means adding an object to a resource’s contents
removes it from its current container
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 96
97. Moving a Tree Model Instance
ResourceSet
Resource child =
resources
resourceSet.createResource
(URI.createFileURI
(quot;c:/Child.treequot;));
Resource Resource
child.getContents().add(a); resourceSet resourceSet
uri file:/c:/Root.tree uri file:/c:/Child.tree
contents contents
Node
eContainer
eResource
label Root
children A
parent
Node
eContainer
eResource
label A
children
parent Root
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 97
98. Cross References Revisited
• A reference that is neither a containment nor the
opposite of a containment, i.e., a container, is a
cross reference
– Cross references can span not only objects within a containment tree
but also objects across different resources
– Cross references require specialized serialization support
– An EObject knows all its cross references
public interface EObject // ...
{
EList<EObject> eCrossReferences();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 98
99. URI Access EObjects
• A full URI that includes a fragment denotes an EObject
– The URI that is left when the fragment is trimmed denotes a resource
– The fragment itself locates the object within that resource
– The resource is responsible for producing a fragment that it can
subsequently use to locate the object
• Given a Resource r and an EObject x the following is always true
r.getEObject(r.getURIFragment(x)) == x
public final class URI
public interface Resource // ...
{
{
public String fragment();
EObject getEObject(String uriFragment); public URI trimFragment();
String getURIFragment(EObject eObject); public URI appendFragment(String fragment);
// ...
// ...
}
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 99
100. Locating or Demand Loading an EObject
• An EObject can be located or demand loaded in a
resource set
– The URI fragment is trimmed and used to locate or
demand load the resource it denotes
– If one is found, the fragment is used to locate the object
within that resource
public interface ResourceSet // ...
{
EObject getEObject(URI uri, boolean loadOnDemand);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 100
101. URI Fragments
• URI fragment can take one of several different forms
– Fragment paths
• The fragment is a path that consists of /-separated
segments that are used to navigate to the object
starting from the root of the resource
– Keys
• A combination of attributes that uniquely identify the
object within a given reference
– Intrinsic IDs
• A unique string stored as data on the object itself
– Extrinsic IDs
• Unique strings associated with the objects but
maintained by the resource
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 101
102. URI Fragment Paths
• The fragment starts with a root segment determined by the
resource
– By default a numeric indexing scheme is used, i.e., the zero-based
index of the root object in the resource’s contents
• /0 denotes the first root object and the 0 is optional
– The remaining segments are computed by the objects themselves
using the InternalEObject API
• The modeled objects may specialize their segment syntax
• The default implementation uses @feature-name[.index]
public interface InternalEObject // ...
{
String eURIFragmentSegment(EStructuralFeature eFeature, EObject eObject);
EObject eObjectForURIFragmentSegment(String uriFragmentSegment);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 102
103. URI Fragment Paths with Keys
• The index-based default segment syntax within a multi-
valued reference is fragile with respect to list reordering
• Keys can be used to make this more robust
– An EReference can designate one or more of the EAttributes of
its referenced EClass as uniquely identifying each object in that
reference
– This yields a syntax in the following form, where the square brackets
are part of the actual segment rather than denoting optionality
@feature-name[key='value1',key2='value2']
public interface EReference // ...
{
EList<EAttribute> getEKeys();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 103
104. URI Fragment Intrinsic IDs
• Any path-based mechanism will be fragile with
respect to restructuring of the tree
• IDs can be used to make this more robust
– An EAttribute can be designed as the ID of its containing EClass
– The string value of this attribute will be used directly as the fragment
– This string value must be unique with respect to all other objects (of
all types) within the same resource
– This uniqueness requirement makes them a bit difficult and expensive
to maintain
public interface EAttribute// ...
{
boolean isID();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 104
105. URI Fragment Extrinsic IDs
• Because not all models are able to maintain IDs as data
within the instances themselves, a resource implementation
can manage a two way object-to-ID mapping within the
resource
– XMLResource supports that approach
• A specific attribute can be set as corresponding to the ID in the
serialization, e.g., xmi:id
• By specializing useUUIDs to return true, universally unique IDs
are generated automatically as needed
• UUIDs and ID maps take up a lot of space! ~175 bytes per object
public class EcoreUtil
{
public static String generateUUID();
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 105
106. Saving Cross Document References
ResourceSet
ResourceSet resourceSet =
resources
new ResourceSetImpl();
Resource resource =
Resource Resource
resourceSet.getResource
resourceSet resourceSet
(URI.createFileURI(quot;c:/Root.treequot;),
<?xml version=quot;1.0quot; encoding=quot;ASCIIquot;?>
uri file:/c:/Root.tree uri file:/c:/Map.tree
true); <tree:Node xmi:version=quot;2.0quot;
contents contents
Resource map = xmlns:xmi=quot;http://www.omg.org/XMIquot;
resourceSet.createResource
xmlns:tree=quot;http://www.example.org/treequot;
Node Node
(URI.createFileURI(quot;c:/Map.treequot;));
label=quot;Rootquot;> eContainer eContainer
EcoreUtil.Copier copier =
<children label=quot;Aquot;>
new EcoreUtil.Copier(); eResource eResource
<data href=quot;Root.tree#//@children.0quot;/> label
label Root Root
map.getContents().addAll
</children> children A children A
(copier.copyAll
(resource.getContents())); href=quot;Root.tree#/quot;/>
<data parent parent
data data
for (Iterator<EObject> </tree:Node>
i=
resource.getAllContents();
Node Node
i.hasNext(); )
{ eContainer eContainer
EObject eObject = i.next(); eResource eResource
((Node)copier.get(eObject)). label A label A
setData(eObject); children children
}
parent Root parent Root
resource.save(null); data data
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 106
107. Proxies
• EMF supports the concept of a proxy
– A proxy is just a regular instance that acts as a proxy
– Internally it stores the proxy URI, i.e., the URI of the
EObject to which the proxy should resolve
– The proxy URI can be set by the de-serializer and is set for
each object when a resource is unloaded
public interface EObject public interface InternalEObject
// ...
{ extends EObject
boolean eIsProxy(); {
// ... URI eProxyURI();
}
void eSetProxyURI(URI uri);
// ...
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 107
108. Proxy Resolution
• Generated get methods as well as EMF’s specialized
list implementations all resolve proxies on demand
– Resolution produces notifications
– Resolution demand loads the proxy URI into the resource set
public EObject getData()
{
if (data != null && data.eIsProxy())
{
InternalEObject oldData = (InternalEObject)data;
data = eResolveProxy(oldData);
if (data != oldData)
{
if (eNotificationRequired())
eNotify
(new ENotificationImpl
(this, Notification.RESOLVE, TreePackage.NODE__DATA, oldData, data));
}
}
return data;
}
Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 108