Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building RESTful Java Applications with EMF

7,799 views

Published on

Representational State Transfer (REST) is a style of software architecture for distributed hypermedia systems such as the World Wide Web. However, it is possible to design any enterprise software system in accordance with the 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. 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. Among these principles are the notions that application state and functionality are divided into resources and that every resource is uniquely addressable using a universal syntax for use in hypermedia links. Another key principle of REST is that 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.

The Eclipse Modeling Framework (EMF) provides a Java runtime framework and tools for generative application development and fine-grained data integration based on simple models. Models can be specified directly using EMF's metamodel, Ecore, or imported from other forms, including UML and XML Schema. Given a model specification, EMF can generate a corresponding set of Java interfaces and implementation classes that can easily be mixed with hand-written code for maximum flexibility. When deployed, applications developed with EMF benefit from a powerful and extensible runtime, which, among other features, includes a persistence mechanism which has always supported the principles of REST – perhaps even before the term "REST" became popular. This tutorial will provide an introduction to EMF, including alternatives for specifying a model, EMF's code generation tools, and key runtime framework concepts. As a practical usage of this knowledge, the presenters will show how EMF can be used to build RESTful applications, exploring some best practices for working with resources and other features of the framework.

Published in: Technology

Building RESTful Java Applications with EMF

  1. 1. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  12. 12. Ecore Overview Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 12
  13. 13. Ecore Data Types Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 13
  14. 14. Ecore Annotations and EObject Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 14
  15. 15. Ecore Generics Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 15
  16. 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. 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. 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. 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. 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. 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
  22. 22. EMF Application Architecture Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 22
  23. 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. 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. 25. A Richer Tree Ecore Model Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 25
  26. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 51. Exercise 1 Code Generation Friday, March 20, 2009 © Macro Modeling Ltd., Embarcadero Technologies Inc., IBM Corp. | EPL v1.0 51
  52. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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

×